From 66bdd0a2a31ff1184d7b111fd1cac837e8aff7a7 Mon Sep 17 00:00:00 2001 From: "roomote-roomote[bot]" <301996811+roomote-roomote[bot]@users.noreply.github.com> Date: Sat, 31 Oct 2026 20:28:04 -0400 Subject: [PATCH 1/3] [Chore] Patch body-parser runtime denial of service (#3628) Co-authored-by: Roomote --- package.json | 2 +- pnpm-lock.yaml | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 0f7783add..7f544da0d 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "@hono/node-server": "2.0.10", "@humanfs/node": "0.16.8", "@xmldom/xmldom": "0.8.15", - "body-parser": "2.3.0", + "body-parser": "2.4.0", "browserslist": "4.28.7", "brace-expansion@<1.1.21": "1.1.21", "brace-expansion@>=2.0.0 <2.1.7": "2.1.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1bea814c..57ec59955 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,7 +59,7 @@ overrides: '@hono/node-server': 2.0.10 '@humanfs/node': 0.16.8 '@xmldom/xmldom': 0.8.15 - body-parser: 2.3.0 + body-parser: 2.4.0 browserslist: 4.28.7 brace-expansion@<1.1.21: 1.1.21 brace-expansion@>=2.0.0 <2.1.7: 2.1.7 @@ -7241,8 +7241,8 @@ packages: bn.js@4.12.3: resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} - body-parser@2.3.0: - resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + body-parser@2.4.0: + resolution: {integrity: sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==} engines: {node: '>=18'} bowser@2.14.1: @@ -7570,6 +7570,10 @@ packages: resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} engines: {node: '>=18'} + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} + engines: {node: '>=18'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -8949,6 +8953,10 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -18202,13 +18210,13 @@ snapshots: bn.js@4.12.3: {} - body-parser@2.3.0: + body-parser@2.4.0: dependencies: bytes: 3.1.2 - content-type: 2.0.0 + content-type: 2.1.0 debug: 4.4.3 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 on-finished: 2.4.1 qs: 6.16.1 raw-body: 3.0.2 @@ -18529,6 +18537,8 @@ snapshots: content-type@2.0.0: {} + content-type@2.1.0: {} + convert-source-map@2.0.0: {} cookie-signature@1.2.2: {} @@ -19492,7 +19502,7 @@ snapshots: express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.3.0 + body-parser: 2.4.0 content-disposition: 1.0.1 content-type: 1.0.5 cookie: 0.7.2 @@ -20149,6 +20159,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@5.3.2: {} From 249d87b97c34eb3c7450855b56be1e6940c84fe0 Mon Sep 17 00:00:00 2001 From: "roomote-roomote[bot]" <301996811+roomote-roomote[bot]@users.noreply.github.com> Date: Sat, 31 Oct 2026 20:44:51 -0400 Subject: [PATCH 2/3] chore(deps): patch runtime dependency alert bundle (#3600) Co-authored-by: Roomote Co-authored-by: @mrubens <2600+mrubens@users.noreply.github.com> --- .docker/app/runtime-deps/api/package.json | 3 +- .docker/app/runtime-deps/api/pnpm-lock.yaml | 27 +- apps/api/package.json | 2 +- apps/api/src/handlers/ado/types.ts | 2 +- .../src/handlers/custom-automations/index.ts | 2 +- apps/api/src/handlers/inference/jevgrep.ts | 1 + apps/api/src/handlers/mcp/bitbucket.ts | 9 +- .../handlers/mcp/http-integrations/broker.ts | 2 +- apps/api/src/handlers/mcp/task-outputs.ts | 4 +- .../tasks/automation-work-items/schema.ts | 14 +- .../tasks/fastSessionCommunication.ts | 2 +- .../api/src/handlers/tasks/getTaskMessages.ts | 2 +- apps/api/src/handlers/tasks/saveTaskMemory.ts | 4 +- .../handlers/tasks/submitTaskSuggestions.ts | 2 +- apps/bullmq/package.json | 2 +- apps/bullmq/src/jobs/snapshot.ts | 2 +- apps/preview-proxy/package.json | 2 +- apps/web/package.json | 2 +- .../[reportId]/submit/page.tsx | 2 +- .../(sandbox)/sessions/[sessionId]/page.tsx | 2 +- .../api/mcp-remote-oauth/authorize/route.ts | 2 +- .../app/api/mcp-remote-oauth/revoke/route.ts | 2 +- .../app/api/mcp-remote-oauth/token/route.ts | 4 +- .../sessions/[sessionId]/attention/route.ts | 6 +- .../[sessionId]/attention/stream/route.ts | 4 +- .../integration-tool-approvals/route.ts | 2 +- .../sessions/[sessionId]/presence/route.ts | 4 +- .../api/sessions/[sessionId]/secrets/route.ts | 2 +- .../api/sessions/[sessionId]/stream/route.ts | 2 +- .../system/primitives/form.stories.tsx | 13 +- .../lib/server/fast-session-reply-stream.ts | 4 +- .../automations/ci-failure-triage-routing.ts | 6 +- .../trpc/commands/fast-sessions/input.test.ts | 22 +- .../src/trpc/commands/fast-sessions/input.ts | 32 +- .../trpc/commands/sandbox-session/index.ts | 3 +- apps/web/src/trpc/commands/sessions/index.ts | 4 +- apps/web/src/trpc/routers/_app.ts | 148 +++++----- apps/web/src/trpc/routers/instance-skills.ts | 4 +- .../src/trpc/routers/vulnerability-watch.ts | 2 +- apps/worker/package.json | 2 +- .../automation-work-items-tool-schema.test.ts | 9 +- .../__tests__/report-platform-issue.test.ts | 15 +- .../__tests__/tool-descriptions.test.ts | 7 +- .../automation-work-items-tool.ts | 2 +- .../src/mcp/roomote-mcp-server/index.ts | 2 +- .../on-demand-integrations.ts | 2 +- .../procedures/answerUserInputRequest.ts | 1 + package.json | 7 +- packages/ado/package.json | 2 +- packages/ado/src/api.ts | 4 +- packages/auth/package.json | 2 +- packages/auth/src/auth-token.ts | 2 +- packages/auth/src/preview-token.ts | 2 +- packages/auth/src/run-token.ts | 2 +- packages/auth/src/session-broker-token.ts | 2 +- packages/bitbucket/package.json | 2 +- packages/cloud-agents/package.json | 3 +- ...slack-question-channel-suggestions.test.ts | 9 +- .../fast-agent-native-tool-schemas.test.ts | 2 +- .../fast-agent-native-tool-bridge.ts | 4 +- .../server/fast-agent/fast-agent-service.ts | 6 +- .../src/server/mcp-nullable-optionals.test.ts | 55 +++- .../src/server/mcp-nullable-optionals.ts | 76 +++-- .../src/server/non-task-provider-usage.ts | 10 +- .../cloud-agents/src/server/task-run-queue.ts | 4 +- packages/communication/package.json | 2 +- .../communication/scripts/run-mock-discord.ts | 2 +- .../scripts/run-mock-telegram.ts | 8 +- .../src/mock-agentmail-config.ts | 4 +- packages/db/package.json | 2 +- packages/db/src/lib/custom-skills.ts | 2 +- packages/env/package.json | 2 +- packages/gitea/package.json | 2 +- packages/gitea/src/api.ts | 2 +- packages/github/package.json | 2 +- packages/gitlab/package.json | 2 +- packages/linear/package.json | 2 +- packages/linear/src/types.ts | 2 +- packages/sdk/package.json | 2 +- .../vulnerability-watch/matching.ts | 2 +- .../server/lib/automation-recommendations.ts | 4 +- .../sdk/src/server/lib/credential-egress.ts | 7 +- .../lib/task-runs/pr-review-notification.ts | 6 +- .../pull-request-mergeability-check.ts | 2 +- .../sdk/src/server/routers/linear-sessions.ts | 2 +- packages/sdk/src/server/routers/llm-usage.ts | 9 +- .../sdk/src/server/routers/mcp-connections.ts | 6 +- packages/sdk/src/server/routers/task-runs.ts | 11 +- .../sdk/src/server/routers/tool-approvals.ts | 4 +- packages/sdk/src/server/trpc.ts | 2 +- packages/slack/package.json | 2 +- packages/types/package.json | 2 +- packages/types/src/auth.ts | 18 +- .../types/src/automation-additional-rules.ts | 4 +- packages/types/src/credential-egress.ts | 2 +- packages/types/src/custom-mcp-servers.ts | 14 +- packages/types/src/environment-config.ts | 25 +- packages/types/src/environment-recipe.ts | 2 +- packages/types/src/fast-agent-capabilities.ts | 2 +- packages/types/src/fast-agent.ts | 2 +- .../types/src/integration-tool-approvals.ts | 2 +- packages/types/src/integration-tool-lookup.ts | 4 +- .../src/manage-custom-automations-tool.ts | 28 +- packages/types/src/manage-tasks-tool.ts | 2 +- packages/types/src/service-credentials.ts | 8 +- packages/types/src/source-control.ts | 2 +- packages/types/src/task-launch-api.ts | 6 +- packages/types/src/task-runs.ts | 22 +- pnpm-lock.yaml | 274 +++++++++--------- 109 files changed, 609 insertions(+), 491 deletions(-) diff --git a/.docker/app/runtime-deps/api/package.json b/.docker/app/runtime-deps/api/package.json index bc184241c..97cb9825c 100644 --- a/.docker/app/runtime-deps/api/package.json +++ b/.docker/app/runtime-deps/api/package.json @@ -7,11 +7,12 @@ "dompurify": "3.4.17", "jsdom": "26.1.0", "snowflake-sdk": "3.3.0", - "zod": "3.25.76" + "zod": "4.6.7" }, "pnpm": { "overrides": { "axios": "1.20.0", + "@azure/msal-node": "7.1.0", "follow-redirects": "1.16.1", "moment": "2.31.0", "toml": "5.0.1" diff --git a/.docker/app/runtime-deps/api/pnpm-lock.yaml b/.docker/app/runtime-deps/api/pnpm-lock.yaml index 52ca4ee21..04c50bcee 100644 --- a/.docker/app/runtime-deps/api/pnpm-lock.yaml +++ b/.docker/app/runtime-deps/api/pnpm-lock.yaml @@ -6,6 +6,7 @@ settings: overrides: axios: 1.20.0 + '@azure/msal-node': 7.1.0 follow-redirects: 1.16.1 moment: 2.31.0 toml: 5.0.1 @@ -24,8 +25,8 @@ importers: specifier: 3.3.0 version: 3.3.0(asn1.js@5.4.1) zod: - specifier: 3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 packages: @@ -211,8 +212,12 @@ packages: resolution: {integrity: sha512-hgLgfRdbG2AmhXPygebf1KYJEvse86+ZZLWufdiTKaGRYEUqOzHdlf6AS1IiuUCHWbynkgbHc451jSNkbfhWlg==} engines: {node: '>=0.8.0'} - '@azure/msal-node@5.5.0': - resolution: {integrity: sha512-A/2WIsuH0vsC6JVkkafjS4kHpi2LDR4AzDT0kJ+oIRtXYeYtvGQ2pwN2X88thQPhSek+82ela3MprsKXWQRrhQ==} + '@azure/msal-common@16.14.2': + resolution: {integrity: sha512-HOBR0Gfo39TMrkxNG8k6cfjRkrRjXZc3JQs3ebMWQc9S4cihuknMYra3sgmzbZB752oQBqBN9+WF7c826p2vIQ==} + engines: {node: '>=0.8.0'} + + '@azure/msal-node@7.1.0': + resolution: {integrity: sha512-s1O6hSY/C/dmqykTmmeHY6GhSkDuY8N1gxyhuLyaCwbY7N+UBvU2Wu4flas7+NxZiAPcXNPVpgt3n/HP/5yL+w==} engines: {node: '>=20'} '@azure/storage-blob@12.26.0': @@ -885,8 +890,8 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} snapshots: @@ -1238,7 +1243,7 @@ snapshots: '@azure/core-util': 1.14.0 '@azure/logger': 1.4.0 '@azure/msal-browser': 5.18.0 - '@azure/msal-node': 5.5.0 + '@azure/msal-node': 7.1.0 open: 10.2.0 tslib: 2.8.1 transitivePeerDependencies: @@ -1257,9 +1262,11 @@ snapshots: '@azure/msal-common@16.12.0': {} - '@azure/msal-node@5.5.0': + '@azure/msal-common@16.14.2': {} + + '@azure/msal-node@7.1.0': dependencies: - '@azure/msal-common': 16.12.0 + '@azure/msal-common': 16.14.2 jsonwebtoken: 9.0.3 '@azure/storage-blob@12.26.0': @@ -1986,4 +1993,4 @@ snapshots: xmlchars@2.2.0: {} - zod@3.25.76: {} + zod@4.6.7: {} diff --git a/apps/api/package.json b/apps/api/package.json index 47e1c5565..b66bbe879 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -50,7 +50,7 @@ "snowflake-sdk": "3.3.0", "svix": "^1.99.1", "undici": "^7.30.1", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@ai-sdk/azure": "3.0.93", diff --git a/apps/api/src/handlers/ado/types.ts b/apps/api/src/handlers/ado/types.ts index 1f42a8e6e..4ee945413 100644 --- a/apps/api/src/handlers/ado/types.ts +++ b/apps/api/src/handlers/ado/types.ts @@ -167,7 +167,7 @@ const adoWorkItemResourceSchema = z // work-item-update shape with per-field old/new values. revision: z .object({ - fields: z.record(adoWorkItemRevisionFieldSchema).optional(), + fields: z.record(z.string(), adoWorkItemRevisionFieldSchema).optional(), revisedBy: adoIdentitySchema.optional(), }) .passthrough() diff --git a/apps/api/src/handlers/custom-automations/index.ts b/apps/api/src/handlers/custom-automations/index.ts index abdac77a7..8536a5677 100644 --- a/apps/api/src/handlers/custom-automations/index.ts +++ b/apps/api/src/handlers/custom-automations/index.ts @@ -63,7 +63,7 @@ const modelSchema = z .regex(/^[^/\s]+\/.+$/u, 'Model must use provider/model format.'); const environmentTargetSchema = z.union([ - z.string().uuid(), + z.guid(), z.literal(ALL_REPOSITORIES), z.literal(FAST_EXECUTION), ]); diff --git a/apps/api/src/handlers/inference/jevgrep.ts b/apps/api/src/handlers/inference/jevgrep.ts index c1722c8d8..33ceb5c6b 100644 --- a/apps/api/src/handlers/inference/jevgrep.ts +++ b/apps/api/src/handlers/inference/jevgrep.ts @@ -9,6 +9,7 @@ const requestSchema = z.object({ state: z.unknown(), questions: z .record( + z.string(), z.object({ type: z.literal('noul'), instructions: z.string().min(1).max(32_768), diff --git a/apps/api/src/handlers/mcp/bitbucket.ts b/apps/api/src/handlers/mcp/bitbucket.ts index 5a1756f79..f286f7e88 100644 --- a/apps/api/src/handlers/mcp/bitbucket.ts +++ b/apps/api/src/handlers/mcp/bitbucket.ts @@ -109,11 +109,12 @@ function createServer(auth: Variables['authContext']) { connected?: Awaited>, ) => Promise, ) { - server.registerTool( + const inputSchema = z.object(shape).strict(); + server.registerTool( name, { description, - inputSchema: z.object(shape).strict(), + inputSchema, annotations: { readOnlyHint: readOnly, destructiveHint: !readOnly, @@ -122,7 +123,9 @@ function createServer(auth: Variables['authContext']) { }, async (input) => { try { - const fullName = repository.parse(input.repositoryFullName); + const fullName = repository.parse( + (input as Record).repositoryFullName, + ); const connected = await authorize(auth, fullName); // Resolve through the existing refresh coordinator on every call, never at discovery. const token = await resolveBitbucketOAuthAccessToken(); diff --git a/apps/api/src/handlers/mcp/http-integrations/broker.ts b/apps/api/src/handlers/mcp/http-integrations/broker.ts index 05a5e927f..465dc4001 100644 --- a/apps/api/src/handlers/mcp/http-integrations/broker.ts +++ b/apps/api/src/handlers/mcp/http-integrations/broker.ts @@ -257,7 +257,7 @@ export async function integrationRequest( : undefined; const secretRef = z .string() - .uuid() + .check(z.guid()) .safeParse( typeof rawId === 'string' && rawId.startsWith('session:') ? rawId.slice(8) diff --git a/apps/api/src/handlers/mcp/task-outputs.ts b/apps/api/src/handlers/mcp/task-outputs.ts index 14bbfc371..02ef5963a 100644 --- a/apps/api/src/handlers/mcp/task-outputs.ts +++ b/apps/api/src/handlers/mcp/task-outputs.ts @@ -83,7 +83,7 @@ const commandCursorSchema = z .max(100) .refine((value) => Number.isFinite(Date.parse(value))), ts: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER), - id: z.string().uuid(), + id: z.guid(), }) .strict(); @@ -238,7 +238,7 @@ export async function downloadMemberTaskArtifact( const input = z .object({ taskId: z.string().regex(/^[0-9a-z]{13}$/), - artifactId: z.string().uuid(), + artifactId: z.guid(), }) .strict() .safeParse(c.req.query()); diff --git a/apps/api/src/handlers/tasks/automation-work-items/schema.ts b/apps/api/src/handlers/tasks/automation-work-items/schema.ts index 1b3360c42..0280d2c9c 100644 --- a/apps/api/src/handlers/tasks/automation-work-items/schema.ts +++ b/apps/api/src/handlers/tasks/automation-work-items/schema.ts @@ -12,7 +12,7 @@ const automationWorkItemBaseSchema = z.object({ actionKind: z.string().trim().min(1).max(120), investigationContext: z.string().trim().max(4000).optional(), fingerprint: z.string().trim().max(255).optional(), - targetEnvironmentId: z.string().uuid().optional(), + targetEnvironmentId: z.guid().optional(), workspaceReadiness: workspaceReadinessSchema.optional(), readinessMessage: z.string().trim().min(1).max(500).optional(), }); @@ -28,16 +28,20 @@ export const automationWorkItemSchema = z disposition: z.literal('act'), executionPrompt: z .string({ - required_error: - 'Act automation work items must include executionPrompt.', + error: (issue) => + issue.input === undefined + ? 'Act automation work items must include executionPrompt.' + : undefined, }) .trim() .min(1, 'Act automation work items must include executionPrompt.') .max(6000), targetRepositoryFullName: z .string({ - required_error: - 'Act automation work items must include targetRepositoryFullName.', + error: (issue) => + issue.input === undefined + ? 'Act automation work items must include targetRepositoryFullName.' + : undefined, }) .trim() .min( diff --git a/apps/api/src/handlers/tasks/fastSessionCommunication.ts b/apps/api/src/handlers/tasks/fastSessionCommunication.ts index 343e8a0c8..753eb1203 100644 --- a/apps/api/src/handlers/tasks/fastSessionCommunication.ts +++ b/apps/api/src/handlers/tasks/fastSessionCommunication.ts @@ -21,7 +21,7 @@ import { } from '@roomote/types'; import { z } from 'zod'; -const canonicalFastSessionIdSchema = z.string().uuid(); +const canonicalFastSessionIdSchema = z.guid(); export async function getFastSessionMessagesForUser(params: { sessionId: string; diff --git a/apps/api/src/handlers/tasks/getTaskMessages.ts b/apps/api/src/handlers/tasks/getTaskMessages.ts index ba1c0c4f9..eb2a81494 100644 --- a/apps/api/src/handlers/tasks/getTaskMessages.ts +++ b/apps/api/src/handlers/tasks/getTaskMessages.ts @@ -85,7 +85,7 @@ export async function getTaskMessages( if (!task) { const userId = c.get('mcpAuth').userId; - if (userId && z.string().uuid().safeParse(taskId).success) { + if (userId && z.guid().safeParse(taskId).success) { const [conversation] = await db .select({ id: fastAgentConversations.id }) .from(fastAgentConversations) diff --git a/apps/api/src/handlers/tasks/saveTaskMemory.ts b/apps/api/src/handlers/tasks/saveTaskMemory.ts index 5706ffab4..39c0fe740 100644 --- a/apps/api/src/handlers/tasks/saveTaskMemory.ts +++ b/apps/api/src/handlers/tasks/saveTaskMemory.ts @@ -26,7 +26,7 @@ function describeTaskMemoryIssues( const value = issue.path.reduce( (acc, key) => acc && typeof acc === 'object' - ? (acc as Record)[key] + ? (acc as Record)[key] : undefined, input, ); @@ -36,7 +36,7 @@ function describeTaskMemoryIssues( : Array.isArray(value) ? `${value.length} entries` : undefined; - return `${path}: at most ${issue.maximum} ${issue.type === 'array' ? 'entries' : 'characters'}${actual ? ` (got ${actual})` : ''}`; + return `${path}: at most ${issue.maximum} ${issue.origin === 'array' ? 'entries' : 'characters'}${actual ? ` (got ${actual})` : ''}`; } return `${path}: ${issue.message}`; }) diff --git a/apps/api/src/handlers/tasks/submitTaskSuggestions.ts b/apps/api/src/handlers/tasks/submitTaskSuggestions.ts index ebd47b9b7..ebf468ea7 100644 --- a/apps/api/src/handlers/tasks/submitTaskSuggestions.ts +++ b/apps/api/src/handlers/tasks/submitTaskSuggestions.ts @@ -103,7 +103,7 @@ const taskSuggestionSchema = z.object({ priority: z.enum(['P0', 'P1', 'P2', 'P3']).optional(), investigationContext: z.string().trim().max(4000).optional(), targetRepositoryFullName: z.string().trim().min(1).optional(), - targetEnvironmentId: z.string().uuid().optional(), + targetEnvironmentId: z.guid().optional(), workspaceReadiness: workspaceReadinessSchema.optional(), readinessMessage: z.string().trim().min(1).max(500).optional(), }); diff --git a/apps/bullmq/package.json b/apps/bullmq/package.json index 288af5c1b..2de159ca0 100644 --- a/apps/bullmq/package.json +++ b/apps/bullmq/package.json @@ -39,7 +39,7 @@ "hono": "4.13.11", "ioredis": "^5.10.1", "jsdom": "26.1.0", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/apps/bullmq/src/jobs/snapshot.ts b/apps/bullmq/src/jobs/snapshot.ts index 64cec7df6..28e06a3a1 100644 --- a/apps/bullmq/src/jobs/snapshot.ts +++ b/apps/bullmq/src/jobs/snapshot.ts @@ -92,7 +92,7 @@ const snapshotFailureMetadataSchema = z .object({ name: z.string().min(1).nullish(), responseHeaders: z - .record(z.unknown()) + .record(z.string(), z.unknown()) .nullish() .transform((headers) => Object.fromEntries( diff --git a/apps/preview-proxy/package.json b/apps/preview-proxy/package.json index c054df5b5..df1b760aa 100644 --- a/apps/preview-proxy/package.json +++ b/apps/preview-proxy/package.json @@ -30,7 +30,7 @@ "http-proxy": "^1.18.1", "pino": "^9.7.0", "pino-pretty": "^13.1.3", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/apps/web/package.json b/apps/web/package.json index d46b264df..4237bae44 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -133,7 +133,7 @@ "usehooks-ts": "^3.1.1", "vaul": "^1.1.2", "yaml": "^2.9.0", - "zod": "^3.25.76", + "zod": "^4.6.6", "zustand": "^5.0.10" }, "devDependencies": { diff --git a/apps/web/src/app/(authenticated)/platform-issues/[reportId]/submit/page.tsx b/apps/web/src/app/(authenticated)/platform-issues/[reportId]/submit/page.tsx index ddf5e3eb8..6edcef106 100644 --- a/apps/web/src/app/(authenticated)/platform-issues/[reportId]/submit/page.tsx +++ b/apps/web/src/app/(authenticated)/platform-issues/[reportId]/submit/page.tsx @@ -6,7 +6,7 @@ import { getPlatformIssueReportCommand } from '@/trpc/commands/platform-issue-re import { PlatformIssueSubmission } from './PlatformIssueSubmission'; -const reportIdSchema = z.string().uuid(); +const reportIdSchema = z.guid(); export default async function Page({ params, diff --git a/apps/web/src/app/(sandbox)/sessions/[sessionId]/page.tsx b/apps/web/src/app/(sandbox)/sessions/[sessionId]/page.tsx index be98129b8..087881947 100644 --- a/apps/web/src/app/(sandbox)/sessions/[sessionId]/page.tsx +++ b/apps/web/src/app/(sandbox)/sessions/[sessionId]/page.tsx @@ -46,7 +46,7 @@ const getSessionPageData = cache(async (sessionId: string) => { } // Both lookup columns are uuid; a garbage route param would otherwise throw // 22P02 in Postgres instead of 404ing. - if (!z.string().uuid().safeParse(sessionId).success) { + if (!z.guid().safeParse(sessionId).success) { notFound(); } diff --git a/apps/web/src/app/api/mcp-remote-oauth/authorize/route.ts b/apps/web/src/app/api/mcp-remote-oauth/authorize/route.ts index 2aca2600a..8a1364fe5 100644 --- a/apps/web/src/app/api/mcp-remote-oauth/authorize/route.ts +++ b/apps/web/src/app/api/mcp-remote-oauth/authorize/route.ts @@ -18,7 +18,7 @@ export const dynamic = 'force-dynamic'; const authorizeSchema = z.object({ response_type: z.literal('code'), - client_id: z.string().uuid(), + client_id: z.guid(), redirect_uri: z.string().url(), state: z.string().min(1), code_challenge: z.string().regex(/^[A-Za-z0-9_-]{43}$/), diff --git a/apps/web/src/app/api/mcp-remote-oauth/revoke/route.ts b/apps/web/src/app/api/mcp-remote-oauth/revoke/route.ts index 2e82246db..fe4a9f8b8 100644 --- a/apps/web/src/app/api/mcp-remote-oauth/revoke/route.ts +++ b/apps/web/src/app/api/mcp-remote-oauth/revoke/route.ts @@ -7,7 +7,7 @@ export const runtime = 'nodejs'; const revocationSchema = z.object({ token: z.string().min(1), - client_id: z.string().uuid(), + client_id: z.guid(), }); export async function POST(request: NextRequest) { diff --git a/apps/web/src/app/api/mcp-remote-oauth/token/route.ts b/apps/web/src/app/api/mcp-remote-oauth/token/route.ts index 3f488fff4..0df5a0628 100644 --- a/apps/web/src/app/api/mcp-remote-oauth/token/route.ts +++ b/apps/web/src/app/api/mcp-remote-oauth/token/route.ts @@ -27,7 +27,7 @@ const tokenSchema = z.discriminatedUnion('grant_type', [ z.object({ grant_type: z.literal('authorization_code'), code: z.string().min(1), - client_id: z.string().uuid(), + client_id: z.guid(), redirect_uri: z.string().url(), code_verifier: z.string().regex(/^[A-Za-z0-9._~-]{43,128}$/), resource: z.string().url().optional(), @@ -35,7 +35,7 @@ const tokenSchema = z.discriminatedUnion('grant_type', [ z.object({ grant_type: z.literal('refresh_token'), refresh_token: z.string().min(1), - client_id: z.string().uuid(), + client_id: z.guid(), resource: z.string().url().optional(), scope: z.string().optional(), }), diff --git a/apps/web/src/app/api/sessions/[sessionId]/attention/route.ts b/apps/web/src/app/api/sessions/[sessionId]/attention/route.ts index 0c2a4eff1..7f2109d37 100644 --- a/apps/web/src/app/api/sessions/[sessionId]/attention/route.ts +++ b/apps/web/src/app/api/sessions/[sessionId]/attention/route.ts @@ -9,10 +9,10 @@ import { findAccessibleSession } from '@/lib/server/sessions'; export const runtime = 'nodejs'; -const paramsSchema = z.object({ sessionId: z.string().uuid() }); +const paramsSchema = z.object({ sessionId: z.guid() }); const bodySchema = z.object({ - notificationId: z.string().uuid(), - clientId: z.string().uuid(), + notificationId: z.guid(), + clientId: z.guid(), action: z.enum(['accepted', 'failed', 'opened']), }); diff --git a/apps/web/src/app/api/sessions/[sessionId]/attention/stream/route.ts b/apps/web/src/app/api/sessions/[sessionId]/attention/stream/route.ts index 576fd3b2a..0153992a4 100644 --- a/apps/web/src/app/api/sessions/[sessionId]/attention/stream/route.ts +++ b/apps/web/src/app/api/sessions/[sessionId]/attention/stream/route.ts @@ -16,9 +16,9 @@ import { findAccessibleSession } from '@/lib/server/sessions'; export const runtime = 'nodejs'; -const paramsSchema = z.object({ sessionId: z.string().uuid() }); +const paramsSchema = z.object({ sessionId: z.guid() }); const querySchema = z.object({ - clientId: z.string().uuid(), + clientId: z.guid(), permission: z.enum(['granted', 'default', 'denied', 'unsupported']), }); const POLL_INTERVAL_MS = 1_000; diff --git a/apps/web/src/app/api/sessions/[sessionId]/integration-tool-approvals/route.ts b/apps/web/src/app/api/sessions/[sessionId]/integration-tool-approvals/route.ts index c4c2672d5..d06419eec 100644 --- a/apps/web/src/app/api/sessions/[sessionId]/integration-tool-approvals/route.ts +++ b/apps/web/src/app/api/sessions/[sessionId]/integration-tool-approvals/route.ts @@ -30,7 +30,7 @@ async function handle(request: Request, props: Props, method: 'GET' | 'POST') { const auth = await authorize(); if (!auth.success || !auth.userId) return error(401); const params = z - .object({ sessionId: z.string().uuid() }) + .object({ sessionId: z.guid() }) .safeParse(await props.params); if (!params.success) return error(400); const context = { sessionId: params.data.sessionId, userId: auth.userId }; diff --git a/apps/web/src/app/api/sessions/[sessionId]/presence/route.ts b/apps/web/src/app/api/sessions/[sessionId]/presence/route.ts index f1f3d16d5..9b0ff8709 100644 --- a/apps/web/src/app/api/sessions/[sessionId]/presence/route.ts +++ b/apps/web/src/app/api/sessions/[sessionId]/presence/route.ts @@ -18,9 +18,9 @@ import { getUsersById } from '@/lib/server/users'; export const runtime = 'nodejs'; -const paramsSchema = z.object({ sessionId: z.string().uuid() }); +const paramsSchema = z.object({ sessionId: z.guid() }); const bodySchema = z.object({ - clientId: z.string().uuid(), + clientId: z.guid(), channel: z.enum(['view', 'voice']).default('view'), generation: z.number().int().nonnegative().optional(), }); diff --git a/apps/web/src/app/api/sessions/[sessionId]/secrets/route.ts b/apps/web/src/app/api/sessions/[sessionId]/secrets/route.ts index 5b584ef48..3677ebb04 100644 --- a/apps/web/src/app/api/sessions/[sessionId]/secrets/route.ts +++ b/apps/web/src/app/api/sessions/[sessionId]/secrets/route.ts @@ -41,7 +41,7 @@ async function handle( const auth = await authorize(); if (!auth.success || !auth.userId) return error(401); const params = z - .object({ sessionId: z.string().uuid() }) + .object({ sessionId: z.guid() }) .safeParse(await props.params); if (!params.success) return error(400); const context = { sessionId: params.data.sessionId, userId: auth.userId }; diff --git a/apps/web/src/app/api/sessions/[sessionId]/stream/route.ts b/apps/web/src/app/api/sessions/[sessionId]/stream/route.ts index dff32f19c..516ee06cc 100644 --- a/apps/web/src/app/api/sessions/[sessionId]/stream/route.ts +++ b/apps/web/src/app/api/sessions/[sessionId]/stream/route.ts @@ -43,7 +43,7 @@ export async function GET( } const { sessionId } = await props.params; - const parsedSessionId = z.string().uuid().safeParse(sessionId); + const parsedSessionId = z.guid().safeParse(sessionId); if (!parsedSessionId.success) { return NextResponse.json({ error: 'Not Found' }, { status: 404 }); } diff --git a/apps/web/src/components/system/primitives/form.stories.tsx b/apps/web/src/components/system/primitives/form.stories.tsx index 57e30f1d4..79345d159 100644 --- a/apps/web/src/components/system/primitives/form.stories.tsx +++ b/apps/web/src/components/system/primitives/form.stories.tsx @@ -125,7 +125,10 @@ const profileFormSchema = z.object({ }), email: z .string({ - required_error: 'Please select an email to display.', + error: (issue) => + issue.input === undefined + ? 'Please select an email to display.' + : undefined, }) .email(), bio: z.string().max(160).min(4), @@ -243,11 +246,15 @@ const settingsFormSchema = z.object({ marketingEmails: z.boolean().default(false).optional(), securityEmails: z.boolean(), communicationMethod: z.enum(['email', 'sms', 'push'], { - required_error: 'You need to select a notification method.', + error: (issue) => + issue.input === undefined + ? 'You need to select a notification method.' + : undefined, }), theme: z.enum(['light', 'dark', 'system']), language: z.string({ - required_error: 'Please select a language.', + error: (issue) => + issue.input === undefined ? 'Please select a language.' : undefined, }), }); diff --git a/apps/web/src/lib/server/fast-session-reply-stream.ts b/apps/web/src/lib/server/fast-session-reply-stream.ts index 70c9098bd..aaefa4868 100644 --- a/apps/web/src/lib/server/fast-session-reply-stream.ts +++ b/apps/web/src/lib/server/fast-session-reply-stream.ts @@ -17,8 +17,8 @@ const replyChunkEventSchema = z.object({ contentBlocks: z.array( z.object({ type: z.literal('text'), text: z.string() }), ), - metadata: z.record(z.unknown()).nullable(), - payload: z.record(z.unknown()), + metadata: z.record(z.string(), z.unknown()).nullable(), + payload: z.record(z.string(), z.unknown()), logicalEventId: z.string().optional(), text: z.string().optional(), }); diff --git a/apps/web/src/trpc/commands/automations/ci-failure-triage-routing.ts b/apps/web/src/trpc/commands/automations/ci-failure-triage-routing.ts index 445a87f48..3f9483144 100644 --- a/apps/web/src/trpc/commands/automations/ci-failure-triage-routing.ts +++ b/apps/web/src/trpc/commands/automations/ci-failure-triage-routing.ts @@ -32,11 +32,9 @@ import type { UserAuthSuccess } from '@/types'; const resolutionSchema = z .object({ status: z.enum(['resolved', 'ambiguous']), - repositoryIds: z.array(z.string().uuid()).nullable(), + repositoryIds: z.array(z.guid()).nullable(), destinations: z.array( - z - .object({ repositoryId: z.string().uuid(), destinationId: z.string() }) - .strict(), + z.object({ repositoryId: z.guid(), destinationId: z.string() }).strict(), ), instructions: z.string(), clarification: z.string().nullable(), diff --git a/apps/web/src/trpc/commands/fast-sessions/input.test.ts b/apps/web/src/trpc/commands/fast-sessions/input.test.ts index bdef416ab..b779f1e40 100644 --- a/apps/web/src/trpc/commands/fast-sessions/input.test.ts +++ b/apps/web/src/trpc/commands/fast-sessions/input.test.ts @@ -76,15 +76,21 @@ describe('Session input schemas', () => { }); it('rejects too many extracted attachments', () => { - expect(() => - startFastSessionInputSchema.parse({ - text: 'Implement these plans', - attachmentTexts: Array.from( - { length: 21 }, - (_, index) => `Attachment ${index}`, - ), + const result = startFastSessionInputSchema.safeParse({ + text: 'Implement these plans', + attachmentTexts: Array.from( + { length: 21 }, + (_, index) => `Attachment ${index}`, + ), + }); + expect(result.success).toBe(false); + expect(result.error?.issues).toEqual([ + expect.objectContaining({ + code: 'too_big', + maximum: 20, + path: ['attachmentTexts'], }), - ).toThrow('Array must contain at most 20 element(s)'); + ]); }); it('rejects extracted attachment text over the aggregate limit', () => { diff --git a/apps/web/src/trpc/commands/fast-sessions/input.ts b/apps/web/src/trpc/commands/fast-sessions/input.ts index 18f11298b..436f8d75b 100644 --- a/apps/web/src/trpc/commands/fast-sessions/input.ts +++ b/apps/web/src/trpc/commands/fast-sessions/input.ts @@ -41,11 +41,11 @@ const fastSessionMessageInputShape = { * prompt opens a blank workspace. */ export const pinnedFastSessionLaunchSchema = z.object({ - launchId: z.string().uuid(), + launchId: z.guid(), repo: z.string().trim().min(1), branch: z.string().trim().min(1).optional(), sha: z.string().trim().min(1).optional(), - environmentId: z.string().uuid().optional(), + environmentId: z.guid().optional(), harness: z.enum(launchCodingHarnesses).optional(), computeProvider: z.enum(computeProviders).optional(), }); @@ -93,7 +93,7 @@ function requireFastSessionContent( export const startFastSessionInputSchema = z .object({ ...fastSessionMessageInputShape, - conversationId: z.string().uuid().optional(), + conversationId: z.guid().optional(), privacy: z.enum(['shared', 'private']).optional(), pinnedLaunch: pinnedFastSessionLaunchSchema.optional(), /** Open the Session for a voice call; any text is the pre-typed message. */ @@ -105,18 +105,18 @@ export const startFastSessionInputSchema = z export const fastSessionAutoToolApprovalsInputSchema = z.object({ /** The unified session; omitted for one that has not started yet. */ - sessionId: z.string().uuid().optional(), + sessionId: z.guid().optional(), }); export const setFastSessionAutoToolApprovalsInputSchema = z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), enabled: z.boolean(), }); export const replyToFastSessionInputSchema = z .object({ - sessionId: z.string().uuid(), - clientMessageId: z.string().uuid().optional(), + sessionId: z.guid(), + clientMessageId: z.guid().optional(), /** The message was spoken on a voice call; the reply goes to the voice. */ voiceMode: z.boolean().optional(), ...fastSessionMessageInputShape, @@ -124,29 +124,29 @@ export const replyToFastSessionInputSchema = z .superRefine(requireFastSessionContent); export const deleteFastSessionQueuedMessageInputSchema = z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), /** The client id the queued reply was sent with. */ - clientMessageId: z.string().uuid(), + clientMessageId: z.guid(), }); export const steerFastSessionQueuedMessageInputSchema = z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), /** The client id of the oldest queued reply to send now. */ - clientMessageId: z.string().uuid(), + clientMessageId: z.guid(), }); export const stopFastSessionInputSchema = z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), }); export const fastSessionPrReviewActionInputSchema = z.object({ - sessionId: z.string().uuid(), - deliveryId: z.string().uuid(), + sessionId: z.guid(), + deliveryId: z.guid(), choice: z.enum(['yes', 'auto', 'dismiss']), }); export const fastSessionCapabilityOfferResponseInputSchema = z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), offerId: z.string().min(1), capability: fastAgentCapabilityIdSchema, resolution: z.enum(['completed', 'dismissed']), @@ -154,7 +154,7 @@ export const fastSessionCapabilityOfferResponseInputSchema = z.object({ }); export const updateFastSessionModelSelectionInputSchema = z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), model: fastSessionMessageInputShape.model, reasoningEffort: fastSessionMessageInputShape.reasoningEffort, }); diff --git a/apps/web/src/trpc/commands/sandbox-session/index.ts b/apps/web/src/trpc/commands/sandbox-session/index.ts index 7a74927a1..eb90f6981 100644 --- a/apps/web/src/trpc/commands/sandbox-session/index.ts +++ b/apps/web/src/trpc/commands/sandbox-session/index.ts @@ -97,6 +97,7 @@ export function shouldPollForAutomaticFailedStartRetry(input: { ); } const requestUserInputAnswersSchema = z.record( + z.string(), z.object({ answers: z.array(z.string()), }), @@ -206,7 +207,7 @@ export const answerSandboxUserInputRequestInputSchema = z.object({ }); export const handlePrReviewNotificationActionInputSchema = z.object({ - deliveryId: z.string().uuid(), + deliveryId: z.guid(), choice: z.enum(['yes', 'auto', 'dismiss']), }); diff --git a/apps/web/src/trpc/commands/sessions/index.ts b/apps/web/src/trpc/commands/sessions/index.ts index 74280af3a..690ea8795 100644 --- a/apps/web/src/trpc/commands/sessions/index.ts +++ b/apps/web/src/trpc/commands/sessions/index.ts @@ -62,7 +62,7 @@ const ARTIFACT_SIGNATURE_CACHE_WINDOW_SECONDS = 60 * 60; const TASK_STOP_WAIT_MS = 15_000; const TASK_STOP_POLL_MS = 100; -export const sessionIdInputSchema = z.object({ sessionId: z.string().uuid() }); +export const sessionIdInputSchema = z.object({ sessionId: z.guid() }); export const sessionStatusInputSchema = sessionIdInputSchema.extend({ status: z.enum(SESSION_MANUAL_STATUSES), }); @@ -561,7 +561,7 @@ export const sessionsListInputSchema = z.object({ model: z.string().nullish(), period: z.union([z.literal('all'), z.number().int().positive()]).optional(), q: z.string().max(200).nullish(), - ids: z.array(z.string().uuid()).max(20).optional(), + ids: z.array(z.guid()).max(20).optional(), ownedOnly: z.boolean().optional(), before: z.string().nullish(), limit: z.number().int().min(1).max(200).optional(), diff --git a/apps/web/src/trpc/routers/_app.ts b/apps/web/src/trpc/routers/_app.ts index c3ec47de0..619a25f4a 100644 --- a/apps/web/src/trpc/routers/_app.ts +++ b/apps/web/src/trpc/routers/_app.ts @@ -605,7 +605,7 @@ import { } from '../commands/platform-issue-reports'; import { getStatuspageIncident } from '@roomote/slack'; -const stateRecordSchema = z.record(z.string()); +const stateRecordSchema = z.record(z.string(), z.string()); function assertAdmin(auth: { isAdmin: boolean }) { if (!auth.isAdmin) throw new Error('Unauthorized'); @@ -721,7 +721,7 @@ const automationsRouter = createRouter({ ), reviewerEnabled: z.boolean(), reviewerEnvironmentScope: z.enum(['all', 'specific']), - reviewerEnvironmentIds: z.array(z.string().uuid()), + reviewerEnvironmentIds: z.array(z.guid()), reviewerAuthorReviewMode: z.enum(['all', 'specific', 'none']), reviewerCollaborators: z.array(z.string().trim().min(1).max(255)), reviewerExcludedAuthors: z.string().max(8_000).nullable(), @@ -1033,7 +1033,7 @@ const automationsRouter = createRouter({ ), getCustomAutomationOptions: protectedProcedure - .input(z.object({ automationId: z.string().uuid().optional() }).optional()) + .input(z.object({ automationId: z.guid().optional() }).optional()) .query(({ ctx: { auth }, input }) => getCustomAutomationOptionsCommand(auth, input ?? {}), ), @@ -1069,7 +1069,7 @@ const automationsRouter = createRouter({ .optional(), reasoningEffort: z.enum(REASONING_EFFORT_VALUES).nullable().optional(), environmentId: z.union([ - z.string().uuid(), + z.guid(), z.literal(ALL_REPOSITORIES), z.literal(NO_REPOSITORIES), z.literal(FAST_EXECUTION), @@ -1095,7 +1095,7 @@ const automationsRouter = createRouter({ updateCustomAutomation: protectedProcedure .input( z.object({ - id: z.string().uuid(), + id: z.guid(), name: z.string().trim().min(1).max(100), prompt: z .string() @@ -1124,7 +1124,7 @@ const automationsRouter = createRouter({ .optional(), reasoningEffort: z.enum(REASONING_EFFORT_VALUES).nullable().optional(), environmentId: z.union([ - z.string().uuid(), + z.guid(), z.literal(ALL_REPOSITORIES), z.literal(NO_REPOSITORIES), z.literal(FAST_EXECUTION), @@ -1148,31 +1148,31 @@ const automationsRouter = createRouter({ ), getCustomAutomationWebhook: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .query(({ ctx: { auth }, input }) => getCustomAutomationWebhookCommand(auth, input), ), setCustomAutomationWebhookEnabled: protectedProcedure - .input(z.object({ id: z.string().uuid(), enabled: z.boolean() })) + .input(z.object({ id: z.guid(), enabled: z.boolean() })) .mutation(({ ctx: { auth }, input }) => setCustomAutomationWebhookEnabledCommand(auth, input), ), rotateCustomAutomationWebhook: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .mutation(({ ctx: { auth }, input }) => rotateCustomAutomationWebhookCommand(auth, input), ), deleteCustomAutomation: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .mutation(({ ctx: { auth }, input }) => deleteCustomAutomationCommand(auth, input), ), triggerCustomAutomation: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .mutation(({ ctx: { auth }, input }) => triggerCustomAutomationCommand(auth, input), ), @@ -1266,7 +1266,7 @@ export const appRouter = createRouter({ .object({ createdAt: z.string(), ts: z.number(), - id: z.string().uuid(), + id: z.guid(), }) .optional(), }), @@ -1349,12 +1349,12 @@ export const appRouter = createRouter({ platformIssueReports: createRouter({ byId: protectedProcedure - .input(z.object({ reportId: z.string().uuid() })) + .input(z.object({ reportId: z.guid() })) .query(({ ctx: { auth }, input }) => getPlatformIssueReportCommand(auth, input.reportId), ), submit: protectedProcedure - .input(z.object({ reportId: z.string().uuid() })) + .input(z.object({ reportId: z.guid() })) .mutation(({ ctx: { auth }, input }) => submitPlatformIssueReportCommand(auth, input.reportId), ), @@ -1366,7 +1366,7 @@ export const appRouter = createRouter({ z .object({ taskId: z.string().optional(), - sessionId: z.string().uuid().optional(), + sessionId: z.guid().optional(), path: z.string(), version: z.number().optional(), preview: z.boolean().optional(), @@ -1384,7 +1384,7 @@ export const appRouter = createRouter({ z .object({ taskId: z.string().optional(), - sessionId: z.string().uuid().optional(), + sessionId: z.guid().optional(), path: z.string(), }) .refine( @@ -1613,7 +1613,7 @@ export const appRouter = createRouter({ .input( z.object({ provider: sourceControlProviderSchema, - values: z.record(z.string().trim()).optional(), + values: z.record(z.string(), z.string().trim()).optional(), }), ) .mutation(({ ctx: { auth }, input }) => @@ -1914,7 +1914,7 @@ export const appRouter = createRouter({ ), listConfigVersions: protectedProcedure - .input(z.object({ environmentId: z.string().uuid() })) + .input(z.object({ environmentId: z.guid() })) .query(({ ctx: { auth }, input }) => listEnvironmentConfigVersionsCommand(auth, input), ), @@ -1922,7 +1922,7 @@ export const appRouter = createRouter({ getConfigVersion: protectedProcedure .input( z.object({ - environmentId: z.string().uuid(), + environmentId: z.guid(), version: z.number().int().min(1), }), ) @@ -1937,7 +1937,7 @@ export const appRouter = createRouter({ activeDefinitionTask: protectedProcedure .input( z.object({ - environmentId: z.string().uuid(), + environmentId: z.guid(), }), ) .query(({ ctx: { auth }, input }) => @@ -1949,7 +1949,7 @@ export const appRouter = createRouter({ z.object({ name: z.string().min(1), description: z.string().optional(), - config: z.record(z.unknown()), + config: z.record(z.string(), z.unknown()), }), ) .mutation(({ ctx: { auth }, input }) => @@ -1966,7 +1966,7 @@ export const appRouter = createRouter({ name: z.string().min(1).optional(), description: z.string().optional(), agentInstructions: z.string().optional(), - config: z.record(z.unknown()).optional(), + config: z.record(z.string(), z.unknown()).optional(), }), ) .mutation(({ ctx: { auth }, input }) => @@ -1979,7 +1979,7 @@ export const appRouter = createRouter({ startDefinitionTask: protectedProcedure .input( z.object({ - repositoryIds: z.array(z.string().uuid()), + repositoryIds: z.array(z.guid()), environmentId: z.string().optional(), changeRequest: z.string().trim().min(1).max(8_000).optional(), selectedModelId: z.string().trim().min(1).optional(), @@ -1996,7 +1996,7 @@ export const appRouter = createRouter({ ), retryVerification: protectedProcedure - .input(z.object({ environmentId: z.string().uuid() })) + .input(z.object({ environmentId: z.guid() })) .mutation(({ ctx: { auth }, input }) => retryEnvironmentVerificationCommand(auth, input), ), @@ -2125,7 +2125,7 @@ export const appRouter = createRouter({ setVisibility: protectedProcedure .input( z.object({ - id: z.string().uuid(), + id: z.guid(), visibility: customMcpServerVisibilitySchema, }), ) @@ -2134,21 +2134,19 @@ export const appRouter = createRouter({ ), update: protectedProcedure - .input( - z.object({ id: z.string().uuid(), server: customMcpServerInputSchema }), - ) + .input(z.object({ id: z.guid(), server: customMcpServerInputSchema })) .mutation(({ ctx: { auth }, input }) => updateCustomMcpServerCommand(auth, input), ), delete: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .mutation(({ ctx: { auth }, input }) => deleteCustomMcpServerCommand(auth, input), ), setEnabled: protectedProcedure - .input(z.object({ id: z.string().uuid(), enabled: z.boolean() })) + .input(z.object({ id: z.guid(), enabled: z.boolean() })) .mutation(({ ctx: { auth }, input }) => setCustomMcpServerEnabledCommand(auth, input), ), @@ -2156,7 +2154,7 @@ export const appRouter = createRouter({ setDisabledTools: protectedProcedure .input( z.object({ - id: z.string().uuid(), + id: z.guid(), disabledTools: z.array(z.string().min(1)), }), ) @@ -2165,21 +2163,19 @@ export const appRouter = createRouter({ ), listTools: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .query(({ ctx: { auth }, input }) => listCustomMcpServerToolsCommand(auth, input), ), connect: protectedProcedure - .input( - z.object({ id: z.string().uuid(), redirectTo: z.string().optional() }), - ) + .input(z.object({ id: z.guid(), redirectTo: z.string().optional() })) .mutation(({ ctx: { auth }, input }) => connectCustomMcpServerCommand(auth, input), ), disconnect: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .mutation(({ ctx: { auth }, input }) => disconnectCustomMcpServerCommand(auth, input), ), @@ -2427,7 +2423,7 @@ export const appRouter = createRouter({ .input( z.object({ provider: z.enum(COMMS_PROVIDER_IDS), - values: z.record(z.string().trim()).optional(), + values: z.record(z.string(), z.string().trim()).optional(), }), ) .mutation(({ ctx: { auth }, input }) => @@ -2494,7 +2490,7 @@ export const appRouter = createRouter({ .input( z.object({ provider: z.enum(computeProviders), - values: z.record(z.string().trim()).optional(), + values: z.record(z.string(), z.string().trim()).optional(), }), ) .mutation(({ ctx: { auth }, input }) => @@ -2661,7 +2657,7 @@ export const appRouter = createRouter({ ), delete: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .mutation(({ ctx: { auth }, input }) => deleteUserTaskModelMappingPresetCommand(auth, input), ), @@ -2691,7 +2687,9 @@ export const appRouter = createRouter({ .trim() .refine(isSetupModelProviderId, 'Invalid model provider.'), apiKey: z.string().trim().optional(), - additionalEnvValues: z.record(z.string().trim()).optional(), + additionalEnvValues: z + .record(z.string(), z.string().trim()) + .optional(), connectionName: z.string().trim().optional(), modelId: z.string().trim().optional(), }), @@ -2897,7 +2895,7 @@ export const appRouter = createRouter({ .input( z.object({ enabled: z.boolean(), - roles: z.record( + roles: z.partialRecord( z.enum(TASK_MODEL_ROLES as [TaskModelRole, ...TaskModelRole[]]), z.object({ modelId: z.string().trim().min(1), @@ -3010,7 +3008,7 @@ export const appRouter = createRouter({ .array( z.object({ name: z.string().min(1).max(100), - repositoryIds: z.array(z.string().uuid()), + repositoryIds: z.array(z.guid()), installCommand: z.string().max(500).optional(), testCommand: z.string().max(500).optional(), }), @@ -3042,7 +3040,7 @@ export const appRouter = createRouter({ completeWithStarterTasks: protectedProcedure .input( z.object({ - launchBatchId: z.string().uuid(), + launchBatchId: z.guid(), selectedStarterTaskIds: z .array(z.enum(SETUP_STARTER_TASK_IDS)) .max(SETUP_STARTER_TASK_IDS.length), @@ -3063,7 +3061,7 @@ export const appRouter = createRouter({ ), skipSourceControl: protectedProcedure - .input(z.object({ sessionId: z.string().uuid() })) + .input(z.object({ sessionId: z.guid() })) .mutation(({ ctx: { auth }, input }) => skipSetupSourceControlCommand(auth, input.sessionId), ), @@ -3071,9 +3069,12 @@ export const appRouter = createRouter({ submitSessionUserInput: protectedProcedure .input( z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), requestId: z.string().min(1), - answers: z.record(z.object({ answers: z.array(z.string()).max(50) })), + answers: z.record( + z.string(), + z.object({ answers: z.array(z.string()).max(50) }), + ), }), ) .mutation(({ ctx: { auth }, input }) => @@ -3114,7 +3115,7 @@ export const appRouter = createRouter({ .input( z.object({ provider: z.enum(SETUP_AUTH_PROVIDER_IDS), - values: z.record(z.string().trim()).optional(), + values: z.record(z.string(), z.string().trim()).optional(), }), ) .mutation(({ ctx: { auth }, input }) => @@ -3129,7 +3130,9 @@ export const appRouter = createRouter({ .trim() .refine(isSetupModelProviderId, 'Invalid model provider.'), apiKey: z.string().trim().optional(), - additionalEnvValues: z.record(z.string().trim()).optional(), + additionalEnvValues: z + .record(z.string(), z.string().trim()) + .optional(), connectionName: z.string().trim().optional(), modelId: z.string().trim().optional(), }), @@ -3164,7 +3167,7 @@ export const appRouter = createRouter({ .input( z.object({ provider: z.enum(computeProviders), - values: z.record(z.string().trim()).optional(), + values: z.record(z.string(), z.string().trim()).optional(), }), ) .mutation(async ({ ctx: { auth }, input }) => { @@ -3192,7 +3195,7 @@ export const appRouter = createRouter({ .input( z.object({ provider: sourceControlProviderSchema, - values: z.record(z.string().trim()).optional(), + values: z.record(z.string(), z.string().trim()).optional(), }), ) .mutation(({ ctx: { auth }, input }) => @@ -3202,7 +3205,7 @@ export const appRouter = createRouter({ saveQueuedTasks: protectedProcedure .input( z.object({ - selectedSuggestionIds: z.array(z.string().uuid()).max(5), + selectedSuggestionIds: z.array(z.guid()).max(5), customTaskPrompt: z.string().trim().max(4_000).optional(), }), ) @@ -3251,7 +3254,7 @@ export const appRouter = createRouter({ .input( z.object({ provider: z.enum(SETUP_AUTH_PROVIDER_IDS), - values: z.record(z.string().trim()).optional(), + values: z.record(z.string(), z.string().trim()).optional(), setupToken: z.string().optional(), }), ) @@ -3340,7 +3343,7 @@ export const appRouter = createRouter({ dismiss: protectedProcedure .input( z.object({ - suggestionId: z.string().uuid(), + suggestionId: z.guid(), }), ) .mutation(({ ctx: { auth }, input }) => @@ -3355,7 +3358,7 @@ export const appRouter = createRouter({ get: protectedProcedure .input( z.object({ - id: z.string().uuid(), + id: z.guid(), kind: z.enum(['report', 'suggestion']), }), ) @@ -3369,7 +3372,7 @@ export const appRouter = createRouter({ act: protectedProcedure .input( z.object({ - id: z.string().uuid(), + id: z.guid(), kind: z.enum(['report', 'suggestion']), action: z.enum(['accept', 'ignore']), }), @@ -3381,13 +3384,13 @@ export const appRouter = createRouter({ clearOne: protectedProcedure .input( z.object({ - id: z.string().uuid(), + id: z.guid(), kind: z.enum(['report', 'suggestion']), }), ) .mutation(({ ctx: { auth }, input }) => clearResultCommand(auth, input)), acceptSuggestion: protectedProcedure - .input(z.object({ id: z.string().uuid() })) + .input(z.object({ id: z.guid() })) .mutation(({ ctx: { auth }, input }) => acceptSuggestionResultCommand(auth, input), ), @@ -3426,7 +3429,7 @@ export const appRouter = createRouter({ startGoal: protectedProcedure .input( z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), objective: sessionGoalInputSchema.shape.objective, clientMessageId: z.string().optional(), }), @@ -3460,24 +3463,24 @@ export const appRouter = createRouter({ setFastSessionAutoToolApprovalsCommand(auth, input), ), tasks: protectedProcedure - .input(z.object({ sessionId: z.string().uuid() })) + .input(z.object({ sessionId: z.guid() })) .query(({ ctx: { auth }, input }) => getFastSessionTasksCommand(auth, input.sessionId), ), messages: protectedProcedure - .input(z.object({ sessionId: z.string().uuid() })) + .input(z.object({ sessionId: z.guid() })) .query(({ ctx: { auth }, input }) => getFastSessionMessagesCommand(auth, input.sessionId), ), olderMessages: protectedProcedure .input( z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), cursor: z.object({ createdAt: z.string().min(1).max(64), ts: z.number().int(), turnSeq: z.number().int(), - id: z.string().uuid(), + id: z.guid(), }), }), ) @@ -3487,9 +3490,12 @@ export const appRouter = createRouter({ submitUserInput: protectedProcedure .input( z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), requestId: z.string().min(1), - answers: z.record(z.object({ answers: z.array(z.string()).max(50) })), + answers: z.record( + z.string(), + z.object({ answers: z.array(z.string()).max(50) }), + ), resolution: z.enum(['submitted', 'cancelled']).optional(), }), ) @@ -3499,7 +3505,7 @@ export const appRouter = createRouter({ composerSuggestion: protectedProcedure .input( z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), // Client-side cache keys: bump when the live transcript or the // delegated tasks' state meaningfully change so stale suggestions // are never shown. The server derives its own cache keys from @@ -3540,7 +3546,7 @@ export const appRouter = createRouter({ recordTurn: protectedProcedure .input( z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), role: z.enum(['user', 'assistant']), text: z.string().trim().min(1).max(20_000), }), @@ -3551,7 +3557,7 @@ export const appRouter = createRouter({ recordCallEvent: protectedProcedure .input( z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), phase: z.enum(['started', 'ended']), durationMs: z.number().int().nonnegative().optional(), }), @@ -3568,7 +3574,7 @@ export const appRouter = createRouter({ getSessionWakeupsCommand(auth, input.sessionId), ), cancelWakeup: protectedProcedure - .input(sessionIdInputSchema.extend({ wakeupId: z.string().uuid() })) + .input(sessionIdInputSchema.extend({ wakeupId: z.guid() })) .mutation(({ ctx: { auth }, input }) => cancelSessionWakeupCommand(auth, input), ), @@ -3710,7 +3716,7 @@ export const appRouter = createRouter({ revokeInvite: protectedProcedure .input( z.object({ - inviteId: z.string().uuid(), + inviteId: z.guid(), }), ) .mutation(({ ctx: { auth }, input }) => revokeInviteCommand(auth, input)), @@ -3777,7 +3783,7 @@ export const appRouter = createRouter({ .input( z.object({ skillId: z.string().min(3), - environmentIds: z.array(z.string().uuid()).min(1), + environmentIds: z.array(z.guid()).min(1), }), ) .mutation(({ ctx: { auth }, input }) => @@ -3790,7 +3796,7 @@ export const appRouter = createRouter({ name: z.string().min(1), description: z.string().min(1), content: z.string().min(1), - environmentIds: z.array(z.string().uuid()).min(1), + environmentIds: z.array(z.guid()).min(1), previousSkillId: z.string().min(3).optional(), }), ) diff --git a/apps/web/src/trpc/routers/instance-skills.ts b/apps/web/src/trpc/routers/instance-skills.ts index 017146848..40d2d6ff1 100644 --- a/apps/web/src/trpc/routers/instance-skills.ts +++ b/apps/web/src/trpc/routers/instance-skills.ts @@ -12,7 +12,7 @@ import { updateInstanceSkillCommand, } from '../commands/instance-skills'; -const skillIdSchema = z.object({ skillId: z.string().uuid() }).strict(); +const skillIdSchema = z.object({ skillId: z.guid() }).strict(); export const instanceSkillsRouter = createRouter({ list: protectedProcedure.query(({ ctx: { auth } }) => @@ -31,7 +31,7 @@ export const instanceSkillsRouter = createRouter({ customSkillDefinitionSchema .extend({ expectedVersion: z.number().int().positive(), - skillId: z.string().uuid(), + skillId: z.guid(), }) .strict(), ) diff --git a/apps/web/src/trpc/routers/vulnerability-watch.ts b/apps/web/src/trpc/routers/vulnerability-watch.ts index 0b661f28a..3455e1771 100644 --- a/apps/web/src/trpc/routers/vulnerability-watch.ts +++ b/apps/web/src/trpc/routers/vulnerability-watch.ts @@ -45,7 +45,7 @@ export const vulnerabilityWatchRouter = createRouter({ z .object({ enabled: z.boolean(), - excludedRepositoryIds: z.array(z.string().uuid()).max(1000), + excludedRepositoryIds: z.array(z.guid()).max(1000), }) .strict(), ) diff --git a/apps/worker/package.json b/apps/worker/package.json index a1329e919..c1d6f396d 100644 --- a/apps/worker/package.json +++ b/apps/worker/package.json @@ -46,7 +46,7 @@ "superjson": "^2.2.6", "ws": "^8.20.1", "yaml": "^2.9.0", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-eslint": "workspace:^", diff --git a/apps/worker/src/mcp/roomote-mcp-server/__tests__/automation-work-items-tool-schema.test.ts b/apps/worker/src/mcp/roomote-mcp-server/__tests__/automation-work-items-tool-schema.test.ts index d638104a1..a8e4a1fee 100644 --- a/apps/worker/src/mcp/roomote-mcp-server/__tests__/automation-work-items-tool-schema.test.ts +++ b/apps/worker/src/mcp/roomote-mcp-server/__tests__/automation-work-items-tool-schema.test.ts @@ -34,14 +34,11 @@ describe('automationWorkItemInputSchema', () => { )) { let schema: z.ZodTypeAny = fieldSchema; - while ( - schema instanceof z.ZodOptional || - schema instanceof z.ZodEffects - ) { + while (schema instanceof z.ZodOptional || schema instanceof z.ZodPipe) { schema = schema instanceof z.ZodOptional - ? schema.unwrap() - : schema.innerType(); + ? (schema.unwrap() as z.ZodType) + : (schema.in as z.ZodType); } expect( diff --git a/apps/worker/src/mcp/roomote-mcp-server/__tests__/report-platform-issue.test.ts b/apps/worker/src/mcp/roomote-mcp-server/__tests__/report-platform-issue.test.ts index 81f17423e..0a3def728 100644 --- a/apps/worker/src/mcp/roomote-mcp-server/__tests__/report-platform-issue.test.ts +++ b/apps/worker/src/mcp/roomote-mcp-server/__tests__/report-platform-issue.test.ts @@ -34,6 +34,19 @@ describe('handleReportPlatformIssue', () => { const parsed = JSON.parse(text); expect(parsed.success).toBe(false); - expect(parsed.error).toContain('String must contain at least 1 character'); + expect(JSON.parse(parsed.error)).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + code: 'too_small', + minimum: 1, + path: ['title'], + }), + expect.objectContaining({ + code: 'too_small', + minimum: 1, + path: ['summary'], + }), + ]), + ); }); }); diff --git a/apps/worker/src/mcp/roomote-mcp-server/__tests__/tool-descriptions.test.ts b/apps/worker/src/mcp/roomote-mcp-server/__tests__/tool-descriptions.test.ts index 42b781991..fea06c5ea 100644 --- a/apps/worker/src/mcp/roomote-mcp-server/__tests__/tool-descriptions.test.ts +++ b/apps/worker/src/mcp/roomote-mcp-server/__tests__/tool-descriptions.test.ts @@ -136,10 +136,11 @@ function unwrapSchema(schema: z.ZodTypeAny): z.ZodTypeAny { while ( current instanceof z.ZodOptional || current instanceof z.ZodNullable || - current instanceof z.ZodEffects + current instanceof z.ZodPipe ) { - current = - current instanceof z.ZodEffects ? current.innerType() : current.unwrap(); + current = ( + current instanceof z.ZodPipe ? current.in : current.unwrap() + ) as z.ZodType; } return current; diff --git a/apps/worker/src/mcp/roomote-mcp-server/automation-work-items-tool.ts b/apps/worker/src/mcp/roomote-mcp-server/automation-work-items-tool.ts index 9949c624a..acfab52b8 100644 --- a/apps/worker/src/mcp/roomote-mcp-server/automation-work-items-tool.ts +++ b/apps/worker/src/mcp/roomote-mcp-server/automation-work-items-tool.ts @@ -21,7 +21,7 @@ const nonEmptyTrimmedStringSchema = z }); const uuidStringSchema = z .string() - .refine((value) => z.string().uuid().safeParse(value).success, { + .refine((value) => z.guid().safeParse(value).success, { message: 'Value must be a UUID.', }); diff --git a/apps/worker/src/mcp/roomote-mcp-server/index.ts b/apps/worker/src/mcp/roomote-mcp-server/index.ts index 762b97d13..4333b4a7b 100644 --- a/apps/worker/src/mcp/roomote-mcp-server/index.ts +++ b/apps/worker/src/mcp/roomote-mcp-server/index.ts @@ -178,7 +178,7 @@ const boundedNonEmptyStringSchema = (maximumLength: number) => }); const uuidStringSchema = z .string() - .refine((value) => z.string().uuid().safeParse(value).success, { + .refine((value) => z.guid().safeParse(value).success, { message: 'Value must be a UUID.', }); diff --git a/apps/worker/src/mcp/roomote-mcp-server/on-demand-integrations.ts b/apps/worker/src/mcp/roomote-mcp-server/on-demand-integrations.ts index a22c0c454..1fe60e8f6 100644 --- a/apps/worker/src/mcp/roomote-mcp-server/on-demand-integrations.ts +++ b/apps/worker/src/mcp/roomote-mcp-server/on-demand-integrations.ts @@ -33,7 +33,7 @@ const onDemandMcpServerSchema = z.object({ displayName: z.string().min(1), description: z.string().optional(), url: z.string().url(), - headers: z.record(z.string()).optional(), + headers: z.record(z.string(), z.string()).optional(), }); const onDemandMcpCatalogSchema = z.object({ diff --git a/apps/worker/src/sandbox-server/procedures/answerUserInputRequest.ts b/apps/worker/src/sandbox-server/procedures/answerUserInputRequest.ts index b00b15654..10a70fa0b 100644 --- a/apps/worker/src/sandbox-server/procedures/answerUserInputRequest.ts +++ b/apps/worker/src/sandbox-server/procedures/answerUserInputRequest.ts @@ -15,6 +15,7 @@ import { } from './slackQuoteTracking'; const requestUserInputAnswersSchema = z.record( + z.string(), z.object({ answers: z.array(z.string()), }), diff --git a/package.json b/package.json index 7f544da0d..87cac7691 100644 --- a/package.json +++ b/package.json @@ -122,9 +122,7 @@ "socket.io>socket.io-adapter": "2.5.8", "socket.io-adapter>ws": "8.21.0", "tar": "7.5.21", - "zod": "^3.25.76", - "astro>zod": "^4.3.6", - "knip>zod": "^4.1.11", + "zod": "4.6.7", "@streamdown/mermaid>mermaid": "11.16.1", "nanoid@<4": "5.1.16", "dagre-d3-es>lodash-es": "4.18.1", @@ -133,6 +131,7 @@ "preact": ">=10.26.10", "smol-toml": "1.9.0", "undici": "^7.30.1", + "@azure/msal-node": "7.1.0", "diff": ">=5.2.2", "flatted": "^3.4.2", "@protobufjs/utf8": "1.1.1", @@ -148,7 +147,7 @@ "brace-expansion@<1.1.21": "1.1.21", "brace-expansion@>=2.0.0 <2.1.7": "2.1.7", "brace-expansion@>=3.0.0 <5.0.12": "5.0.12", - "fast-uri": "3.1.8", + "fast-uri": "3.1.9", "ip-address": "10.7.4", "immutable": "5.1.8", "moment": "2.31.0", diff --git a/packages/ado/package.json b/packages/ado/package.json index 10b4b0323..a29f73afe 100644 --- a/packages/ado/package.json +++ b/packages/ado/package.json @@ -15,7 +15,7 @@ "dependencies": { "@roomote/db": "workspace:^", "@roomote/types": "workspace:^", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/ado/src/api.ts b/packages/ado/src/api.ts index b88cd037e..9fe34221c 100644 --- a/packages/ado/src/api.ts +++ b/packages/ado/src/api.ts @@ -138,8 +138,8 @@ const adoServiceHookSubscriptionSchema = z resourceVersion: z.string().optional(), consumerId: z.string().optional(), consumerActionId: z.string().optional(), - publisherInputs: z.record(z.string()).optional(), - consumerInputs: z.record(z.string()).optional(), + publisherInputs: z.record(z.string(), z.string()).optional(), + consumerInputs: z.record(z.string(), z.string()).optional(), }) .passthrough(); const adoServiceHookSubscriptionListResponseSchema = z.object({ diff --git a/packages/auth/package.json b/packages/auth/package.json index 3b746d75d..85b464292 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -41,7 +41,7 @@ "@roomote/env": "workspace:^", "@roomote/types": "workspace:^", "jsonwebtoken": "^9.0.3", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/auth/src/auth-token.ts b/packages/auth/src/auth-token.ts index 06bc14fa1..25f9a8e01 100644 --- a/packages/auth/src/auth-token.ts +++ b/packages/auth/src/auth-token.ts @@ -106,7 +106,7 @@ export async function validateAuthToken( const parseResult = authTokenPayloadSchema.safeParse(rawPayload); if (!parseResult.success) { - const validationErrors = parseResult.error.errors + const validationErrors = parseResult.error.issues .map((err) => `${err.path.join('.')}: ${err.message}`) .join(', '); diff --git a/packages/auth/src/preview-token.ts b/packages/auth/src/preview-token.ts index 945c283c5..a50e24c71 100644 --- a/packages/auth/src/preview-token.ts +++ b/packages/auth/src/preview-token.ts @@ -86,7 +86,7 @@ export async function validatePreviewToken( const parseResult = previewTokenPayloadSchema.safeParse(rawPayload); if (!parseResult.success) { - const validationErrors = parseResult.error.errors + const validationErrors = parseResult.error.issues .map((err) => `${err.path.join('.')}: ${err.message}`) .join(', '); diff --git a/packages/auth/src/run-token.ts b/packages/auth/src/run-token.ts index 2d3ed8d9b..abb03a184 100644 --- a/packages/auth/src/run-token.ts +++ b/packages/auth/src/run-token.ts @@ -102,7 +102,7 @@ export async function validateRunToken( const parseResult = compatibleRunTokenPayloadSchema.safeParse(rawPayload); if (!parseResult.success) { - const validationErrors = parseResult.error.errors + const validationErrors = parseResult.error.issues .map((err) => `${err.path.join('.')}: ${err.message}`) .join(', '); diff --git a/packages/auth/src/session-broker-token.ts b/packages/auth/src/session-broker-token.ts index d68cd9ce8..b26d9e4d4 100644 --- a/packages/auth/src/session-broker-token.ts +++ b/packages/auth/src/session-broker-token.ts @@ -11,7 +11,7 @@ const claims = z.object({ sub: z.string().min(1), aud: z.literal('roomote-session-broker'), exp: z.number().int(), - r: z.object({ t: z.literal('session-broker'), c: z.string().uuid() }), + r: z.object({ t: z.literal('session-broker'), c: z.guid() }), }); export interface SessionBrokerContext { diff --git a/packages/bitbucket/package.json b/packages/bitbucket/package.json index 2c0952e19..1109573ea 100644 --- a/packages/bitbucket/package.json +++ b/packages/bitbucket/package.json @@ -19,7 +19,7 @@ "@roomote/db": "workspace:^", "@roomote/source-control-oauth": "workspace:^", "@roomote/types": "workspace:^", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/cloud-agents/package.json b/packages/cloud-agents/package.json index 2a04569fc..703bac16c 100644 --- a/packages/cloud-agents/package.json +++ b/packages/cloud-agents/package.json @@ -123,8 +123,7 @@ "mammoth": "^1.11.0", "pdfjs-dist": "^6.2.108", "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz", - "zod": "^3.25.76", - "zod-to-json-schema": "3.25.1" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/cloud-agents/src/server/__tests__/slack-question-channel-suggestions.test.ts b/packages/cloud-agents/src/server/__tests__/slack-question-channel-suggestions.test.ts index 0999fa617..3e8f40aae 100644 --- a/packages/cloud-agents/src/server/__tests__/slack-question-channel-suggestions.test.ts +++ b/packages/cloud-agents/src/server/__tests__/slack-question-channel-suggestions.test.ts @@ -1,4 +1,4 @@ -import zodToJsonSchema from 'zod-to-json-schema'; +import { z } from 'zod'; const { mockGenerateTrackedNonTaskObject } = vi.hoisted(() => ({ mockGenerateTrackedNonTaskObject: vi.fn(), @@ -107,9 +107,10 @@ describe('suggestSlackQuestionChannels', () => { false, ); - const wireSchema = zodToJsonSchema(schema, { - $refStrategy: 'none', - target: 'jsonSchema7', + const wireSchema = z.toJSONSchema(schema, { + reused: 'inline', + target: 'draft-7', + io: 'input', }); expect(JSON.stringify(wireSchema)).not.toMatch( /"(?:minItems|maxItems|minLength|maxLength|minimum|maximum|exclusiveMinimum|exclusiveMaximum)"/, diff --git a/packages/cloud-agents/src/server/fast-agent/__tests__/fast-agent-native-tool-schemas.test.ts b/packages/cloud-agents/src/server/fast-agent/__tests__/fast-agent-native-tool-schemas.test.ts index d7f648cbd..04b94ce77 100644 --- a/packages/cloud-agents/src/server/fast-agent/__tests__/fast-agent-native-tool-schemas.test.ts +++ b/packages/cloud-agents/src/server/fast-agent/__tests__/fast-agent-native-tool-schemas.test.ts @@ -221,7 +221,7 @@ function toOpenCodeJsonSchema(zod: ZodV4, args: unknown) { describe('Fast native tool schemas as OpenAI receives them', () => { const validator = new Ajv2020({ strict: false }).addFormat( 'uuid', - (value: string) => z.string().uuid().safeParse(value).success, + (value: string) => z.guid().safeParse(value).success, ); let workDir: string; let zod: ZodV4; diff --git a/packages/cloud-agents/src/server/fast-agent/fast-agent-native-tool-bridge.ts b/packages/cloud-agents/src/server/fast-agent/fast-agent-native-tool-bridge.ts index 47da3d58d..8018bf844 100644 --- a/packages/cloud-agents/src/server/fast-agent/fast-agent-native-tool-bridge.ts +++ b/packages/cloud-agents/src/server/fast-agent/fast-agent-native-tool-bridge.ts @@ -264,7 +264,7 @@ const bridgeRequestSchema = z.object({ ...FastAgentNativeToolName[], ], ), - args: z.record(z.unknown()), + args: z.record(z.string(), z.unknown()), agent: z.string().min(1).optional(), }); @@ -690,7 +690,7 @@ export default { description: "Add or reconnect one remote MCP integration from its HTTPS streamable-HTTP endpoint. Any member may call this. Use it for a service's official hosted remote MCP endpoint or a URL the human supplied; never invent a URL, and a local stdio project is not a hosted MCP. It is shared with everyone in the deployment by default, like an integration key; pass visibility 'owner' only when the human asked to keep it private to them, and say which it is when you report it. The server verifies the endpoint before saving it, reuses an existing matching integration, and returns either connected tools, a secure OAuth authorization link, or a settingsUrl for static headers/manual OAuth client setup: the Integrations page for a shared server, or Personal settings for a private one. Roomote registers this deployment with the provider before returning an authorization link, so a returned link can succeed. A client-registration-required or needs-static-headers result means this human cannot connect it now: relay the result's reason (the provider's own words) when present, share settingsUrl as the alternative, and continue with the integration-key route. A pending-owner result means a shared server someone else added is still waiting on them or an administrator: say so, share no link, and continue with the integration-key route or a private server of their own if they ask. Server-backed results include integrationId, the actual Fast catalog ID: use that exact integrationId with find_integration_tools and call_integration_tool, never a server UUID, but do not narrate IDs or catalog checks to the human. Share authorizeUrl and settingsUrl exactly unchanged, labeled 'Authorize ' and 'Integration settings' respectively; never rewrite either target. The conversation resumes automatically after the human authorizes, so never ask them to send a follow-up. In user-visible progress say at most that you are checking. Never ask for or accept secrets in chat or tool arguments.", args: { name: z.string().trim().min(1).max(80).describe("Short integration name; Roomote normalizes it to a lowercase slug"), - url: z.string().url().startsWith("https://").max(2048).describe("HTTPS streamable-HTTP MCP endpoint"), + url: z.string().regex(/^https:\/\/.*/).url().max(2048).describe("HTTPS streamable-HTTP MCP endpoint"), visibility: z.enum(["owner", "deployment"]).optional().describe("deployment (default) shares it with everyone; owner keeps it private to the requesting human"), }, execute: (args, context) => invoke("add_remote_mcp", args, context), diff --git a/packages/cloud-agents/src/server/fast-agent/fast-agent-service.ts b/packages/cloud-agents/src/server/fast-agent/fast-agent-service.ts index 364ef0702..3ef2044e6 100644 --- a/packages/cloud-agents/src/server/fast-agent/fast-agent-service.ts +++ b/packages/cloud-agents/src/server/fast-agent/fast-agent-service.ts @@ -1961,7 +1961,11 @@ function isSuccessfulChatReactionResult( const addRemoteMcpArgsSchema = z .object({ name: z.string().trim().min(1).max(80), - url: z.string().url().startsWith('https://').max(2_048), + url: z + .string() + .regex(/^https:\/\/.*/) + .url() + .max(2_048), visibility: customMcpServerVisibilitySchema.optional(), }) .strict(); diff --git a/packages/cloud-agents/src/server/mcp-nullable-optionals.test.ts b/packages/cloud-agents/src/server/mcp-nullable-optionals.test.ts index f2006d5b3..978bb2468 100644 --- a/packages/cloud-agents/src/server/mcp-nullable-optionals.test.ts +++ b/packages/cloud-agents/src/server/mcp-nullable-optionals.test.ts @@ -137,6 +137,59 @@ describe('withNullableOptionals', () => { it('passes through undefined unchanged', () => { expect(withNullableOptionals(undefined)).toBeUndefined(); }); + + it('preserves object and array checks and descriptions while adapting nested fields', () => { + const original = z + .object({ + entries: z + .array(z.object({ name: z.string().optional() })) + .max(2) + .describe('bounded entries'), + }) + .refine((value) => value.entries.length > 0, 'At least one entry') + .describe('checked object'); + const adapted = withNullableOptionals(original); + expect(adapted.description).toBe('checked object'); + expect(adapted.shape.entries.description).toBe('bounded entries'); + expect(adapted.parse({ entries: [{ name: null }] })).toEqual({ + entries: [{ name: undefined }], + }); + expect(adapted.safeParse({ entries: [] }).success).toBe(false); + expect(adapted.safeParse({ entries: [{}, {}, {}] }).success).toBe(false); + }); + + it('adapts nested discriminated unions and transformed objects', () => { + const original = z + .discriminatedUnion('kind', [ + z.object({ kind: z.literal('text'), note: z.string().optional() }), + z.object({ + kind: z.literal('count'), + count: z.number().int().optional(), + }), + ]) + .transform((value) => ({ ...value, parsed: true })); + const adapted = withNullableOptionals(original); + expect(adapted.parse({ kind: 'text', note: null })).toEqual({ + kind: 'text', + note: undefined, + parsed: true, + }); + expect(adapted.parse({ kind: 'count', count: '2' })).toEqual({ + kind: 'count', + count: 2, + parsed: true, + }); + expect(adapted.safeParse({ kind: 'other' }).success).toBe(false); + }); + + it('evaluates a default factory for each null input', () => { + let next = 0; + const adapted = withNullableOptionals( + z.object({ value: z.number().default(() => ++next) }), + ); + expect(adapted.parse({ value: null }).value).toBe(1); + expect(adapted.parse({ value: null }).value).toBe(2); + }); }); describe('NullableOptionalsMcpServer', () => { @@ -255,7 +308,7 @@ describe('NullableOptionalsMcpServer', () => { >; expect(properties.prNumber).toMatchObject({ type: 'integer' }); expect(properties.resolved).toMatchObject({ - anyOf: [{ type: 'boolean' }, { type: 'null' }], + type: ['boolean', 'null'], }); await client.callTool({ diff --git a/packages/cloud-agents/src/server/mcp-nullable-optionals.ts b/packages/cloud-agents/src/server/mcp-nullable-optionals.ts index 56e34d900..6630fd4d8 100644 --- a/packages/cloud-agents/src/server/mcp-nullable-optionals.ts +++ b/packages/cloud-agents/src/server/mcp-nullable-optionals.ts @@ -83,7 +83,7 @@ function deserializeTransportPrimitive(schema: ZodTypeAny): ZodTypeAny { function allowNullDeep(schema: ZodTypeAny): ZodTypeAny { if (schema instanceof z.ZodOptional) { - const inner = allowNullDeep(schema.unwrap()); + const inner = allowNullDeep(schema.unwrap() as ZodTypeAny); const nullable = inner instanceof z.ZodNullable ? inner @@ -91,50 +91,66 @@ function allowNullDeep(schema: ZodTypeAny): ZodTypeAny { return keepDescription(nullable.optional(), schema.description); } if (schema instanceof z.ZodDefault) { - const defaultValue = schema._def.defaultValue; - const inner = allowNullDeep(schema.removeDefault()) + const defaultValue = () => schema.def.defaultValue; + const inner = allowNullDeep(schema.removeDefault() as ZodTypeAny) .nullable() .transform((value) => value ?? defaultValue()); return keepDescription(inner.default(defaultValue), schema.description); } if (schema instanceof z.ZodNullable) { - return new z.ZodNullable({ - ...schema._def, - innerType: allowNullDeep(schema.unwrap()), - }); + return keepDescription( + new z.ZodNullable({ + ...schema.def, + innerType: allowNullDeep(schema.unwrap() as ZodTypeAny), + }), + schema.description, + ); } - if (schema instanceof z.ZodEffects) { - return new z.ZodEffects({ - ...schema._def, - schema: allowNullDeep(schema.innerType()), - }); + if (schema instanceof z.ZodPipe) { + return keepDescription( + new z.ZodPipe({ + ...schema.def, + in: allowNullDeep(schema.in as ZodTypeAny), + out: allowNullDeep(schema.out as ZodTypeAny), + }), + schema.description, + ); } if (schema instanceof z.ZodObject) { const shape = withNullableOptionals(schema.shape as z.ZodRawShape); - return new z.ZodObject({ ...schema._def, shape: () => shape }); + return keepDescription( + new z.ZodObject({ ...schema.def, shape }), + schema.description, + ); } if (schema instanceof z.ZodArray) { - return new z.ZodArray({ - ...schema._def, - type: allowNullDeep(schema.element), - }); - } - if (schema instanceof z.ZodUnion) { - const options = (schema.options as ZodTypeAny[]).map(allowNullDeep); - return new z.ZodUnion({ - ...schema._def, - options: options as [ZodTypeAny, ZodTypeAny, ...ZodTypeAny[]], - }); + return keepDescription( + new z.ZodArray({ + ...schema.def, + element: allowNullDeep(schema.element as ZodTypeAny), + }), + schema.description, + ); } if (schema instanceof z.ZodDiscriminatedUnion) { - const options = (schema.options as z.AnyZodObject[]).map( - (option) => allowNullDeep(option) as z.AnyZodObject, + return keepDescription( + new z.ZodDiscriminatedUnion({ + ...schema.def, + discriminator: schema.def.discriminator, + options: schema.options.map((option) => + allowNullDeep(option as ZodTypeAny), + ), + }), + schema.description, ); + } + if (schema instanceof z.ZodUnion) { + const options = (schema.options as ZodTypeAny[]).map(allowNullDeep); return keepDescription( - z.discriminatedUnion( - schema.discriminator, - options as [z.AnyZodObject, z.AnyZodObject, ...z.AnyZodObject[]], - ), + new z.ZodUnion({ + ...schema.def, + options: options as [ZodTypeAny, ZodTypeAny, ...ZodTypeAny[]], + }), schema.description, ); } diff --git a/packages/cloud-agents/src/server/non-task-provider-usage.ts b/packages/cloud-agents/src/server/non-task-provider-usage.ts index 2fb40a722..74cd7848a 100644 --- a/packages/cloud-agents/src/server/non-task-provider-usage.ts +++ b/packages/cloud-agents/src/server/non-task-provider-usage.ts @@ -32,8 +32,7 @@ import { TASK_MODEL_ROLE_DESCRIPTORS, } from '@roomote/types'; import { captureInstanceEvent } from '@roomote/telemetry/server'; -import type { z } from 'zod'; -import zodToJsonSchema from 'zod-to-json-schema'; +import { z } from 'zod'; import { decodeInferenceErrorEnvelope } from './inference-error-envelope'; import { streamOpenCodeEventsAcrossDisposal } from './opencode-event-stream'; @@ -2730,9 +2729,10 @@ async function generateTrackedNonTaskObjectWithSdk< export function buildNonTaskStructuredOutputJsonSchema( schema: z.ZodTypeAny, ): Record { - return zodToJsonSchema(schema, { - $refStrategy: 'none', - target: 'jsonSchema7', + return z.toJSONSchema(schema, { + reused: 'inline', + target: 'draft-7', + io: 'input', }) as Record; } diff --git a/packages/cloud-agents/src/server/task-run-queue.ts b/packages/cloud-agents/src/server/task-run-queue.ts index b8b1ac56e..10c51e495 100644 --- a/packages/cloud-agents/src/server/task-run-queue.ts +++ b/packages/cloud-agents/src/server/task-run-queue.ts @@ -2791,7 +2791,7 @@ function inheritSnapshotResumeSourceControlStamps( if (usesSourceProvider && payload.repositoryProviders === undefined) { const repositoryProviders = z - .record(sourceControlProviderSchema) + .record(z.string(), sourceControlProviderSchema) .safeParse(source.repositoryProviders); if (repositoryProviders.success) { @@ -2838,7 +2838,7 @@ function inheritSnapshotResumeFastAgentSession( ): void { const fastAgentSessionId = z .string() - .uuid() + .check(z.guid()) .safeParse( sourcePayload && typeof sourcePayload === 'object' ? (sourcePayload as Record).fastAgentSessionId diff --git a/packages/communication/package.json b/packages/communication/package.json index 777cb30de..00e018c21 100644 --- a/packages/communication/package.json +++ b/packages/communication/package.json @@ -50,7 +50,7 @@ "@roomote/env": "workspace:^", "@roomote/redis": "workspace:^", "@roomote/types": "workspace:^", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/communication/scripts/run-mock-discord.ts b/packages/communication/scripts/run-mock-discord.ts index 40629d162..dcbf2ff55 100644 --- a/packages/communication/scripts/run-mock-discord.ts +++ b/packages/communication/scripts/run-mock-discord.ts @@ -52,7 +52,7 @@ const configSchema = z.object({ .array( z.object({ kind: z.enum(['message', 'interaction']), - payload: z.record(z.unknown()), + payload: z.record(z.string(), z.unknown()), eventId: z.string().min(1).optional(), }), ) diff --git a/packages/communication/scripts/run-mock-telegram.ts b/packages/communication/scripts/run-mock-telegram.ts index 4f5eaee05..7af57feba 100644 --- a/packages/communication/scripts/run-mock-telegram.ts +++ b/packages/communication/scripts/run-mock-telegram.ts @@ -25,7 +25,7 @@ const inboundMessageSchema = z message_id: z.number().int().optional(), message_thread_id: z.number().int().optional(), date: z.number().int().optional(), - entities: z.array(z.record(z.unknown())).optional(), + entities: z.array(z.record(z.string(), z.unknown())).optional(), }) .passthrough(); @@ -70,7 +70,7 @@ const configSchema = z.object({ }) .passthrough(), ), - messages: z.array(z.record(z.unknown())).optional(), + messages: z.array(z.record(z.string(), z.unknown())).optional(), behavior: z .object({ rejectHtmlParseMode: z.boolean().optional(), @@ -99,13 +99,13 @@ const configSchema = z.object({ id: z.string().min(1), from: z.object({ id: z.number() }).passthrough(), data: z.string().optional(), - message: z.record(z.unknown()).optional(), + message: z.record(z.string(), z.unknown()).optional(), }) .passthrough(), }), z.object({ kind: z.literal('update'), - update: z.record(z.unknown()), + update: z.record(z.string(), z.unknown()), }), ]), ) diff --git a/packages/communication/src/mock-agentmail-config.ts b/packages/communication/src/mock-agentmail-config.ts index 0d595035a..fdc27632a 100644 --- a/packages/communication/src/mock-agentmail-config.ts +++ b/packages/communication/src/mock-agentmail-config.ts @@ -85,7 +85,7 @@ const configSchema = z.object({ .passthrough(), ) .optional(), - messages: z.array(z.record(z.unknown())).optional(), + messages: z.array(z.record(z.string(), z.unknown())).optional(), // Seeded events make `kind: "redeliver"` usable from a scenario file: // the redelivery reuses the stored svix id and resends the payload. events: z @@ -98,7 +98,7 @@ const configSchema = z.object({ inbox_id: z.string().min(1), message_id: z.string().min(1), payload: z.string().min(1), - deliveries: z.array(z.record(z.unknown())).optional(), + deliveries: z.array(z.record(z.string(), z.unknown())).optional(), }) .passthrough(), ) diff --git a/packages/db/package.json b/packages/db/package.json index 5fbe286da..9cc2c1aa0 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -60,6 +60,6 @@ "drizzle-kit": "^0.31.9", "fishery": "^2.4.0", "vitest": "^4.1.1", - "zod": "^3.25.76" + "zod": "^4.6.6" } } diff --git a/packages/db/src/lib/custom-skills.ts b/packages/db/src/lib/custom-skills.ts index 75ef5ce82..0015b5d0d 100644 --- a/packages/db/src/lib/custom-skills.ts +++ b/packages/db/src/lib/custom-skills.ts @@ -34,7 +34,7 @@ async function requireMember(tx: Transaction, actorUserId: string) { } async function readSkill(tx: Transaction, skillId: string) { - if (!z.string().uuid().safeParse(skillId).success) + if (!z.guid().safeParse(skillId).success) throw new CreateCustomSkillError('Skill not found', 404); const [skill] = await tx .select() diff --git a/packages/env/package.json b/packages/env/package.json index 09cc85e75..74fce3a2b 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -16,7 +16,7 @@ "dependencies": { "@roomote/types": "workspace:^", "@t3-oss/env-nextjs": "^0.13.10", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/gitea/package.json b/packages/gitea/package.json index 531bba0b6..8d503a106 100644 --- a/packages/gitea/package.json +++ b/packages/gitea/package.json @@ -16,7 +16,7 @@ "@roomote/db": "workspace:^", "@roomote/source-control-oauth": "workspace:^", "@roomote/types": "workspace:^", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/gitea/src/api.ts b/packages/gitea/src/api.ts index ded2dc036..e5a64b151 100644 --- a/packages/gitea/src/api.ts +++ b/packages/gitea/src/api.ts @@ -60,7 +60,7 @@ const giteaHookSchema = z .object({ id: z.number(), type: z.string().optional(), - config: z.record(z.string()).optional(), + config: z.record(z.string(), z.string()).optional(), }) .passthrough(); const giteaHookListSchema = z.array(giteaHookSchema); diff --git a/packages/github/package.json b/packages/github/package.json index ec81421fc..7c5ff8ac7 100644 --- a/packages/github/package.json +++ b/packages/github/package.json @@ -21,7 +21,7 @@ "execa": "9.6.1", "jsonwebtoken": "^9.0.3", "p-map": "^7.0.4", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/gitlab/package.json b/packages/gitlab/package.json index 06986697c..c66a01eba 100644 --- a/packages/gitlab/package.json +++ b/packages/gitlab/package.json @@ -16,7 +16,7 @@ "@roomote/db": "workspace:^", "@roomote/source-control-oauth": "workspace:^", "@roomote/types": "workspace:^", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/linear/package.json b/packages/linear/package.json index 08ad7a437..29c235f78 100644 --- a/packages/linear/package.json +++ b/packages/linear/package.json @@ -22,7 +22,7 @@ "@roomote/redis": "workspace:^", "@roomote/telemetry": "workspace:^", "@roomote/types": "workspace:^", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/linear/src/types.ts b/packages/linear/src/types.ts index e241d469f..66c7d51d3 100644 --- a/packages/linear/src/types.ts +++ b/packages/linear/src/types.ts @@ -153,7 +153,7 @@ const webhookAgentActivitySchema = z.object({ userId: z.string().optional(), content: webhookAgentActivityContentSchema, signal: humanToAgentSignalSchema.nullish(), - signalMetadata: z.record(z.unknown()).nullish(), + signalMetadata: z.record(z.string(), z.unknown()).nullish(), ephemeral: z.boolean().optional(), }); diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 3c9e1ded1..8d57e8366 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -151,7 +151,7 @@ "undici": "^7.30.1", "unzipper": "^0.12.5", "yaml": "^2.9.0", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/sdk/src/server/automations/vulnerability-watch/matching.ts b/packages/sdk/src/server/automations/vulnerability-watch/matching.ts index 41a05b4a2..49171d715 100644 --- a/packages/sdk/src/server/automations/vulnerability-watch/matching.ts +++ b/packages/sdk/src/server/automations/vulnerability-watch/matching.ts @@ -119,7 +119,7 @@ export function matchCve( if (m.other?.type === 'kev') return true; if (m.other?.type !== 'ssvc') return false; const ssvc = z - .object({ options: z.array(z.record(z.unknown())) }) + .object({ options: z.array(z.record(z.string(), z.unknown())) }) .safeParse(m.other.content); return ( ssvc.success && diff --git a/packages/sdk/src/server/lib/automation-recommendations.ts b/packages/sdk/src/server/lib/automation-recommendations.ts index 43039e925..66e79f7ee 100644 --- a/packages/sdk/src/server/lib/automation-recommendations.ts +++ b/packages/sdk/src/server/lib/automation-recommendations.ts @@ -86,14 +86,14 @@ type GitHubOctokitCache = Map>; export const automationRecommendationJobSchema = z.object({ fingerprint: z.string().min(1), - repositoryIds: z.array(z.string().uuid()), + repositoryIds: z.array(z.guid()), }); export type AutomationRecommendationJob = z.infer< typeof automationRecommendationJobSchema >; export const automationSignalPrefetchJobSchema = z.object({ - repositoryId: z.string().uuid(), + repositoryId: z.guid(), signalsVersion: z.number().int().positive(), }); export type AutomationSignalPrefetchJob = z.infer< diff --git a/packages/sdk/src/server/lib/credential-egress.ts b/packages/sdk/src/server/lib/credential-egress.ts index 66a5e884a..4ee97bcf9 100644 --- a/packages/sdk/src/server/lib/credential-egress.ts +++ b/packages/sdk/src/server/lib/credential-egress.ts @@ -77,16 +77,13 @@ export class CredentialEgressRequestError extends Error { } } -function parse( - schema: z.ZodType, - input: unknown, -): T { +function parse(schema: z.ZodType, input: unknown): T { const parsed = schema.safeParse(input); if (!parsed.success) throw new CredentialEgressRequestError(400, 'malformed'); return parsed.data; } -const workloadIdSchema = z.string().uuid(); +const workloadIdSchema = z.guid(); export async function registerWorkload( input: unknown, diff --git a/packages/sdk/src/server/lib/task-runs/pr-review-notification.ts b/packages/sdk/src/server/lib/task-runs/pr-review-notification.ts index ac93aed46..9426193b2 100644 --- a/packages/sdk/src/server/lib/task-runs/pr-review-notification.ts +++ b/packages/sdk/src/server/lib/task-runs/pr-review-notification.ts @@ -173,13 +173,13 @@ export const prReviewNotificationRequestSchema = z.object({ batchId: z.string().optional(), sourceControlProvider: sourceControlProviderSchema.optional(), host: z.string().nullable().optional(), - repositoryId: z.string().uuid().nullable().optional(), + repositoryId: z.guid().nullable().optional(), deliveryIds: z.array(z.string()).optional(), leaseToken: z.string().optional(), events: z.array(prReviewActivityEventSchema).optional(), ownershipVersion: z.enum(['legacy', 'canonical']).optional(), - deliveryId: z.string().uuid().optional(), - notificationUnitId: z.string().uuid().optional(), + deliveryId: z.guid().optional(), + notificationUnitId: z.guid().optional(), destinationKey: z.string().optional(), deliveryState: z .enum([ diff --git a/packages/sdk/src/server/lib/task-runs/pull-request-mergeability-check.ts b/packages/sdk/src/server/lib/task-runs/pull-request-mergeability-check.ts index 86bb4ab6b..ce702d1a9 100644 --- a/packages/sdk/src/server/lib/task-runs/pull-request-mergeability-check.ts +++ b/packages/sdk/src/server/lib/task-runs/pull-request-mergeability-check.ts @@ -23,7 +23,7 @@ export const pullRequestMergeabilityCheckRequestSchema = z // still picked up. baseRef: z.string().min(1).optional(), prNumber: z.number().int().positive().optional(), - taskPullRequestIds: z.array(z.string().uuid()).min(1).optional(), + taskPullRequestIds: z.array(z.guid()).min(1).optional(), deduplicationKey: z.string().min(1), retryAttempt: z.union([z.literal(0), z.literal(1)]), allowNotifiedConflictCheck: z.boolean().default(false), diff --git a/packages/sdk/src/server/routers/linear-sessions.ts b/packages/sdk/src/server/routers/linear-sessions.ts index 392ad5840..1ea11bb65 100644 --- a/packages/sdk/src/server/routers/linear-sessions.ts +++ b/packages/sdk/src/server/routers/linear-sessions.ts @@ -126,7 +126,7 @@ export const linearSessionsRouter = router({ sessionId: z.string(), content: z.string(), signal: z.enum(['select']).optional(), - signalMetadata: z.record(z.unknown()).optional(), + signalMetadata: z.record(z.string(), z.unknown()).optional(), }), ) .mutation(async ({ input }) => { diff --git a/packages/sdk/src/server/routers/llm-usage.ts b/packages/sdk/src/server/routers/llm-usage.ts index 9b069e27d..eb2b26f74 100644 --- a/packages/sdk/src/server/routers/llm-usage.ts +++ b/packages/sdk/src/server/routers/llm-usage.ts @@ -19,7 +19,7 @@ export const llmUsageRouter = router({ eventKey: z.string().min(1).nullable().optional(), taskId: z.string().nullable().optional(), runId: z.number().int().nullable().optional(), - environmentId: z.string().uuid().nullable().optional(), + environmentId: z.guid().nullable().optional(), harnessSessionId: z.string().nullable().optional(), messageId: z.string().nullable().optional(), providerId: z.string().nullable().optional(), @@ -36,8 +36,11 @@ export const llmUsageRouter = router({ costSource: z.enum(LLM_USAGE_COST_SOURCES).nullable().optional(), messageCreatedAt: z.date().nullable().optional(), messageCompletedAt: z.date().nullable().optional(), - pricingMetadata: z.record(z.unknown()).nullable().optional(), - details: z.record(z.unknown()).nullable().optional(), + pricingMetadata: z + .record(z.string(), z.unknown()) + .nullable() + .optional(), + details: z.record(z.string(), z.unknown()).nullable().optional(), }), ) .mutation(async ({ ctx, input }) => { diff --git a/packages/sdk/src/server/routers/mcp-connections.ts b/packages/sdk/src/server/routers/mcp-connections.ts index c746f2ad7..b84c5af19 100644 --- a/packages/sdk/src/server/routers/mcp-connections.ts +++ b/packages/sdk/src/server/routers/mcp-connections.ts @@ -271,7 +271,7 @@ export const mcpConnectionsRouter = router({ hasValidTokens: userOnlyProcedure .input( z.object({ - id: z.string().uuid(), + id: z.guid(), }), ) .query(async ({ ctx, input }) => { @@ -353,7 +353,7 @@ export const mcpConnectionsRouter = router({ * not be able to read directly. */ markCredentialEgressBootstrapReady: authenticatedProcedure - .input(z.object({ nonce: z.string().uuid() }).strict()) + .input(z.object({ nonce: z.guid() }).strict()) .mutation(async ({ ctx, input }) => { try { await markCredentialEgressBootstrapReady(ctx.auth, input.nonce); @@ -367,7 +367,7 @@ export const mcpConnectionsRouter = router({ }), getCredentialEgressDelivery: authenticatedProcedure - .input(z.object({ nonce: z.string().uuid() }).strict()) + .input(z.object({ nonce: z.guid() }).strict()) .query(async ({ ctx, input }) => { try { return { diff --git a/packages/sdk/src/server/routers/task-runs.ts b/packages/sdk/src/server/routers/task-runs.ts index 388395480..dde4915b8 100644 --- a/packages/sdk/src/server/routers/task-runs.ts +++ b/packages/sdk/src/server/routers/task-runs.ts @@ -170,6 +170,7 @@ const acpRequestUserInputQuestionSchema = z.object({ }); const acpRequestUserInputAnswersSchema = z.record( + z.string(), z.object({ answers: z.array(z.string()), }), @@ -252,7 +253,7 @@ function runTokenOnlyScoped( const targetId = typeof extractRunId === 'function' - ? extractRunId(input) + ? extractRunId(input as z.output) : (input as Record)[extractRunId as string]; if (targetId !== ctx.auth.runId) { @@ -317,7 +318,7 @@ export const taskRunsRouter = router({ // apps/api sendMessageToTask and the webhook queue sites), which write // task_runs directly. Both fields sent by a run-token caller are // stripped by this schema. - result: z.record(z.unknown()).optional(), + result: z.record(z.string(), z.unknown()).optional(), }), 'id', ).mutation(({ input: { id, ...values } }) => updateTaskRun(id, values)), @@ -412,7 +413,7 @@ export const taskRunsRouter = router({ source: z.enum(runEventSources), eventType: z.enum(runEventTypes), message: z.string().optional(), - details: z.record(z.unknown()).optional(), + details: z.record(z.string(), z.unknown()).optional(), }), 'runId', ).mutation(({ input }) => recordTaskRunEvent(input)), @@ -540,7 +541,7 @@ export const taskRunsRouter = router({ costSource: z.enum(LLM_USAGE_COST_SOURCES).nullable().optional(), messageCreatedAt: z.date().nullable().optional(), messageCompletedAt: z.date().nullable().optional(), - details: z.record(z.unknown()).nullable().optional(), + details: z.record(z.string(), z.unknown()).nullable().optional(), }), 'runId', ).mutation(({ input }) => recordTaskInferenceUsage(input)), @@ -604,7 +605,7 @@ export const taskRunsRouter = router({ .nonnegative() .nullable() .optional(), - details: z.record(z.unknown()).nullable().optional(), + details: z.record(z.string(), z.unknown()).nullable().optional(), }), 'runId', ).mutation(({ input }) => recordComputeProviderUsage(input)), diff --git a/packages/sdk/src/server/routers/tool-approvals.ts b/packages/sdk/src/server/routers/tool-approvals.ts index da1dadb24..73911b1e7 100644 --- a/packages/sdk/src/server/routers/tool-approvals.ts +++ b/packages/sdk/src/server/routers/tool-approvals.ts @@ -63,7 +63,7 @@ export const toolApprovalsRouter = router({ integrationId: z.string().min(1).max(200), toolName: z.string().min(1).max(200), nativeRequestId: z.string().min(1).max(200), - args: z.unknown(), + args: z.unknown().optional(), userRequest: z .string() .max(INTEGRATION_TOOL_USER_REQUEST_MAX_CHARS) @@ -83,7 +83,7 @@ export const toolApprovalsRouter = router({ /** Poll one of this task's approvals while the Session owner decides. */ status: taskRunProcedure - .input(z.object({ approvalId: z.string().uuid() }).strict()) + .input(z.object({ approvalId: z.guid() }).strict()) .query(async ({ ctx, input }) => ({ status: await getTaskToolApprovalStatus({ runId: ctx.runId, diff --git a/packages/sdk/src/server/trpc.ts b/packages/sdk/src/server/trpc.ts index d7b9e3bb3..f8c18d3f8 100644 --- a/packages/sdk/src/server/trpc.ts +++ b/packages/sdk/src/server/trpc.ts @@ -87,7 +87,7 @@ export function runScoped( .use(async ({ ctx, input, next }) => { const targetId = ( typeof extractRunId === 'function' - ? extractRunId(input) + ? extractRunId(input as z.output) : (input as Record)[extractRunId as string] ) as number; diff --git a/packages/slack/package.json b/packages/slack/package.json index 1789320c0..af5202119 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -26,7 +26,7 @@ "@roomote/redis": "workspace:^", "@roomote/types": "workspace:^", "@slack/web-api": "^7.19.0", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/types/package.json b/packages/types/package.json index 31b395433..5e6112ab6 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "yaml": "^2.9.0", - "zod": "^3.25.76" + "zod": "^4.6.6" }, "devDependencies": { "@roomote/config-typescript": "workspace:^", diff --git a/packages/types/src/auth.ts b/packages/types/src/auth.ts index 5dca242ce..03bbc37d3 100644 --- a/packages/types/src/auth.ts +++ b/packages/types/src/auth.ts @@ -10,13 +10,13 @@ export const runTokenPayloadSchema = z.object({ exp: z.number().int().positive('Expiration (exp) must be a positive integer'), iat: z.number().int().positive('Issued at (iat) must be a positive integer'), nbf: z.number().int().positive('Not before (nbf) must be a positive integer'), - v: z.literal(1, { errorMap: () => ({ message: 'Version must be 1' }) }), + v: z.literal(1, { error: () => ({ message: 'Version must be 1' }) }), r: z.object({ // Absent user claim means the run runs as the deployment service // principal (automation-initiated work with no human driver). u: z.string().min(1, 'User ID must be non-empty when present').optional(), t: z.literal('run', { - errorMap: () => ({ message: 'Token type must be "run"' }), + error: () => ({ message: 'Token type must be "run"' }), }), }), }); @@ -51,11 +51,11 @@ export const authTokenPayloadSchema = z.object({ exp: z.number().int().positive('Expiration (exp) must be a positive integer'), iat: z.number().int().positive('Issued at (iat) must be a positive integer'), nbf: z.number().int().positive('Not before (nbf) must be a positive integer'), - v: z.literal(1, { errorMap: () => ({ message: 'Version must be 1' }) }), + v: z.literal(1, { error: () => ({ message: 'Version must be 1' }) }), r: z.object({ u: z.string().min(1, 'User ID is required'), t: z.literal('auth', { - errorMap: () => ({ message: 'Token type must be "auth"' }), + error: () => ({ message: 'Token type must be "auth"' }), }), }), }); @@ -91,11 +91,11 @@ export const mcpAccessTokenPayloadSchema = z.object({ exp: z.number().int().positive('Expiration (exp) must be a positive integer'), iat: z.number().int().positive('Issued at (iat) must be a positive integer'), nbf: z.number().int().positive('Not before (nbf) must be a positive integer'), - v: z.literal(1, { errorMap: () => ({ message: 'Version must be 1' }) }), + v: z.literal(1, { error: () => ({ message: 'Version must be 1' }) }), r: z.object({ u: z.string().min(1, 'User ID is required'), t: z.literal('mcp', { - errorMap: () => ({ message: 'Token type must be "mcp"' }), + error: () => ({ message: 'Token type must be "mcp"' }), }), s: z.array(z.string().min(1)).min(1, 'At least one scope is required'), }), @@ -121,16 +121,16 @@ export interface McpAccessTokenContext { export const previewTokenPayloadSchema = z.object({ iss: z.string().min(1, 'Issuer (iss) is required'), sub: z.literal('preview', { - errorMap: () => ({ message: 'Subject must be "preview"' }), + error: () => ({ message: 'Subject must be "preview"' }), }), exp: z.number().int().positive('Expiration (exp) must be a positive integer'), iat: z.number().int().positive('Issued at (iat) must be a positive integer'), nbf: z.number().int().positive('Not before (nbf) must be a positive integer'), - v: z.literal(1, { errorMap: () => ({ message: 'Version must be 1' }) }), + v: z.literal(1, { error: () => ({ message: 'Version must be 1' }) }), r: z.object({ u: z.string().min(1, 'User ID is required'), t: z.literal('pt', { - errorMap: () => ({ message: 'Token type must be "pt"' }), + error: () => ({ message: 'Token type must be "pt"' }), }), }), }); diff --git a/packages/types/src/automation-additional-rules.ts b/packages/types/src/automation-additional-rules.ts index 76faba9d6..36cb35d0f 100644 --- a/packages/types/src/automation-additional-rules.ts +++ b/packages/types/src/automation-additional-rules.ts @@ -3,11 +3,11 @@ import { z } from 'zod'; export const automationAdditionalRulesSchema = z .object({ text: z.string().min(1).max(8000), - repositoryIds: z.array(z.string().uuid()).nullable(), + repositoryIds: z.array(z.guid()).nullable(), destinations: z.array( z .object({ - repositoryId: z.string().uuid(), + repositoryId: z.guid(), target: z .object({ provider: z.enum(['slack', 'discord', 'teams', 'telegram']), diff --git a/packages/types/src/credential-egress.ts b/packages/types/src/credential-egress.ts index fc03fa4a7..50e10438d 100644 --- a/packages/types/src/credential-egress.ts +++ b/packages/types/src/credential-egress.ts @@ -214,7 +214,7 @@ export const credentialEgressProxyAuthorizeSchema = z method: credentialEgressMethodSchema, path: requestPathSchema, phase: z.enum(CREDENTIAL_EGRESS_PHASES).default('request'), - authorizationId: z.string().uuid().optional(), + authorizationId: z.guid().optional(), }) .strict(); diff --git a/packages/types/src/custom-mcp-servers.ts b/packages/types/src/custom-mcp-servers.ts index d5476a93a..a3f84d113 100644 --- a/packages/types/src/custom-mcp-servers.ts +++ b/packages/types/src/custom-mcp-servers.ts @@ -200,12 +200,14 @@ export const customMcpServerNameSchema = z CUSTOM_MCP_SERVER_NAME_PATTERN, 'Server name must be a lowercase slug (letters, digits, "-", "_"), at most 64 characters.', ) - .refine( - (name) => !RESERVED_CUSTOM_MCP_SERVER_NAMES.has(name), - (name) => ({ - message: `'${name}' is reserved by a built-in ${PRODUCT_NAME} integration.`, - }), - ); + .superRefine((name, ctx) => { + if (RESERVED_CUSTOM_MCP_SERVER_NAMES.has(name)) { + ctx.addIssue({ + code: 'custom', + message: `'${name}' is reserved by a built-in ${PRODUCT_NAME} integration.`, + }); + } + }); export const customMcpServerHeadersSchema = z .record(z.string(), z.string().max(MAX_CUSTOM_MCP_HEADER_VALUE_LENGTH)) diff --git a/packages/types/src/environment-config.ts b/packages/types/src/environment-config.ts index 26008c5ec..fe2eccaa9 100644 --- a/packages/types/src/environment-config.ts +++ b/packages/types/src/environment-config.ts @@ -7,15 +7,17 @@ import { gitBranchNameSchema } from './git-ref'; import { collectReservedEnvReferences } from './reserved-mcp-env-vars'; import { SANDBOX_OPENROUTER_API_KEY_ENV_VAR_NAME } from './sandbox-preview-inference'; -const environmentEnvMapSchema = z.record(z.string()).superRefine((env, ctx) => { - if (SANDBOX_OPENROUTER_API_KEY_ENV_VAR_NAME in env) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - path: [SANDBOX_OPENROUTER_API_KEY_ENV_VAR_NAME], - message: `${SANDBOX_OPENROUTER_API_KEY_ENV_VAR_NAME} is a deployment-level preview key and cannot be stored in an environment definition`, - }); - } -}); +const environmentEnvMapSchema = z + .record(z.string(), z.string()) + .superRefine((env, ctx) => { + if (SANDBOX_OPENROUTER_API_KEY_ENV_VAR_NAME in env) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: [SANDBOX_OPENROUTER_API_KEY_ENV_VAR_NAME], + message: `${SANDBOX_OPENROUTER_API_KEY_ENV_VAR_NAME} is a deployment-level preview key and cannot be stored in an environment definition`, + }); + } + }); /** * Command @@ -410,7 +412,7 @@ export function slugToPortKey(slug: string): string { */ const environmentMcpServerStreamableHttpInputSchema = z.object({ url: z.string().min(1), - headers: z.record(z.string()).optional(), + headers: z.record(z.string(), z.string()).optional(), command: z.undefined().optional(), args: z.undefined().optional(), env: z.undefined().optional(), @@ -717,7 +719,8 @@ export const environmentConfigSchema = z services: z .array(serviceConfigSchema) .optional() - .transform(filterLegacyServices), + .transform(filterLegacyServices) + .optional(), /** * Customer-owned Docker Compose projects or Dockerfiles to start after * their repositories have been prepared. diff --git a/packages/types/src/environment-recipe.ts b/packages/types/src/environment-recipe.ts index aa50f6124..8a941833b 100644 --- a/packages/types/src/environment-recipe.ts +++ b/packages/types/src/environment-recipe.ts @@ -44,7 +44,7 @@ const rBioconductorRecipeSchema = z r_version: z.string().min(1), bioconductor_version: z.string().min(1), packages: z.array(rResolvedPackageSchema).min(1), - renv_lock: z.record(z.unknown()), + renv_lock: z.record(z.string(), z.unknown()), resolution_fingerprint: recipeFingerprintSchema, }) .optional(), diff --git a/packages/types/src/fast-agent-capabilities.ts b/packages/types/src/fast-agent-capabilities.ts index 001e0d750..5bd6154f3 100644 --- a/packages/types/src/fast-agent-capabilities.ts +++ b/packages/types/src/fast-agent-capabilities.ts @@ -96,7 +96,7 @@ const fastAgentCapabilitySnapshotSchema = z.object({ >, ), initialMilestones: z - .record( + .partialRecord( fastAgentCapabilityIdSchema, z.enum(['offered', 'completed', 'declined', 'deferred']), ) diff --git a/packages/types/src/fast-agent.ts b/packages/types/src/fast-agent.ts index d64fad735..c91bd7b14 100644 --- a/packages/types/src/fast-agent.ts +++ b/packages/types/src/fast-agent.ts @@ -177,7 +177,7 @@ export function isFastAgentCommunicationConversation( } export const fastAgentParentSchema = z.object({ - sessionId: z.string().uuid(), + sessionId: z.guid(), conversation: fastAgentConversationSchema, }); diff --git a/packages/types/src/integration-tool-approvals.ts b/packages/types/src/integration-tool-approvals.ts index 3e8b60cba..91619ff63 100644 --- a/packages/types/src/integration-tool-approvals.ts +++ b/packages/types/src/integration-tool-approvals.ts @@ -183,7 +183,7 @@ export interface IntegrationToolApprovals { } export const integrationToolApprovalDecisionSchema = z.object({ - approvalId: z.string().uuid(), + approvalId: z.guid(), /** `approved_for_session` approves this call and stops asking for the tool. */ decision: z.enum(['approved', 'approved_for_session', 'rejected']), }); diff --git a/packages/types/src/integration-tool-lookup.ts b/packages/types/src/integration-tool-lookup.ts index 965a6155d..abc5d7b9b 100644 --- a/packages/types/src/integration-tool-lookup.ts +++ b/packages/types/src/integration-tool-lookup.ts @@ -116,7 +116,7 @@ const integrationToolArgumentValueSchema = z.union([ z.boolean(), z.null(), z.array(z.unknown()), - z.record(z.unknown()), + z.record(z.string(), z.unknown()), ]); /** @@ -187,7 +187,7 @@ export const CALL_INTEGRATION_TOOL_TOOL = { // models take the null branch for a property-less object even when the // integration tool needs arguments. args: z - .record(integrationToolArgumentValueSchema) + .record(z.string(), integrationToolArgumentValueSchema) .describe(CALL_INTEGRATION_TOOL_ARG_DESCRIPTIONS.args), }, annotations: { diff --git a/packages/types/src/manage-custom-automations-tool.ts b/packages/types/src/manage-custom-automations-tool.ts index 83c68aaca..6a06b96e5 100644 --- a/packages/types/src/manage-custom-automations-tool.ts +++ b/packages/types/src/manage-custom-automations-tool.ts @@ -66,8 +66,8 @@ export const manageCustomAutomationsFieldSchemas = { enabled: z.boolean().optional(), resultPriority: z .enum(AUTOMATION_RESULT_PRIORITIES) - .describe('Result inbox priority. Defaults to normal when creating.') - .optional(), + .optional() + .describe('Result inbox priority. Defaults to normal when creating.'), schedule: z .string() .optional() @@ -77,42 +77,42 @@ export const manageCustomAutomationsFieldSchemas = { model: z .string() .nullable() + .optional() .describe( 'Optional provider/model launch override. Call list_models first and pass an exact returned model ID. The ID prefix selects the configured inference route; openai/... includes connected ChatGPT subscription routing. Omit to keep the deployment default; pass null on update to clear an existing override.', - ) - .optional(), + ), reasoningEffort: z .enum(REASONING_EFFORT_VALUES) .nullable() + .optional() .describe( 'Optional reasoning effort for the selected model. Omit to keep the model default; pass null on update to clear an existing override.', - ) - .optional(), + ), environmentId: z .string() + .optional() .describe( `Environment UUID, "${ALL_REPOSITORIES}", "${NO_REPOSITORIES}" for a Blank slate sandbox without repositories, or "${FAST_EXECUTION}" for Fast mode without an initial sandbox task.`, - ) - .optional(), + ), targetProvider: z .enum(['slack', 'discord', 'teams', 'telegram', 'email']) .nullable() + .optional() .describe( 'Destination provider. Pass null on update to clear the report destination.', - ) - .optional(), + ), targetMode: z .enum(['channel', 'direct_message']) + .optional() .describe( 'Destination mode. Use direct_message to send reports privately to the automation owner through the selected connected provider. Email only supports direct_message.', - ) - .optional(), + ), targetChannelId: z .string() + .optional() .describe( 'Channel identifier for channel destinations, or the opaque account identity id returned by list_destinations for Email. Never pass a raw email address. Account verification is required for inbound email commands and replies, not for receiving automation reports; replying to a Roomote email from the account address verifies it implicitly.', - ) - .optional(), + ), } satisfies z.ZodRawShape; export const manageCustomAutomationsInputSchema = z.object( diff --git a/packages/types/src/manage-tasks-tool.ts b/packages/types/src/manage-tasks-tool.ts index 0ba9eb964..bdb843c1c 100644 --- a/packages/types/src/manage-tasks-tool.ts +++ b/packages/types/src/manage-tasks-tool.ts @@ -130,7 +130,7 @@ export const roomoteManagementFieldSchemas = { ), sessionId: z .string() - .uuid() + .check(z.guid()) .optional() .describe( 'Roomote session UUID from a /sessions/:id URL for get_summary, get_messages, get_updates, or send_message when taskId is omitted; responses return the canonical session ID', diff --git a/packages/types/src/service-credentials.ts b/packages/types/src/service-credentials.ts index 7937d3af5..11a3cc57f 100644 --- a/packages/types/src/service-credentials.ts +++ b/packages/types/src/service-credentials.ts @@ -68,7 +68,7 @@ export const serviceCredentialPrepareToolSchema = z export const serviceCredentialCreateSchema = z .object({ - pendingRef: z.string().uuid(), + pendingRef: z.guid(), secret: z.string().min(8).max(4096), /** * Required, and required to match the prepared policy exactly, whenever @@ -82,13 +82,13 @@ export const serviceCredentialCreateSchema = z export const serviceCredentialRevokeSchema = z .object({ - secretRef: z.string().uuid(), + secretRef: z.guid(), }) .strict(); export const serviceCredentialVisibilityUpdateSchema = z .object({ - secretRef: z.string().uuid(), + secretRef: z.guid(), visibility: serviceCredentialVisibilitySchema, }) .strict(); @@ -113,7 +113,7 @@ export const SERVICE_CREDENTIAL_REQUEST_BODY_MAX_BYTES = 65_536; export const serviceCredentialRequestSchema = z .object({ - secretRef: z.string().uuid(), + secretRef: z.guid(), /** Any method; the broker enforces the grant's approved methods. */ method: credentialEgressMethodSchema, path: z.string().min(1).max(2048), diff --git a/packages/types/src/source-control.ts b/packages/types/src/source-control.ts index 9b25d994a..b37beba00 100644 --- a/packages/types/src/source-control.ts +++ b/packages/types/src/source-control.ts @@ -186,7 +186,7 @@ export function resolveRepositoryProvidersFromPayload(payload: { repositoryProviders?: unknown; }): Record | undefined { const parsed = z - .record(sourceControlProviderSchema) + .record(z.string(), sourceControlProviderSchema) .safeParse(payload.repositoryProviders); return parsed.success && Object.keys(parsed.data).length > 0 diff --git a/packages/types/src/task-launch-api.ts b/packages/types/src/task-launch-api.ts index 1dc91ec14..1a8d80f1a 100644 --- a/packages/types/src/task-launch-api.ts +++ b/packages/types/src/task-launch-api.ts @@ -110,12 +110,12 @@ export const taskLaunchRequestSchema = z.object({ .trim() .regex(/^[0-9a-f]{7,40}$/i, 'sha must be a git commit SHA') .optional(), - environmentId: z.string().uuid().optional(), + environmentId: z.guid().optional(), /** * Idempotency key for standard launches. Retrying with the same id returns * the task the first request created instead of starting another one. */ - launchId: z.string().uuid().optional(), + launchId: z.guid().optional(), type: launchTaskTypeSchema.optional(), repositoryFullNames: z.array(z.string().trim().min(1)).min(1).optional(), selectedRepositories: z.array(z.string().trim().min(1)).min(1).optional(), @@ -140,7 +140,7 @@ export const taskLaunchRequestSchema = z.object({ * Fast conversation whose Session should own the launched task. `pr-review` * launches attach the review to this Session and announce its outcome there. */ - fastConversationId: z.string().uuid().optional(), + fastConversationId: z.guid().optional(), }); export type TaskLaunchRequest = z.infer; diff --git a/packages/types/src/task-runs.ts b/packages/types/src/task-runs.ts index 16da42862..390e0c49b 100644 --- a/packages/types/src/task-runs.ts +++ b/packages/types/src/task-runs.ts @@ -1013,7 +1013,9 @@ const sharedTaskPayloadSchema = z.object({ * span multiple providers. Aggregate selections also include this map when * homogeneous so downstream attribution can verify complete coverage. */ - repositoryProviders: z.record(sourceControlProviderSchema).optional(), + repositoryProviders: z + .record(z.string(), sourceControlProviderSchema) + .optional(), /** * Source-control instance host for repository resolution (for example @@ -1076,13 +1078,13 @@ const sharedTaskPayloadSchema = z.object({ * When specified, additional repositories defined in the environment * will be cloned alongside the primary repository. */ - environmentId: z.string().uuid().optional(), + environmentId: z.guid().optional(), /** * Optional environment definition ID for setup/update tasks that should be * associated with an environment record without changing workspace selection. */ - environmentDefinitionId: z.string().uuid().optional(), + environmentDefinitionId: z.guid().optional(), /** Marks a repository-free environment-definition task that needs nested Docker. */ preparesEnvironment: z.boolean().optional(), @@ -1094,7 +1096,7 @@ const sharedTaskPayloadSchema = z.object({ * this marker may record a verification result for that environment through * the `record_verification` MCP action. */ - verifiesEnvironmentId: z.string().uuid().optional(), + verifiesEnvironmentId: z.guid().optional(), /** * Optional validated repository subset to prepare when `repo` is the @@ -1168,7 +1170,7 @@ const sharedTaskPayloadSchema = z.object({ * the task. */ liveTaskStream: z.boolean().optional(), /** Runless Fast conversation that delegated this task on any chat provider. */ - fastAgentSessionId: z.string().uuid().optional(), + fastAgentSessionId: z.guid().optional(), /** A Session explicitly requested this review, so its result reaches that * Session through the pull-request feedback relay even though review runs * otherwise stay quiet there. Settle still announces only failures. */ @@ -1545,7 +1547,7 @@ const suggestedTasksPayloadSchema = delegatedTaskPayloadSchema.extend({ .min(1) .max(4000) .optional(), - selectedRepositoryIds: z.array(z.string().uuid()).min(1).optional(), + selectedRepositoryIds: z.array(z.guid()).min(1).optional(), }); export const suggestedTasksTaskSchema = sharedTaskSchema.extend({ @@ -1605,18 +1607,18 @@ export const snapshotEnvironmentAttachmentSchema = z.preprocess( z.discriminatedUnion('source', [ z.object({ source: z.literal('active_snapshot_row'), - environmentSnapshotId: z.string().uuid(), + environmentSnapshotId: z.guid(), sourceSnapshotId: z.string().nullable(), sourceSnapshotCreatedAt: z.string().datetime().nullable(), }), z.object({ source: z.literal('pending_snapshot_row'), - environmentSnapshotId: z.string().uuid(), + environmentSnapshotId: z.guid(), claimedAt: z.string().datetime(), }), z.object({ source: z.literal('legacy_active_snapshot_row'), - environmentSnapshotId: z.string().uuid(), + environmentSnapshotId: z.guid(), }), z.object({ source: z.literal('legacy_sandbox_row'), @@ -1645,7 +1647,7 @@ export const snapshotEnvironmentSchema = sharedTaskSchema.extend({ * The environment config defines which repositories, services, * and setup commands to include in the snapshot. */ - environmentId: z.string().uuid(), + environmentId: z.guid(), environmentSnapshotAttachment: snapshotEnvironmentAttachmentSchema.optional(), }), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57ec59955..831902e25 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,9 +38,7 @@ overrides: socket.io>socket.io-adapter: 2.5.8 socket.io-adapter>ws: 8.21.0 tar: 7.5.21 - zod: ^3.25.76 - astro>zod: ^4.3.6 - knip>zod: ^4.1.11 + zod: 4.6.7 '@streamdown/mermaid>mermaid': 11.16.1 nanoid@<4: 5.1.16 dagre-d3-es>lodash-es: 4.18.1 @@ -49,6 +47,7 @@ overrides: preact: '>=10.26.10' smol-toml: 1.9.0 undici: ^7.30.1 + '@azure/msal-node': 7.1.0 diff: '>=5.2.2' flatted: ^3.4.2 '@protobufjs/utf8': 1.1.1 @@ -64,7 +63,7 @@ overrides: brace-expansion@<1.1.21: 1.1.21 brace-expansion@>=2.0.0 <2.1.7: 2.1.7 brace-expansion@>=3.0.0 <5.0.12: 5.0.12 - fast-uri: 3.1.8 + fast-uri: 3.1.9 ip-address: 10.7.4 immutable: 5.1.8 moment: 2.31.0 @@ -165,7 +164,7 @@ importers: version: 0.4.2(@trpc/server@11.15.0(typescript@5.9.3))(hono@4.13.11) '@modelcontextprotocol/sdk': specifier: 1.32.0 - version: 1.32.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) + version: 1.32.0(@cfworker/json-schema@4.1.1)(zod@4.6.7) '@octokit/openapi-webhooks-types': specifier: ^12.1.0 version: 12.1.0 @@ -257,12 +256,12 @@ importers: specifier: ^7.30.1 version: 7.30.1 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@ai-sdk/azure': specifier: 3.0.93 - version: 3.0.93(zod@3.25.76) + version: 3.0.93(zod@4.6.7) '@roomote/config-typescript': specifier: workspace:^ version: link:../../packages/config-typescript @@ -345,8 +344,8 @@ importers: specifier: 26.1.0 version: 26.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -520,8 +519,8 @@ importers: specifier: ^13.1.3 version: 13.1.3 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -555,7 +554,7 @@ importers: version: 3.1000.0 '@better-auth/drizzle-adapter': specifier: ^1.7.12 - version: 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.0)(@libsql/client-wasm@0.15.5)(@opentelemetry/api@1.9.1)(@types/pg@8.16.0)(better-sqlite3@11.10.0)(kysely@0.29.4)(pg@8.15.6)(postgres@3.4.8)) + version: 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.0)(@libsql/client-wasm@0.15.5)(@opentelemetry/api@1.9.1)(@types/pg@8.16.0)(better-sqlite3@11.10.0)(kysely@0.29.4)(pg@8.15.6)(postgres@3.4.8)) '@codemirror/lang-yaml': specifier: ^6.0.0 version: 6.1.3 @@ -741,7 +740,7 @@ importers: version: 4.1.2 ai: specifier: ^6.0.116 - version: 6.0.116(zod@3.25.76) + version: 6.0.116(zod@4.6.7) ansi-to-react: specifier: ^6.2.6 version: 6.2.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -869,8 +868,8 @@ importers: specifier: ^2.9.0 version: 2.9.0 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 zustand: specifier: ^5.0.10 version: 5.0.10(@types/react@19.2.10)(immer@11.1.4)(react@19.2.4)(use-sync-external-store@1.5.0(react@19.2.4)) @@ -958,7 +957,7 @@ importers: version: 2.0.10(hono@4.13.11) '@modelcontextprotocol/sdk': specifier: 1.32.0 - version: 1.32.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) + version: 1.32.0(@cfworker/json-schema@4.1.1)(zod@4.6.7) '@roo-code/judgement': specifier: 0.4.1 version: 0.4.1 @@ -1038,8 +1037,8 @@ importers: specifier: ^2.9.0 version: 2.9.0 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-eslint': specifier: workspace:^ @@ -1078,8 +1077,8 @@ importers: specifier: workspace:^ version: link:../types zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1109,8 +1108,8 @@ importers: specifier: ^9.0.3 version: 9.0.3 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1137,8 +1136,8 @@ importers: specifier: workspace:^ version: link:../types zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1154,13 +1153,13 @@ importers: dependencies: '@ai-sdk/mcp': specifier: ^1.0.25 - version: 1.0.25(zod@3.25.76) + version: 1.0.25(zod@4.6.7) '@aws-sdk/client-s3': specifier: 3.1000.0 version: 3.1000.0 '@modelcontextprotocol/sdk': specifier: 1.32.0 - version: 1.32.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) + version: 1.32.0(@cfworker/json-schema@4.1.1)(zod@4.6.7) '@opencode-ai/sdk': specifier: 1.18.30 version: 1.18.30 @@ -1208,7 +1207,7 @@ importers: version: link:../types ai: specifier: ^6.0.116 - version: 6.0.116(zod@3.25.76) + version: 6.0.116(zod@4.6.7) bullmq: specifier: ^5.78.0 version: 5.78.0 @@ -1234,11 +1233,8 @@ importers: specifier: https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz version: https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz zod: - specifier: ^3.25.76 - version: 3.25.76 - zod-to-json-schema: - specifier: 3.25.1 - version: 3.25.1(zod@3.25.76) + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1277,8 +1273,8 @@ importers: specifier: workspace:^ version: link:../types zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1423,8 +1419,8 @@ importers: specifier: 4.1.12 version: 4.1.12(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(jsdom@26.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(vite@7.3.7(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.20.4)(yaml@2.9.0)) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 packages/env: dependencies: @@ -1433,10 +1429,10 @@ importers: version: link:../types '@t3-oss/env-nextjs': specifier: ^0.13.10 - version: 0.13.10(arktype@2.1.27)(typescript@5.9.3)(zod@3.25.76) + version: 0.13.10(arktype@2.1.27)(typescript@5.9.3)(zod@4.6.7) zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1472,8 +1468,8 @@ importers: specifier: workspace:^ version: link:../types zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1512,8 +1508,8 @@ importers: specifier: ^7.0.4 version: 7.0.4 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1540,8 +1536,8 @@ importers: specifier: workspace:^ version: link:../types zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1574,8 +1570,8 @@ importers: specifier: workspace:^ version: link:../types zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1696,8 +1692,8 @@ importers: specifier: ^2.9.0 version: 2.9.0 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1745,8 +1741,8 @@ importers: specifier: ^7.19.0 version: 7.19.0 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1798,8 +1794,8 @@ importers: specifier: ^2.9.0 version: 2.9.0 zod: - specifier: ^3.25.76 - version: 3.25.76 + specifier: 4.6.7 + version: 4.6.7 devDependencies: '@roomote/config-typescript': specifier: workspace:^ @@ -1820,37 +1816,37 @@ packages: resolution: {integrity: sha512-9nKNmRtopjE3+L+286/4sLBDfDvmdsL7fiQXG0TE38NywxkDDLUhdr0KSllkRQ+m1/8bO7x4rIVhHSjQQiqmnQ==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 + zod: 4.6.7 '@ai-sdk/deepseek@2.0.50': resolution: {integrity: sha512-pnl22aGBIdpK0sXSJN4zDykIXTdyO9m3gFhno3SBPpdwT4Tq041Uy0i/EDWSxIiFa9JEokFGiCt4NNzcE5ntRA==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 + zod: 4.6.7 '@ai-sdk/gateway@3.0.66': resolution: {integrity: sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 + zod: 4.6.7 '@ai-sdk/mcp@1.0.25': resolution: {integrity: sha512-vMlXUPGHGDE2vzLcPR8sw7Dhz2OBjtPU5lB+lIuC1hNQo4REuUC08P0e96/hzBKf4oQYJ8Zo6uP8AG2qThyFbg==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 + zod: 4.6.7 '@ai-sdk/openai@3.0.88': resolution: {integrity: sha512-6M4+bxK/UMijDYK2ia1hCKYma1iajFYxHDlhbinFUdhH2WbFsjoZRMpSjEMlTOBptqmh2J1JclKnprGulF8WwQ==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 + zod: 4.6.7 '@ai-sdk/provider-utils@4.0.33': resolution: {integrity: sha512-nJ0bAfegMAIJtrzMJtbzer1cS3nb7c7DsyU1S4nrPm7ZU0Mn6SBBZv5IGZZGTbpWTJwqKTSPeZJTXalbAxt1BA==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 + zod: 4.6.7 '@ai-sdk/provider@3.0.12': resolution: {integrity: sha512-sj9DWTJ2Ze0WR9qsiOPqoqzNx3OxL6iMxHImbhvoe9qOspekbzxNDMiJ4TIGfYHYh9w4OmBjz3prvqhzTi96+Q==} @@ -2119,12 +2115,16 @@ packages: resolution: {integrity: sha512-eNf2aqx1C6I0yT1GEu5ukblFrmaBXGfe1bivpmlfqvK7giPZvoXLa404C8EfeHVsy6EIryfQuPRzuW1fPxWlHg==} engines: {node: '>=0.8.0'} + '@azure/msal-common@16.14.2': + resolution: {integrity: sha512-HOBR0Gfo39TMrkxNG8k6cfjRkrRjXZc3JQs3ebMWQc9S4cihuknMYra3sgmzbZB752oQBqBN9+WF7c826p2vIQ==} + engines: {node: '>=0.8.0'} + '@azure/msal-common@16.7.0': resolution: {integrity: sha512-Jb8Y7pX6KM42SIT7KWP6YbY3+vLbwB5b5m+tpiiOzMU1QeyelQzs9lO8jv1e7/Uj9r7tg7VjPvW4T0KB1jF3UQ==} engines: {node: '>=0.8.0'} - '@azure/msal-node@5.2.3': - resolution: {integrity: sha512-YYX4TchEVddVBiybKvKhV9QO/q22jgewP+BVxKG7Uh115voPcviGlypbKERDsqQdAiSTJrwi80gcWFjYKdo8+Q==} + '@azure/msal-node@7.1.0': + resolution: {integrity: sha512-s1O6hSY/C/dmqykTmmeHY6GhSkDuY8N1gxyhuLyaCwbY7N+UBvU2Wu4flas7+NxZiAPcXNPVpgt3n/HP/5yL+w==} engines: {node: '>=20'} '@azure/storage-blob@12.26.0': @@ -3205,7 +3205,7 @@ packages: engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 - zod: ^3.25.76 + zod: 4.6.7 peerDependenciesMeta: '@cfworker/json-schema': optional: true @@ -6043,7 +6043,7 @@ packages: arktype: ^2.1.0 typescript: '>=5.0.0' valibot: ^1.0.0-beta.7 || ^1.0.0 - zod: ^3.25.76 + zod: 4.6.7 peerDependenciesMeta: arktype: optional: true @@ -6060,7 +6060,7 @@ packages: arktype: ^2.1.0 typescript: '>=5.0.0' valibot: ^1.0.0-beta.7 || ^1.0.0 - zod: ^3.25.76 + zod: 4.6.7 peerDependenciesMeta: arktype: optional: true @@ -6879,7 +6879,7 @@ packages: resolution: {integrity: sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 + zod: 4.6.7 ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} @@ -7203,7 +7203,7 @@ packages: better-call@1.4.4: resolution: {integrity: sha512-Gq4XdGFy4dmUxFEAX2nj0ycFcFbD9ZWh8YROouZoyXeF1M11TpYbplk0pDByTFF8Wz+MYa6W9052c9m7dD+mfw==} peerDependencies: - zod: ^3.25.76 + zod: 4.6.7 peerDependenciesMeta: zod: optional: true @@ -8495,8 +8495,8 @@ packages: fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} - fast-uri@3.1.8: - resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==} + fast-uri@3.1.9: + resolution: {integrity: sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==} fast-xml-builder@1.2.0: resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} @@ -12346,13 +12346,7 @@ packages: zod-to-json-schema@3.25.1: resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} peerDependencies: - zod: ^3.25.76 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zod@4.3.6: - resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zod: 4.6.7 zod@4.6.7: resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} @@ -12382,46 +12376,46 @@ snapshots: '@adobe/css-tools@4.4.3': {} - '@ai-sdk/azure@3.0.93(zod@3.25.76)': + '@ai-sdk/azure@3.0.93(zod@4.6.7)': dependencies: - '@ai-sdk/deepseek': 2.0.50(zod@3.25.76) - '@ai-sdk/openai': 3.0.88(zod@3.25.76) + '@ai-sdk/deepseek': 2.0.50(zod@4.6.7) + '@ai-sdk/openai': 3.0.88(zod@4.6.7) '@ai-sdk/provider': 3.0.14 - '@ai-sdk/provider-utils': 4.0.33(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 4.0.33(zod@4.6.7) + zod: 4.6.7 - '@ai-sdk/deepseek@2.0.50(zod@3.25.76)': + '@ai-sdk/deepseek@2.0.50(zod@4.6.7)': dependencies: '@ai-sdk/provider': 3.0.14 - '@ai-sdk/provider-utils': 4.0.33(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 4.0.33(zod@4.6.7) + zod: 4.6.7 - '@ai-sdk/gateway@3.0.66(zod@3.25.76)': + '@ai-sdk/gateway@3.0.66(zod@4.6.7)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.33(zod@3.25.76) + '@ai-sdk/provider-utils': 4.0.33(zod@4.6.7) '@vercel/oidc': 3.1.0 - zod: 3.25.76 + zod: 4.6.7 - '@ai-sdk/mcp@1.0.25(zod@3.25.76)': + '@ai-sdk/mcp@1.0.25(zod@4.6.7)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.33(zod@3.25.76) + '@ai-sdk/provider-utils': 4.0.33(zod@4.6.7) pkce-challenge: 5.0.1 - zod: 3.25.76 + zod: 4.6.7 - '@ai-sdk/openai@3.0.88(zod@3.25.76)': + '@ai-sdk/openai@3.0.88(zod@4.6.7)': dependencies: '@ai-sdk/provider': 3.0.14 - '@ai-sdk/provider-utils': 4.0.33(zod@3.25.76) - zod: 3.25.76 + '@ai-sdk/provider-utils': 4.0.33(zod@4.6.7) + zod: 4.6.7 - '@ai-sdk/provider-utils@4.0.33(zod@3.25.76)': + '@ai-sdk/provider-utils@4.0.33(zod@4.6.7)': dependencies: '@ai-sdk/provider': 3.0.12 '@standard-schema/spec': 1.1.0 eventsource-parser: 3.1.1 - zod: 3.25.76 + zod: 4.6.7 '@ai-sdk/provider@3.0.12': dependencies: @@ -12945,7 +12939,7 @@ snapshots: '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 '@azure/msal-browser': 5.12.0 - '@azure/msal-node': 5.2.3 + '@azure/msal-node': 7.1.0 open: 10.2.0 tslib: 2.8.1 transitivePeerDependencies: @@ -12962,11 +12956,13 @@ snapshots: dependencies: '@azure/msal-common': 16.7.0 + '@azure/msal-common@16.14.2': {} + '@azure/msal-common@16.7.0': {} - '@azure/msal-node@5.2.3': + '@azure/msal-node@7.1.0': dependencies: - '@azure/msal-common': 16.7.0 + '@azure/msal-common': 16.14.2 jsonwebtoken: 9.0.3 '@azure/storage-blob@12.26.0': @@ -13103,7 +13099,7 @@ snapshots: '@balena/dockerignore@1.0.2': {} - '@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1)': + '@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1)': dependencies: '@better-auth/utils': 0.5.0 '@better-fetch/fetch': 1.3.2 @@ -13116,38 +13112,38 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 - '@better-auth/drizzle-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.0)(@libsql/client-wasm@0.15.5)(@opentelemetry/api@1.9.1)(@types/pg@8.16.0)(better-sqlite3@11.10.0)(kysely@0.29.4)(pg@8.15.6)(postgres@3.4.8))': + '@better-auth/drizzle-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.0)(@libsql/client-wasm@0.15.5)(@opentelemetry/api@1.9.1)(@types/pg@8.16.0)(better-sqlite3@11.10.0)(kysely@0.29.4)(pg@8.15.6)(postgres@3.4.8))': dependencies: - '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.5.0 optionalDependencies: drizzle-orm: 0.45.2(@electric-sql/pglite@0.3.0)(@libsql/client-wasm@0.15.5)(@opentelemetry/api@1.9.1)(@types/pg@8.16.0)(better-sqlite3@11.10.0)(kysely@0.29.4)(pg@8.15.6)(postgres@3.4.8) - '@better-auth/kysely-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(kysely@0.29.4)': + '@better-auth/kysely-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(kysely@0.29.4)': dependencies: - '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.5.0 optionalDependencies: kysely: 0.29.4 - '@better-auth/memory-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)': + '@better-auth/memory-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)': dependencies: - '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.5.0 - '@better-auth/mongo-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)': + '@better-auth/mongo-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)': dependencies: - '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.5.0 - '@better-auth/prisma-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)': + '@better-auth/prisma-adapter@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)': dependencies: - '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.5.0 - '@better-auth/telemetry@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)': + '@better-auth/telemetry@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)': dependencies: - '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.5.0 '@better-fetch/fetch': 1.3.2 @@ -13160,7 +13156,7 @@ snapshots: '@blaxel/core@0.3.0(@cfworker/json-schema@4.1.1)(@hey-api/openapi-ts@0.99.0(typescript@5.9.3))(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: '@hey-api/client-fetch': 0.10.2(@hey-api/openapi-ts@0.99.0(typescript@5.9.3)) - '@modelcontextprotocol/sdk': 1.32.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.32.0(@cfworker/json-schema@4.1.1)(zod@4.6.7) archiver: 7.0.1 axios: 1.20.0 dockerfile-ast: 0.7.1 @@ -13171,7 +13167,7 @@ snapshots: uuid: 11.1.1 ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) yaml: 2.9.0 - zod: 3.25.76 + zod: 4.6.7 transitivePeerDependencies: - '@cfworker/json-schema' - '@hey-api/openapi-ts' @@ -14225,7 +14221,7 @@ snapshots: '@mixmark-io/domino@2.2.0': {} - '@modelcontextprotocol/sdk@1.32.0(@cfworker/json-schema@4.1.1)(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.32.0(@cfworker/json-schema@4.1.1)(zod@4.6.7)': dependencies: '@hono/node-server': 2.0.10(hono@4.13.11) ajv: 8.20.0 @@ -14242,8 +14238,8 @@ snapshots: json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) + zod: 4.6.7 + zod-to-json-schema: 3.25.1(zod@4.6.7) optionalDependencies: '@cfworker/json-schema': 4.1.1 transitivePeerDependencies: @@ -16924,19 +16920,19 @@ snapshots: dependencies: tslib: 2.8.1 - '@t3-oss/env-core@0.13.10(arktype@2.1.27)(typescript@5.9.3)(zod@3.25.76)': + '@t3-oss/env-core@0.13.10(arktype@2.1.27)(typescript@5.9.3)(zod@4.6.7)': optionalDependencies: arktype: 2.1.27 typescript: 5.9.3 - zod: 3.25.76 + zod: 4.6.7 - '@t3-oss/env-nextjs@0.13.10(arktype@2.1.27)(typescript@5.9.3)(zod@3.25.76)': + '@t3-oss/env-nextjs@0.13.10(arktype@2.1.27)(typescript@5.9.3)(zod@4.6.7)': dependencies: - '@t3-oss/env-core': 0.13.10(arktype@2.1.27)(typescript@5.9.3)(zod@3.25.76) + '@t3-oss/env-core': 0.13.10(arktype@2.1.27)(typescript@5.9.3)(zod@4.6.7) optionalDependencies: arktype: 2.1.27 typescript: 5.9.3 - zod: 3.25.76 + zod: 4.6.7 '@tailwindcss/node@4.3.1': dependencies: @@ -17851,13 +17847,13 @@ snapshots: agent-base@7.1.4: {} - ai@6.0.116(zod@3.25.76): + ai@6.0.116(zod@4.6.7): dependencies: - '@ai-sdk/gateway': 3.0.66(zod@3.25.76) + '@ai-sdk/gateway': 3.0.66(zod@4.6.7) '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.33(zod@3.25.76) + '@ai-sdk/provider-utils': 4.0.33(zod@4.6.7) '@opentelemetry/api': 1.9.0 - zod: 3.25.76 + zod: 4.6.7 ajv-formats@2.1.1(ajv@8.20.0): optionalDependencies: @@ -17882,7 +17878,7 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.8 + fast-uri: 3.1.9 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -18140,13 +18136,13 @@ snapshots: better-auth@1.7.12(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.9)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.0)(@libsql/client-wasm@0.15.5)(@opentelemetry/api@1.9.1)(@types/pg@8.16.0)(better-sqlite3@11.10.0)(kysely@0.29.4)(pg@8.15.6)(postgres@3.4.8))(next@16.4.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.15.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vitest@4.1.12(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(jsdom@26.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(vite@7.3.7(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.20.4)(yaml@2.9.0))): dependencies: - '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) - '@better-auth/drizzle-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.0)(@libsql/client-wasm@0.15.5)(@opentelemetry/api@1.9.1)(@types/pg@8.16.0)(better-sqlite3@11.10.0)(kysely@0.29.4)(pg@8.15.6)(postgres@3.4.8)) - '@better-auth/kysely-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(kysely@0.29.4) - '@better-auth/memory-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0) - '@better-auth/mongo-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0) - '@better-auth/prisma-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0) - '@better-auth/telemetry': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@3.25.76))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2) + '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/drizzle-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.0)(@libsql/client-wasm@0.15.5)(@opentelemetry/api@1.9.1)(@types/pg@8.16.0)(better-sqlite3@11.10.0)(kysely@0.29.4)(pg@8.15.6)(postgres@3.4.8)) + '@better-auth/kysely-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(kysely@0.29.4) + '@better-auth/memory-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0) + '@better-auth/mongo-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0) + '@better-auth/prisma-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0) + '@better-auth/telemetry': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.4(zod@4.6.7))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2) '@better-auth/utils': 0.5.0 '@better-fetch/fetch': 1.3.2 '@noble/ciphers': 2.2.0 @@ -19576,7 +19572,7 @@ snapshots: fast-sha256@1.3.0: {} - fast-uri@3.1.8: {} + fast-uri@3.1.9: {} fast-xml-builder@1.2.0: dependencies: @@ -20614,7 +20610,7 @@ snapshots: smol-toml: 1.9.0 strip-json-comments: 5.0.3 typescript: 5.9.3 - zod: 4.3.6 + zod: 4.6.7 kolorist@1.8.0: {} @@ -24293,13 +24289,9 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 - zod-to-json-schema@3.25.1(zod@3.25.76): + zod-to-json-schema@3.25.1(zod@4.6.7): dependencies: - zod: 3.25.76 - - zod@3.25.76: {} - - zod@4.3.6: {} + zod: 4.6.7 zod@4.6.7: {} From fb5e231dff36d13eb83391e70dae505e58e0a59c Mon Sep 17 00:00:00 2001 From: "roomote-roomote[bot]" <301996811+roomote-roomote[bot]@users.noreply.github.com> Date: Sat, 31 Oct 2026 22:37:08 -0400 Subject: [PATCH 3/3] Release Roomote 1.19.7 (#3639) Co-authored-by: @mrubens <2600+mrubens@users.noreply.github.com> --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30cda58c7..580dd1f4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ This file tracks product releases for Roomote (single monorepo version). Automated release entries are prepended by `pnpm run version`. +## 1.19.7 (2026-11-01) + +Roomote 1.19.7 strengthens runtime security while keeping your existing sign-in and task workflows familiar. + +### Highlights + +- Includes security updates for request parsing, input validation, Microsoft authentication, and URI handling. + +### Patch changes + +- Update runtime dependencies to address security issues in request parsing, input validation, Microsoft authentication, and URI handling while preserving existing sign-in, account-linking, and task workflows. + ## 1.19.6 (2026-10-31) Roomote 1.19.6 restores reliable all-repository automations across GitHub organizations and makes it easier to clean up sessions without losing your place. diff --git a/package.json b/package.json index 87cac7691..80730f3e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "roomote", - "version": "1.19.6", + "version": "1.19.7", "license": "FCL-1.0-ALv2", "packageManager": "pnpm@10.29.3", "engines": {