From 665538a29c8f4cb21e3a2c241d435c6617046d2f Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Fri, 1 May 2026 11:48:20 -0700 Subject: [PATCH 1/3] improvement(repo): update ship skills, flatten internal tools contracts dir --- .agents/skills/ship/SKILL.md | 23 ++++++++++--------- .claude/commands/ship.md | 6 +++-- .cursor/commands/ship.md | 6 +++-- .../app/api/tools/a2a/cancel-task/route.ts | 2 +- .../a2a/delete-push-notification/route.ts | 2 +- .../app/api/tools/a2a/get-agent-card/route.ts | 2 +- .../tools/a2a/get-push-notification/route.ts | 2 +- apps/sim/app/api/tools/a2a/get-task/route.ts | 2 +- .../app/api/tools/a2a/resubscribe/route.ts | 2 +- .../app/api/tools/a2a/send-message/route.ts | 2 +- .../tools/a2a/set-push-notification/route.ts | 2 +- .../tools/cursor/download-artifact/route.ts | 2 +- apps/sim/app/api/tools/docusign/route.ts | 2 +- .../tools/onepassword/create-item/route.ts | 2 +- .../tools/onepassword/delete-item/route.ts | 2 +- .../api/tools/onepassword/get-item/route.ts | 2 +- .../api/tools/onepassword/get-vault/route.ts | 2 +- .../api/tools/onepassword/list-items/route.ts | 2 +- .../tools/onepassword/list-vaults/route.ts | 2 +- .../tools/onepassword/replace-item/route.ts | 2 +- .../tools/onepassword/resolve-secret/route.ts | 2 +- .../tools/onepassword/update-item/route.ts | 2 +- .../api/tools/quiver/image-to-svg/route.ts | 2 +- .../app/api/tools/quiver/text-to-svg/route.ts | 2 +- .../app/api/tools/sap_s4hana/proxy/route.ts | 2 +- .../app/api/tools/stagehand/agent/route.ts | 2 +- .../app/api/tools/stagehand/extract/route.ts | 2 +- apps/sim/app/api/tools/thinking/route.ts | 2 +- .../api/contracts/tools/{internal => }/a2a.ts | 10 +++++++- .../contracts/tools/{internal => }/cursor.ts | 10 +++++++- .../tools/{internal => }/docusign.ts | 0 apps/sim/lib/api/contracts/tools/index.ts | 9 +++++++- .../lib/api/contracts/tools/internal/index.ts | 9 -------- .../api/contracts/tools/internal/shared.ts | 10 -------- .../tools/{internal => }/onepassword.ts | 0 .../contracts/tools/{internal => }/quiver.ts | 10 +++++++- .../api/contracts/tools/{internal => }/sap.ts | 10 +++++++- .../tools/{internal => }/stagehand.ts | 0 .../tools/{internal => }/thinking.ts | 0 39 files changed, 89 insertions(+), 64 deletions(-) rename apps/sim/lib/api/contracts/tools/{internal => }/a2a.ts (93%) rename apps/sim/lib/api/contracts/tools/{internal => }/cursor.ts (71%) rename apps/sim/lib/api/contracts/tools/{internal => }/docusign.ts (100%) delete mode 100644 apps/sim/lib/api/contracts/tools/internal/index.ts delete mode 100644 apps/sim/lib/api/contracts/tools/internal/shared.ts rename apps/sim/lib/api/contracts/tools/{internal => }/onepassword.ts (100%) rename apps/sim/lib/api/contracts/tools/{internal => }/quiver.ts (87%) rename apps/sim/lib/api/contracts/tools/{internal => }/sap.ts (97%) rename apps/sim/lib/api/contracts/tools/{internal => }/stagehand.ts (100%) rename apps/sim/lib/api/contracts/tools/{internal => }/thinking.ts (100%) diff --git a/.agents/skills/ship/SKILL.md b/.agents/skills/ship/SKILL.md index 6f9e6322521..51928c32584 100644 --- a/.agents/skills/ship/SKILL.md +++ b/.agents/skills/ship/SKILL.md @@ -1,7 +1,7 @@ --- -name: ship + +## name: ship description: Commit, push, and open a PR to staging in one shot ---- # Ship Command @@ -13,21 +13,20 @@ When the user runs `/ship`: 1. **Check git status** - See what files have changed 2. **Generate a commit message** following this format: `type(scope): description` - - Types: `fix`, `feat`, `improvement`, `chore` - - Scope: short identifier (e.g., `undo-redo`, `api`, `ui`) - - Keep it concise - -3. **Run lint** - Run `bun run lint` from the repo root to fix formatting issues before staging - + - Types: `fix`, `feat`, `improvement`, `chore` + - Scope: short identifier (e.g., `undo-redo`, `api`, `ui`) + - Keep it concise +3. **Run pre-ship checks** from the repo root before staging: + - `bun run lint` to fix formatting issues + - `bun run check:api-validation:strict` to catch boundary contract failures before CI 4. **Stage and commit** the changes with the generated message - 5. **Push to origin** using the current branch name - 6. **Create a PR** to staging with a description in the user's voice ## Commit Message Format Based on the repo's commit history: + ``` fix(scope): description for bug fixes feat(scope): description for new features @@ -61,6 +60,7 @@ Tested manually (or describe testing) ## PR Creation Command Use this command structure: + ```bash gh pr create --base staging --title "COMMIT_MESSAGE" --body "PR_BODY" ``` @@ -77,6 +77,7 @@ gh pr create --base staging --title "COMMIT_MESSAGE" --body "PR_BODY" - Short, direct bullet points - No unnecessary explanation -- "Tested manually" is acceptable for testing section +- "Tested manually" is acceptable for testing section; include lint and boundary validation results when run - Checkboxes filled in appropriately - No screenshots section unless UI changes + diff --git a/.claude/commands/ship.md b/.claude/commands/ship.md index 6f848cc4a8f..6141fa01c1a 100644 --- a/.claude/commands/ship.md +++ b/.claude/commands/ship.md @@ -17,7 +17,9 @@ When the user runs `/ship`: - Scope: short identifier (e.g., `undo-redo`, `api`, `ui`) - Keep it concise -3. **Run lint** - Run `bun run lint` from the repo root to fix formatting issues before staging +3. **Run pre-ship checks** from the repo root before staging: + - `bun run lint` to fix formatting issues + - `bun run check:api-validation:strict` to catch boundary contract failures before CI 4. **Stage and commit** the changes with the generated message @@ -77,6 +79,6 @@ gh pr create --base staging --title "COMMIT_MESSAGE" --body "PR_BODY" - Short, direct bullet points - No unnecessary explanation -- "Tested manually" is acceptable for testing section +- "Tested manually" is acceptable for testing section; include lint and boundary validation results when run - Checkboxes filled in appropriately - No screenshots section unless UI changes diff --git a/.cursor/commands/ship.md b/.cursor/commands/ship.md index 41855257c44..2530e463ee3 100644 --- a/.cursor/commands/ship.md +++ b/.cursor/commands/ship.md @@ -12,7 +12,9 @@ When the user runs `/ship`: - Scope: short identifier (e.g., `undo-redo`, `api`, `ui`) - Keep it concise -3. **Run lint** - Run `bun run lint` from the repo root to fix formatting issues before staging +3. **Run pre-ship checks** from the repo root before staging: + - `bun run lint` to fix formatting issues + - `bun run check:api-validation:strict` to catch boundary contract failures before CI 4. **Stage and commit** the changes with the generated message @@ -72,6 +74,6 @@ gh pr create --base staging --title "COMMIT_MESSAGE" --body "PR_BODY" - Short, direct bullet points - No unnecessary explanation -- "Tested manually" is acceptable for testing section +- "Tested manually" is acceptable for testing section; include lint and boundary validation results when run - Checkboxes filled in appropriately - No screenshots section unless UI changes diff --git a/apps/sim/app/api/tools/a2a/cancel-task/route.ts b/apps/sim/app/api/tools/a2a/cancel-task/route.ts index 74aa9f9fe0b..f5eef3170e7 100644 --- a/apps/sim/app/api/tools/a2a/cancel-task/route.ts +++ b/apps/sim/app/api/tools/a2a/cancel-task/route.ts @@ -2,7 +2,7 @@ import type { Task } from '@a2a-js/sdk' import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { createA2AClient } from '@/lib/a2a/utils' -import { a2aCancelTaskContract } from '@/lib/api/contracts/tools/internal/a2a' +import { a2aCancelTaskContract } from '@/lib/api/contracts/tools/a2a' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/a2a/delete-push-notification/route.ts b/apps/sim/app/api/tools/a2a/delete-push-notification/route.ts index 9e73ce0a7ef..77b46a30000 100644 --- a/apps/sim/app/api/tools/a2a/delete-push-notification/route.ts +++ b/apps/sim/app/api/tools/a2a/delete-push-notification/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { createA2AClient } from '@/lib/a2a/utils' -import { a2aDeletePushNotificationContract } from '@/lib/api/contracts/tools/internal/a2a' +import { a2aDeletePushNotificationContract } from '@/lib/api/contracts/tools/a2a' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/a2a/get-agent-card/route.ts b/apps/sim/app/api/tools/a2a/get-agent-card/route.ts index 89ef553a910..5a39e944d2f 100644 --- a/apps/sim/app/api/tools/a2a/get-agent-card/route.ts +++ b/apps/sim/app/api/tools/a2a/get-agent-card/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { createA2AClient } from '@/lib/a2a/utils' -import { a2aGetAgentCardContract } from '@/lib/api/contracts/tools/internal/a2a' +import { a2aGetAgentCardContract } from '@/lib/api/contracts/tools/a2a' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/a2a/get-push-notification/route.ts b/apps/sim/app/api/tools/a2a/get-push-notification/route.ts index 1bdbc76ccce..49d21b07439 100644 --- a/apps/sim/app/api/tools/a2a/get-push-notification/route.ts +++ b/apps/sim/app/api/tools/a2a/get-push-notification/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { createA2AClient } from '@/lib/a2a/utils' -import { a2aGetPushNotificationContract } from '@/lib/api/contracts/tools/internal/a2a' +import { a2aGetPushNotificationContract } from '@/lib/api/contracts/tools/a2a' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/a2a/get-task/route.ts b/apps/sim/app/api/tools/a2a/get-task/route.ts index 8ca99d70ef8..ac21da72537 100644 --- a/apps/sim/app/api/tools/a2a/get-task/route.ts +++ b/apps/sim/app/api/tools/a2a/get-task/route.ts @@ -2,7 +2,7 @@ import type { Task } from '@a2a-js/sdk' import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { createA2AClient } from '@/lib/a2a/utils' -import { a2aGetTaskContract } from '@/lib/api/contracts/tools/internal/a2a' +import { a2aGetTaskContract } from '@/lib/api/contracts/tools/a2a' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/a2a/resubscribe/route.ts b/apps/sim/app/api/tools/a2a/resubscribe/route.ts index 90d3d035561..69af495725b 100644 --- a/apps/sim/app/api/tools/a2a/resubscribe/route.ts +++ b/apps/sim/app/api/tools/a2a/resubscribe/route.ts @@ -9,7 +9,7 @@ import type { import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { createA2AClient, extractTextContent, isTerminalState } from '@/lib/a2a/utils' -import { a2aResubscribeContract } from '@/lib/api/contracts/tools/internal/a2a' +import { a2aResubscribeContract } from '@/lib/api/contracts/tools/a2a' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/a2a/send-message/route.ts b/apps/sim/app/api/tools/a2a/send-message/route.ts index da27106eb60..badd3267f3d 100644 --- a/apps/sim/app/api/tools/a2a/send-message/route.ts +++ b/apps/sim/app/api/tools/a2a/send-message/route.ts @@ -4,7 +4,7 @@ import { toError } from '@sim/utils/errors' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' import { createA2AClient, extractTextContent, isTerminalState } from '@/lib/a2a/utils' -import { a2aSendMessageContract } from '@/lib/api/contracts/tools/internal/a2a' +import { a2aSendMessageContract } from '@/lib/api/contracts/tools/a2a' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateUrlWithDNS } from '@/lib/core/security/input-validation.server' diff --git a/apps/sim/app/api/tools/a2a/set-push-notification/route.ts b/apps/sim/app/api/tools/a2a/set-push-notification/route.ts index b76c0c1e615..de9c41b8ccc 100644 --- a/apps/sim/app/api/tools/a2a/set-push-notification/route.ts +++ b/apps/sim/app/api/tools/a2a/set-push-notification/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { createA2AClient } from '@/lib/a2a/utils' -import { a2aSetPushNotificationContract } from '@/lib/api/contracts/tools/internal/a2a' +import { a2aSetPushNotificationContract } from '@/lib/api/contracts/tools/a2a' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateUrlWithDNS } from '@/lib/core/security/input-validation.server' diff --git a/apps/sim/app/api/tools/cursor/download-artifact/route.ts b/apps/sim/app/api/tools/cursor/download-artifact/route.ts index e0d605a57fc..c94109c5928 100644 --- a/apps/sim/app/api/tools/cursor/download-artifact/route.ts +++ b/apps/sim/app/api/tools/cursor/download-artifact/route.ts @@ -1,6 +1,6 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' -import { cursorDownloadArtifactContract } from '@/lib/api/contracts/tools/internal/cursor' +import { cursorDownloadArtifactContract } from '@/lib/api/contracts/tools/cursor' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { diff --git a/apps/sim/app/api/tools/docusign/route.ts b/apps/sim/app/api/tools/docusign/route.ts index 3c89ceec4b0..a1352435b6f 100644 --- a/apps/sim/app/api/tools/docusign/route.ts +++ b/apps/sim/app/api/tools/docusign/route.ts @@ -1,6 +1,6 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' -import { docusignToolContract } from '@/lib/api/contracts/tools/internal/docusign' +import { docusignToolContract } from '@/lib/api/contracts/tools/docusign' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/create-item/route.ts b/apps/sim/app/api/tools/onepassword/create-item/route.ts index 0dbdf21e5af..b0ad6ea8bf0 100644 --- a/apps/sim/app/api/tools/onepassword/create-item/route.ts +++ b/apps/sim/app/api/tools/onepassword/create-item/route.ts @@ -2,7 +2,7 @@ import type { ItemCreateParams } from '@1password/sdk' import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordCreateItemContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordCreateItemContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/delete-item/route.ts b/apps/sim/app/api/tools/onepassword/delete-item/route.ts index b63943f48b2..223ad5c9794 100644 --- a/apps/sim/app/api/tools/onepassword/delete-item/route.ts +++ b/apps/sim/app/api/tools/onepassword/delete-item/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordDeleteItemContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordDeleteItemContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/get-item/route.ts b/apps/sim/app/api/tools/onepassword/get-item/route.ts index 8f7bf5d8b9c..8aa473e6a88 100644 --- a/apps/sim/app/api/tools/onepassword/get-item/route.ts +++ b/apps/sim/app/api/tools/onepassword/get-item/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordGetItemContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordGetItemContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/get-vault/route.ts b/apps/sim/app/api/tools/onepassword/get-vault/route.ts index bf5aeac56df..bc4139b4527 100644 --- a/apps/sim/app/api/tools/onepassword/get-vault/route.ts +++ b/apps/sim/app/api/tools/onepassword/get-vault/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordGetVaultContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordGetVaultContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/list-items/route.ts b/apps/sim/app/api/tools/onepassword/list-items/route.ts index 8791ed14631..4e512ac8805 100644 --- a/apps/sim/app/api/tools/onepassword/list-items/route.ts +++ b/apps/sim/app/api/tools/onepassword/list-items/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordListItemsContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordListItemsContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/list-vaults/route.ts b/apps/sim/app/api/tools/onepassword/list-vaults/route.ts index 05b289318f4..f7f1c4f3d5f 100644 --- a/apps/sim/app/api/tools/onepassword/list-vaults/route.ts +++ b/apps/sim/app/api/tools/onepassword/list-vaults/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordListVaultsContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordListVaultsContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/replace-item/route.ts b/apps/sim/app/api/tools/onepassword/replace-item/route.ts index c69e16c67e7..2a9a705fe12 100644 --- a/apps/sim/app/api/tools/onepassword/replace-item/route.ts +++ b/apps/sim/app/api/tools/onepassword/replace-item/route.ts @@ -2,7 +2,7 @@ import type { Item } from '@1password/sdk' import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordReplaceItemContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordReplaceItemContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/resolve-secret/route.ts b/apps/sim/app/api/tools/onepassword/resolve-secret/route.ts index 99fcc73f160..7df319bfe1b 100644 --- a/apps/sim/app/api/tools/onepassword/resolve-secret/route.ts +++ b/apps/sim/app/api/tools/onepassword/resolve-secret/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordResolveSecretContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordResolveSecretContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/onepassword/update-item/route.ts b/apps/sim/app/api/tools/onepassword/update-item/route.ts index ea24f51568d..d13f9c26f78 100644 --- a/apps/sim/app/api/tools/onepassword/update-item/route.ts +++ b/apps/sim/app/api/tools/onepassword/update-item/route.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { type NextRequest, NextResponse } from 'next/server' -import { onePasswordUpdateItemContract } from '@/lib/api/contracts/tools/internal/onepassword' +import { onePasswordUpdateItemContract } from '@/lib/api/contracts/tools/onepassword' import { parseRequest, validationErrorResponse } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/app/api/tools/quiver/image-to-svg/route.ts b/apps/sim/app/api/tools/quiver/image-to-svg/route.ts index 2a26ca8f04d..190c004916b 100644 --- a/apps/sim/app/api/tools/quiver/image-to-svg/route.ts +++ b/apps/sim/app/api/tools/quiver/image-to-svg/route.ts @@ -1,6 +1,6 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' -import { quiverImageToSvgContract } from '@/lib/api/contracts/tools/internal/quiver' +import { quiverImageToSvgContract } from '@/lib/api/contracts/tools/quiver' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/quiver/text-to-svg/route.ts b/apps/sim/app/api/tools/quiver/text-to-svg/route.ts index 399a3ae188f..12b456e75a3 100644 --- a/apps/sim/app/api/tools/quiver/text-to-svg/route.ts +++ b/apps/sim/app/api/tools/quiver/text-to-svg/route.ts @@ -1,6 +1,6 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' -import { quiverTextToSvgContract } from '@/lib/api/contracts/tools/internal/quiver' +import { quiverTextToSvgContract } from '@/lib/api/contracts/tools/quiver' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/sap_s4hana/proxy/route.ts b/apps/sim/app/api/tools/sap_s4hana/proxy/route.ts index 0879578ec33..d3414a48af1 100644 --- a/apps/sim/app/api/tools/sap_s4hana/proxy/route.ts +++ b/apps/sim/app/api/tools/sap_s4hana/proxy/route.ts @@ -6,7 +6,7 @@ import { assertSafeSapExternalUrl, type SapS4HanaProxyRequest, sapS4HanaProxyContract, -} from '@/lib/api/contracts/tools/internal/sap' +} from '@/lib/api/contracts/tools/sap' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' diff --git a/apps/sim/app/api/tools/stagehand/agent/route.ts b/apps/sim/app/api/tools/stagehand/agent/route.ts index e1dd5b7ffe7..8b0842d5978 100644 --- a/apps/sim/app/api/tools/stagehand/agent/route.ts +++ b/apps/sim/app/api/tools/stagehand/agent/route.ts @@ -1,7 +1,7 @@ import type { Stagehand as StagehandType } from '@browserbasehq/stagehand' import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' -import { stagehandAgentContract } from '@/lib/api/contracts/tools/internal/stagehand' +import { stagehandAgentContract } from '@/lib/api/contracts/tools/stagehand' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { env } from '@/lib/core/config/env' diff --git a/apps/sim/app/api/tools/stagehand/extract/route.ts b/apps/sim/app/api/tools/stagehand/extract/route.ts index 5000f3502a1..5d049559963 100644 --- a/apps/sim/app/api/tools/stagehand/extract/route.ts +++ b/apps/sim/app/api/tools/stagehand/extract/route.ts @@ -1,7 +1,7 @@ import type { Stagehand as StagehandType } from '@browserbasehq/stagehand' import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' -import { stagehandExtractContract } from '@/lib/api/contracts/tools/internal/stagehand' +import { stagehandExtractContract } from '@/lib/api/contracts/tools/stagehand' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { env } from '@/lib/core/config/env' diff --git a/apps/sim/app/api/tools/thinking/route.ts b/apps/sim/app/api/tools/thinking/route.ts index ff8c6424acf..75510e49c89 100644 --- a/apps/sim/app/api/tools/thinking/route.ts +++ b/apps/sim/app/api/tools/thinking/route.ts @@ -1,6 +1,6 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' -import { thinkingToolContract } from '@/lib/api/contracts/tools/internal/thinking' +import { thinkingToolContract } from '@/lib/api/contracts/tools/thinking' import { parseRequest } from '@/lib/api/server' import { generateRequestId } from '@/lib/core/utils/request' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' diff --git a/apps/sim/lib/api/contracts/tools/internal/a2a.ts b/apps/sim/lib/api/contracts/tools/a2a.ts similarity index 93% rename from apps/sim/lib/api/contracts/tools/internal/a2a.ts rename to apps/sim/lib/api/contracts/tools/a2a.ts index 078628aa234..99d713f331d 100644 --- a/apps/sim/lib/api/contracts/tools/internal/a2a.ts +++ b/apps/sim/lib/api/contracts/tools/a2a.ts @@ -1,7 +1,15 @@ import { z } from 'zod' -import { internalToolResponseSchema } from '@/lib/api/contracts/tools/internal/shared' import { defineRouteContract } from '@/lib/api/contracts/types' +const internalToolResponseSchema = z + .object({ + success: z.boolean().optional(), + output: z.unknown().optional(), + error: z.string().optional(), + details: z.array(z.unknown()).optional(), + }) + .passthrough() + const a2aBaseBodySchema = z.object({ agentUrl: z.string().min(1, 'Agent URL is required'), apiKey: z.string().optional(), diff --git a/apps/sim/lib/api/contracts/tools/internal/cursor.ts b/apps/sim/lib/api/contracts/tools/cursor.ts similarity index 71% rename from apps/sim/lib/api/contracts/tools/internal/cursor.ts rename to apps/sim/lib/api/contracts/tools/cursor.ts index 31584f7e450..679658b5cf7 100644 --- a/apps/sim/lib/api/contracts/tools/internal/cursor.ts +++ b/apps/sim/lib/api/contracts/tools/cursor.ts @@ -1,7 +1,15 @@ import { z } from 'zod' -import { internalToolResponseSchema } from '@/lib/api/contracts/tools/internal/shared' import { defineRouteContract } from '@/lib/api/contracts/types' +const internalToolResponseSchema = z + .object({ + success: z.boolean().optional(), + output: z.unknown().optional(), + error: z.string().optional(), + details: z.array(z.unknown()).optional(), + }) + .passthrough() + export const cursorDownloadArtifactBodySchema = z.object({ apiKey: z.string().min(1, 'API key is required'), agentId: z.string().min(1, 'Agent ID is required'), diff --git a/apps/sim/lib/api/contracts/tools/internal/docusign.ts b/apps/sim/lib/api/contracts/tools/docusign.ts similarity index 100% rename from apps/sim/lib/api/contracts/tools/internal/docusign.ts rename to apps/sim/lib/api/contracts/tools/docusign.ts diff --git a/apps/sim/lib/api/contracts/tools/index.ts b/apps/sim/lib/api/contracts/tools/index.ts index b8dea78489c..6274b0d732e 100644 --- a/apps/sim/lib/api/contracts/tools/index.ts +++ b/apps/sim/lib/api/contracts/tools/index.ts @@ -1,20 +1,27 @@ +export * from './a2a' export * from './agiloft' export * from './asana' export * from './communication' export * from './crowdstrike' +export * from './cursor' export * from './custom' export * from './databases' +export * from './docusign' export * from './evernote' export * from './file' export * from './firecrawl' export * from './github' export * from './google' export * from './imap' -export * from './internal' export * from './mail' export * from './media' export * from './microsoft' +export * from './onepassword' export * from './pipedrive' +export * from './quiver' +export * from './sap' export * from './search' +export * from './stagehand' +export * from './thinking' export * from './workday' export * from './zoom' diff --git a/apps/sim/lib/api/contracts/tools/internal/index.ts b/apps/sim/lib/api/contracts/tools/internal/index.ts deleted file mode 100644 index 564f57039dc..00000000000 --- a/apps/sim/lib/api/contracts/tools/internal/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from '@/lib/api/contracts/tools/internal/a2a' -export * from '@/lib/api/contracts/tools/internal/cursor' -export * from '@/lib/api/contracts/tools/internal/docusign' -export * from '@/lib/api/contracts/tools/internal/onepassword' -export * from '@/lib/api/contracts/tools/internal/quiver' -export * from '@/lib/api/contracts/tools/internal/sap' -export * from '@/lib/api/contracts/tools/internal/shared' -export * from '@/lib/api/contracts/tools/internal/stagehand' -export * from '@/lib/api/contracts/tools/internal/thinking' diff --git a/apps/sim/lib/api/contracts/tools/internal/shared.ts b/apps/sim/lib/api/contracts/tools/internal/shared.ts deleted file mode 100644 index d4752eb9f1f..00000000000 --- a/apps/sim/lib/api/contracts/tools/internal/shared.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' - -export const internalToolResponseSchema = z - .object({ - success: z.boolean().optional(), - output: z.unknown().optional(), - error: z.string().optional(), - details: z.array(z.unknown()).optional(), - }) - .passthrough() diff --git a/apps/sim/lib/api/contracts/tools/internal/onepassword.ts b/apps/sim/lib/api/contracts/tools/onepassword.ts similarity index 100% rename from apps/sim/lib/api/contracts/tools/internal/onepassword.ts rename to apps/sim/lib/api/contracts/tools/onepassword.ts diff --git a/apps/sim/lib/api/contracts/tools/internal/quiver.ts b/apps/sim/lib/api/contracts/tools/quiver.ts similarity index 87% rename from apps/sim/lib/api/contracts/tools/internal/quiver.ts rename to apps/sim/lib/api/contracts/tools/quiver.ts index 936abb82bfd..b2c6b9d8133 100644 --- a/apps/sim/lib/api/contracts/tools/internal/quiver.ts +++ b/apps/sim/lib/api/contracts/tools/quiver.ts @@ -1,8 +1,16 @@ import { z } from 'zod' -import { internalToolResponseSchema } from '@/lib/api/contracts/tools/internal/shared' import { defineRouteContract } from '@/lib/api/contracts/types' import { FileInputSchema } from '@/lib/uploads/utils/file-schemas' +const internalToolResponseSchema = z + .object({ + success: z.boolean().optional(), + output: z.unknown().optional(), + error: z.string().optional(), + details: z.array(z.unknown()).optional(), + }) + .passthrough() + const quiverCommonBodySchema = z.object({ apiKey: z.string().min(1), model: z.string().min(1), diff --git a/apps/sim/lib/api/contracts/tools/internal/sap.ts b/apps/sim/lib/api/contracts/tools/sap.ts similarity index 97% rename from apps/sim/lib/api/contracts/tools/internal/sap.ts rename to apps/sim/lib/api/contracts/tools/sap.ts index 6949659913c..8e8585bc6fb 100644 --- a/apps/sim/lib/api/contracts/tools/internal/sap.ts +++ b/apps/sim/lib/api/contracts/tools/sap.ts @@ -1,7 +1,15 @@ import { z } from 'zod' -import { internalToolResponseSchema } from '@/lib/api/contracts/tools/internal/shared' import { defineRouteContract } from '@/lib/api/contracts/types' +const internalToolResponseSchema = z + .object({ + success: z.boolean().optional(), + output: z.unknown().optional(), + error: z.string().optional(), + details: z.array(z.unknown()).optional(), + }) + .passthrough() + const sapHttpMethodSchema = z.enum(['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'MERGE']) const sapDeploymentTypeSchema = z.enum(['cloud_public', 'cloud_private', 'on_premise']) const sapAuthTypeSchema = z.enum(['oauth_client_credentials', 'basic']) diff --git a/apps/sim/lib/api/contracts/tools/internal/stagehand.ts b/apps/sim/lib/api/contracts/tools/stagehand.ts similarity index 100% rename from apps/sim/lib/api/contracts/tools/internal/stagehand.ts rename to apps/sim/lib/api/contracts/tools/stagehand.ts diff --git a/apps/sim/lib/api/contracts/tools/internal/thinking.ts b/apps/sim/lib/api/contracts/tools/thinking.ts similarity index 100% rename from apps/sim/lib/api/contracts/tools/internal/thinking.ts rename to apps/sim/lib/api/contracts/tools/thinking.ts From d635deefa3f6993ded710012eeec3c1124d0d204 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Fri, 1 May 2026 11:54:04 -0700 Subject: [PATCH 2/3] update baselines --- scripts/check-api-validation-contracts.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/check-api-validation-contracts.ts b/scripts/check-api-validation-contracts.ts index 7bcf0ebcb0c..751c1919f54 100644 --- a/scripts/check-api-validation-contracts.ts +++ b/scripts/check-api-validation-contracts.ts @@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries') const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors') const BASELINE = { - totalRoutes: 716, - zodRoutes: 716, + totalRoutes: 717, + zodRoutes: 717, nonZodRoutes: 0, } as const From 32be982a4174acbb0d40a3acb7572f9c0cadc0a9 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Fri, 1 May 2026 12:04:30 -0700 Subject: [PATCH 3/3] address comments --- .agents/skills/ship/SKILL.md | 4 ++-- apps/sim/lib/api/contracts/tools/a2a.ts | 26 ++++++++-------------- apps/sim/lib/api/contracts/tools/cursor.ts | 12 ++-------- apps/sim/lib/api/contracts/tools/index.ts | 1 + apps/sim/lib/api/contracts/tools/quiver.ts | 14 +++--------- apps/sim/lib/api/contracts/tools/sap.ts | 12 ++-------- apps/sim/lib/api/contracts/tools/shared.ts | 10 +++++++++ 7 files changed, 29 insertions(+), 50 deletions(-) create mode 100644 apps/sim/lib/api/contracts/tools/shared.ts diff --git a/.agents/skills/ship/SKILL.md b/.agents/skills/ship/SKILL.md index 51928c32584..85fefb30ea6 100644 --- a/.agents/skills/ship/SKILL.md +++ b/.agents/skills/ship/SKILL.md @@ -1,7 +1,7 @@ --- - -## name: ship +name: ship description: Commit, push, and open a PR to staging in one shot +--- # Ship Command diff --git a/apps/sim/lib/api/contracts/tools/a2a.ts b/apps/sim/lib/api/contracts/tools/a2a.ts index 99d713f331d..705f4f7d437 100644 --- a/apps/sim/lib/api/contracts/tools/a2a.ts +++ b/apps/sim/lib/api/contracts/tools/a2a.ts @@ -1,15 +1,7 @@ import { z } from 'zod' +import { genericToolResponseSchema } from '@/lib/api/contracts/tools/shared' import { defineRouteContract } from '@/lib/api/contracts/types' -const internalToolResponseSchema = z - .object({ - success: z.boolean().optional(), - output: z.unknown().optional(), - error: z.string().optional(), - details: z.array(z.unknown()).optional(), - }) - .passthrough() - const a2aBaseBodySchema = z.object({ agentUrl: z.string().min(1, 'Agent URL is required'), apiKey: z.string().optional(), @@ -61,7 +53,7 @@ export const a2aGetAgentCardContract = defineRouteContract({ body: a2aGetAgentCardBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) @@ -71,7 +63,7 @@ export const a2aSendMessageContract = defineRouteContract({ body: a2aSendMessageBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) @@ -81,7 +73,7 @@ export const a2aGetTaskContract = defineRouteContract({ body: a2aGetTaskBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) @@ -91,7 +83,7 @@ export const a2aCancelTaskContract = defineRouteContract({ body: a2aCancelTaskBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) @@ -101,7 +93,7 @@ export const a2aResubscribeContract = defineRouteContract({ body: a2aResubscribeBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) @@ -111,7 +103,7 @@ export const a2aSetPushNotificationContract = defineRouteContract({ body: a2aSetPushNotificationBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) @@ -121,7 +113,7 @@ export const a2aGetPushNotificationContract = defineRouteContract({ body: a2aGetPushNotificationBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) @@ -131,6 +123,6 @@ export const a2aDeletePushNotificationContract = defineRouteContract({ body: a2aDeletePushNotificationBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) diff --git a/apps/sim/lib/api/contracts/tools/cursor.ts b/apps/sim/lib/api/contracts/tools/cursor.ts index 679658b5cf7..c8e04fb4296 100644 --- a/apps/sim/lib/api/contracts/tools/cursor.ts +++ b/apps/sim/lib/api/contracts/tools/cursor.ts @@ -1,15 +1,7 @@ import { z } from 'zod' +import { genericToolResponseSchema } from '@/lib/api/contracts/tools/shared' import { defineRouteContract } from '@/lib/api/contracts/types' -const internalToolResponseSchema = z - .object({ - success: z.boolean().optional(), - output: z.unknown().optional(), - error: z.string().optional(), - details: z.array(z.unknown()).optional(), - }) - .passthrough() - export const cursorDownloadArtifactBodySchema = z.object({ apiKey: z.string().min(1, 'API key is required'), agentId: z.string().min(1, 'Agent ID is required'), @@ -22,6 +14,6 @@ export const cursorDownloadArtifactContract = defineRouteContract({ body: cursorDownloadArtifactBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) diff --git a/apps/sim/lib/api/contracts/tools/index.ts b/apps/sim/lib/api/contracts/tools/index.ts index 6274b0d732e..691b408d9a7 100644 --- a/apps/sim/lib/api/contracts/tools/index.ts +++ b/apps/sim/lib/api/contracts/tools/index.ts @@ -21,6 +21,7 @@ export * from './pipedrive' export * from './quiver' export * from './sap' export * from './search' +export * from './shared' export * from './stagehand' export * from './thinking' export * from './workday' diff --git a/apps/sim/lib/api/contracts/tools/quiver.ts b/apps/sim/lib/api/contracts/tools/quiver.ts index b2c6b9d8133..47ffe3b89d4 100644 --- a/apps/sim/lib/api/contracts/tools/quiver.ts +++ b/apps/sim/lib/api/contracts/tools/quiver.ts @@ -1,16 +1,8 @@ import { z } from 'zod' +import { genericToolResponseSchema } from '@/lib/api/contracts/tools/shared' import { defineRouteContract } from '@/lib/api/contracts/types' import { FileInputSchema } from '@/lib/uploads/utils/file-schemas' -const internalToolResponseSchema = z - .object({ - success: z.boolean().optional(), - output: z.unknown().optional(), - error: z.string().optional(), - details: z.array(z.unknown()).optional(), - }) - .passthrough() - const quiverCommonBodySchema = z.object({ apiKey: z.string().min(1), model: z.string().min(1), @@ -42,7 +34,7 @@ export const quiverTextToSvgContract = defineRouteContract({ body: quiverTextToSvgBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) @@ -52,6 +44,6 @@ export const quiverImageToSvgContract = defineRouteContract({ body: quiverImageToSvgBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) diff --git a/apps/sim/lib/api/contracts/tools/sap.ts b/apps/sim/lib/api/contracts/tools/sap.ts index 8e8585bc6fb..38b10cbbecc 100644 --- a/apps/sim/lib/api/contracts/tools/sap.ts +++ b/apps/sim/lib/api/contracts/tools/sap.ts @@ -1,15 +1,7 @@ import { z } from 'zod' +import { genericToolResponseSchema } from '@/lib/api/contracts/tools/shared' import { defineRouteContract } from '@/lib/api/contracts/types' -const internalToolResponseSchema = z - .object({ - success: z.boolean().optional(), - output: z.unknown().optional(), - error: z.string().optional(), - details: z.array(z.unknown()).optional(), - }) - .passthrough() - const sapHttpMethodSchema = z.enum(['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'MERGE']) const sapDeploymentTypeSchema = z.enum(['cloud_public', 'cloud_private', 'on_premise']) const sapAuthTypeSchema = z.enum(['oauth_client_credentials', 'basic']) @@ -278,6 +270,6 @@ export const sapS4HanaProxyContract = defineRouteContract({ body: sapS4HanaProxyBodySchema, response: { mode: 'json', - schema: internalToolResponseSchema, + schema: genericToolResponseSchema, }, }) diff --git a/apps/sim/lib/api/contracts/tools/shared.ts b/apps/sim/lib/api/contracts/tools/shared.ts new file mode 100644 index 00000000000..e22d2ed272a --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/shared.ts @@ -0,0 +1,10 @@ +import { z } from 'zod' + +export const genericToolResponseSchema = z + .object({ + success: z.boolean().optional(), + output: z.unknown().optional(), + error: z.string().optional(), + details: z.array(z.unknown()).optional(), + }) + .passthrough()