chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelAddDomainParams, VercelAddDomainResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelAddDomainTool: ToolConfig<VercelAddDomainParams, VercelAddDomainResponse> = {
|
||||
id: 'vercel_add_domain',
|
||||
name: 'Vercel Add Domain',
|
||||
description: 'Add a new domain to a Vercel account or team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The domain name to add',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelAddDomainParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v7/domains${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelAddDomainParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelAddDomainParams) => ({
|
||||
method: 'add',
|
||||
name: params.name.trim(),
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const d = data.domain ?? data
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: d.id ?? null,
|
||||
name: d.name ?? null,
|
||||
verified: d.verified ?? false,
|
||||
createdAt: d.createdAt ?? null,
|
||||
serviceType: d.serviceType ?? null,
|
||||
nameservers: d.nameservers ?? [],
|
||||
intendedNameservers: d.intendedNameservers ?? [],
|
||||
expiresAt: d.expiresAt ?? null,
|
||||
customNameservers: d.customNameservers ?? [],
|
||||
renew: d.renew ?? null,
|
||||
boughtAt: d.boughtAt ?? null,
|
||||
transferredAt: d.transferredAt ?? null,
|
||||
creator: d.creator
|
||||
? {
|
||||
id: d.creator.id ?? null,
|
||||
username: d.creator.username ?? null,
|
||||
email: d.creator.email ?? null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Domain ID' },
|
||||
name: { type: 'string', description: 'Domain name' },
|
||||
verified: { type: 'boolean', description: 'Whether domain is verified' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
serviceType: { type: 'string', description: 'Service type (zeit.world, external, na)' },
|
||||
nameservers: {
|
||||
type: 'array',
|
||||
description: 'Current nameservers',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
intendedNameservers: {
|
||||
type: 'array',
|
||||
description: 'Intended nameservers',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
expiresAt: { type: 'number', description: 'Expiration timestamp', optional: true },
|
||||
customNameservers: {
|
||||
type: 'array',
|
||||
description: 'Custom nameservers',
|
||||
items: { type: 'string' },
|
||||
optional: true,
|
||||
},
|
||||
renew: { type: 'boolean', description: 'Whether auto-renewal is enabled', optional: true },
|
||||
boughtAt: { type: 'number', description: 'Purchase timestamp', optional: true },
|
||||
transferredAt: { type: 'number', description: 'Transfer completion timestamp', optional: true },
|
||||
creator: {
|
||||
type: 'object',
|
||||
description: 'Domain creator (id, username, email)',
|
||||
optional: true,
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Creator ID' },
|
||||
username: { type: 'string', description: 'Creator username' },
|
||||
email: { type: 'string', description: 'Creator email' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelAddProjectDomainParams,
|
||||
VercelAddProjectDomainResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelAddProjectDomainTool: ToolConfig<
|
||||
VercelAddProjectDomainParams,
|
||||
VercelAddProjectDomainResponse
|
||||
> = {
|
||||
id: 'vercel_add_project_domain',
|
||||
name: 'Vercel Add Project Domain',
|
||||
description: 'Add a domain to a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain name to add',
|
||||
},
|
||||
redirect: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target domain for redirect',
|
||||
},
|
||||
redirectStatusCode: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'HTTP status code for redirect (301, 302, 307, 308)',
|
||||
},
|
||||
gitBranch: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Git branch to link the domain to',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelAddProjectDomainParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v10/projects/${params.projectId.trim()}/domains${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelAddProjectDomainParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelAddProjectDomainParams) => {
|
||||
const body: Record<string, unknown> = { name: params.domain.trim() }
|
||||
if (params.redirect) body.redirect = params.redirect.trim()
|
||||
if (params.redirectStatusCode) body.redirectStatusCode = params.redirectStatusCode
|
||||
if (params.gitBranch) body.gitBranch = params.gitBranch.trim()
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
name: data.name,
|
||||
apexName: data.apexName,
|
||||
projectId: data.projectId,
|
||||
verified: data.verified,
|
||||
gitBranch: data.gitBranch ?? null,
|
||||
redirect: data.redirect ?? null,
|
||||
redirectStatusCode: data.redirectStatusCode ?? null,
|
||||
verification: data.verification ?? [],
|
||||
createdAt: data.createdAt,
|
||||
updatedAt: data.updatedAt,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
name: { type: 'string', description: 'Domain name' },
|
||||
apexName: { type: 'string', description: 'Apex domain name' },
|
||||
projectId: { type: 'string', description: 'Project ID the domain belongs to' },
|
||||
verified: { type: 'boolean', description: 'Whether the domain is verified' },
|
||||
gitBranch: { type: 'string', description: 'Git branch for the domain', optional: true },
|
||||
redirect: { type: 'string', description: 'Redirect target domain', optional: true },
|
||||
redirectStatusCode: {
|
||||
type: 'number',
|
||||
description: 'HTTP status code for redirect (301, 302, 307, 308)',
|
||||
optional: true,
|
||||
},
|
||||
verification: {
|
||||
type: 'array',
|
||||
description: 'Domain verification challenges (type, domain, value, reason)',
|
||||
optional: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: { type: 'string', description: 'Challenge type' },
|
||||
domain: { type: 'string', description: 'Domain to add the record to' },
|
||||
value: { type: 'string', description: 'Expected record value' },
|
||||
reason: { type: 'string', description: 'Why verification is needed' },
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelCancelDeploymentParams,
|
||||
VercelCancelDeploymentResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCancelDeploymentTool: ToolConfig<
|
||||
VercelCancelDeploymentParams,
|
||||
VercelCancelDeploymentResponse
|
||||
> = {
|
||||
id: 'vercel_cancel_deployment',
|
||||
name: 'Vercel Cancel Deployment',
|
||||
description: 'Cancel a running Vercel deployment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The deployment ID to cancel',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCancelDeploymentParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v12/deployments/${params.deploymentId.trim()}/cancel${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: VercelCancelDeploymentParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id ?? data.uid,
|
||||
name: data.name ?? null,
|
||||
state: data.readyState ?? data.state ?? 'CANCELED',
|
||||
url: data.url ?? null,
|
||||
status: data.status ?? null,
|
||||
projectId: data.projectId ?? null,
|
||||
inspectorUrl: data.inspectorUrl ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Deployment ID',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Deployment name',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
description: 'Deployment state after cancellation',
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
description: 'Deployment URL',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Deployment status',
|
||||
optional: true,
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
description: 'Associated project ID',
|
||||
optional: true,
|
||||
},
|
||||
inspectorUrl: {
|
||||
type: 'string',
|
||||
description: 'Vercel inspector URL',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelCreateAliasParams, VercelCreateAliasResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCreateAliasTool: ToolConfig<VercelCreateAliasParams, VercelCreateAliasResponse> =
|
||||
{
|
||||
id: 'vercel_create_alias',
|
||||
name: 'Vercel Create Alias',
|
||||
description: 'Assign an alias (domain/subdomain) to a deployment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Deployment ID to assign the alias to',
|
||||
},
|
||||
alias: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The domain or subdomain to assign as an alias',
|
||||
},
|
||||
redirect: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Hostname to 307-redirect the alias to instead of serving the deployment directly',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCreateAliasParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v2/deployments/${params.deploymentId.trim()}/aliases${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelCreateAliasParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelCreateAliasParams) => {
|
||||
const body: Record<string, unknown> = { alias: params.alias.trim() }
|
||||
if (params.redirect != null && params.redirect !== '') {
|
||||
body.redirect = params.redirect.trim()
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
uid: data.uid ?? null,
|
||||
alias: data.alias ?? null,
|
||||
created: data.created ?? null,
|
||||
oldDeploymentId: data.oldDeploymentId ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Alias ID',
|
||||
},
|
||||
alias: {
|
||||
type: 'string',
|
||||
description: 'Alias hostname',
|
||||
},
|
||||
created: {
|
||||
type: 'string',
|
||||
description: 'Creation timestamp as ISO 8601 date-time string',
|
||||
},
|
||||
oldDeploymentId: {
|
||||
type: 'string',
|
||||
description: 'ID of the previously aliased deployment, if the alias was reassigned',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelCheckResponse, VercelCreateCheckParams } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCreateCheckTool: ToolConfig<VercelCreateCheckParams, VercelCheckResponse> = {
|
||||
id: 'vercel_create_check',
|
||||
name: 'Vercel Create Check',
|
||||
description: 'Create a new deployment check',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Deployment ID to create the check for',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name of the check (max 100 characters)',
|
||||
},
|
||||
blocking: {
|
||||
type: 'boolean',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the check blocks the deployment',
|
||||
},
|
||||
path: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page path being checked',
|
||||
},
|
||||
detailsUrl: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'URL with details about the check',
|
||||
},
|
||||
externalId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'External identifier for the check',
|
||||
},
|
||||
rerequestable: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the check can be rerequested',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCreateCheckParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/deployments/${params.deploymentId.trim()}/checks${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelCreateCheckParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelCreateCheckParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
name: params.name.trim(),
|
||||
blocking: params.blocking,
|
||||
}
|
||||
if (params.path) body.path = params.path
|
||||
if (params.detailsUrl) body.detailsUrl = params.detailsUrl
|
||||
if (params.externalId) body.externalId = params.externalId
|
||||
if (params.rerequestable !== undefined) body.rerequestable = params.rerequestable
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
status: data.status ?? 'registered',
|
||||
conclusion: data.conclusion ?? null,
|
||||
blocking: data.blocking ?? false,
|
||||
deploymentId: data.deploymentId,
|
||||
integrationId: data.integrationId ?? null,
|
||||
externalId: data.externalId ?? null,
|
||||
detailsUrl: data.detailsUrl ?? null,
|
||||
path: data.path ?? null,
|
||||
rerequestable: data.rerequestable ?? false,
|
||||
createdAt: data.createdAt,
|
||||
updatedAt: data.updatedAt,
|
||||
startedAt: data.startedAt ?? null,
|
||||
completedAt: data.completedAt ?? null,
|
||||
output: data.output ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Check ID' },
|
||||
name: { type: 'string', description: 'Check name' },
|
||||
status: { type: 'string', description: 'Check status: registered, running, or completed' },
|
||||
conclusion: {
|
||||
type: 'string',
|
||||
description: 'Check conclusion: canceled, failed, neutral, succeeded, skipped, or stale',
|
||||
optional: true,
|
||||
},
|
||||
blocking: { type: 'boolean', description: 'Whether the check blocks the deployment' },
|
||||
deploymentId: { type: 'string', description: 'Associated deployment ID' },
|
||||
integrationId: { type: 'string', description: 'Associated integration ID', optional: true },
|
||||
externalId: { type: 'string', description: 'External identifier', optional: true },
|
||||
detailsUrl: { type: 'string', description: 'URL with details about the check', optional: true },
|
||||
path: { type: 'string', description: 'Page path being checked', optional: true },
|
||||
rerequestable: { type: 'boolean', description: 'Whether the check can be rerequested' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp in milliseconds' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp in milliseconds' },
|
||||
startedAt: { type: 'number', description: 'Start timestamp in milliseconds', optional: true },
|
||||
completedAt: {
|
||||
type: 'number',
|
||||
description: 'Completion timestamp in milliseconds',
|
||||
optional: true,
|
||||
},
|
||||
output: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Check result output including metrics (FCP, LCP, CLS, TBT, virtualExperienceScore)',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelCreateDeploymentParams,
|
||||
VercelCreateDeploymentResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCreateDeploymentTool: ToolConfig<
|
||||
VercelCreateDeploymentParams,
|
||||
VercelCreateDeploymentResponse
|
||||
> = {
|
||||
id: 'vercel_create_deployment',
|
||||
name: 'Vercel Create Deployment',
|
||||
description: 'Create a new deployment or redeploy an existing one',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project name for the deployment',
|
||||
},
|
||||
project: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID (overrides name for project lookup)',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Existing deployment ID to redeploy',
|
||||
},
|
||||
target: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target environment: production, staging, or a custom environment identifier',
|
||||
},
|
||||
gitSource: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON string defining the Git Repository source to deploy (e.g. {"type":"github","repo":"owner/repo","ref":"main"})',
|
||||
},
|
||||
forceNew: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Forces a new deployment even if there is a previous similar deployment (0 or 1)',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCreateDeploymentParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.forceNew) query.set('forceNew', params.forceNew)
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v13/deployments${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelCreateDeploymentParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelCreateDeploymentParams) => {
|
||||
const body: Record<string, any> = {
|
||||
name: params.name.trim(),
|
||||
}
|
||||
if (params.project) body.project = params.project.trim()
|
||||
if (params.deploymentId) body.deploymentId = params.deploymentId.trim()
|
||||
if (params.target) body.target = params.target
|
||||
if (params.gitSource) {
|
||||
try {
|
||||
body.gitSource = JSON.parse(params.gitSource)
|
||||
} catch {
|
||||
body.gitSource = params.gitSource
|
||||
}
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
url: data.url ?? '',
|
||||
readyState: data.readyState ?? 'QUEUED',
|
||||
projectId: data.projectId ?? '',
|
||||
createdAt: data.createdAt ?? data.created,
|
||||
alias: data.alias ?? [],
|
||||
target: data.target ?? null,
|
||||
inspectorUrl: data.inspectorUrl ?? '',
|
||||
errorCode: data.errorCode ?? null,
|
||||
errorMessage: data.errorMessage ?? null,
|
||||
aliasAssigned: data.aliasAssigned ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Deployment ID' },
|
||||
name: { type: 'string', description: 'Deployment name' },
|
||||
url: { type: 'string', description: 'Unique deployment URL' },
|
||||
readyState: {
|
||||
type: 'string',
|
||||
description: 'Deployment ready state: QUEUED, BUILDING, ERROR, INITIALIZING, READY, CANCELED',
|
||||
},
|
||||
projectId: { type: 'string', description: 'Associated project ID' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp in milliseconds' },
|
||||
alias: {
|
||||
type: 'array',
|
||||
description: 'Assigned aliases',
|
||||
items: { type: 'string', description: 'Alias domain' },
|
||||
},
|
||||
target: { type: 'string', description: 'Target environment', optional: true },
|
||||
inspectorUrl: { type: 'string', description: 'Vercel inspector URL' },
|
||||
errorCode: { type: 'string', description: 'Deployment error code', optional: true },
|
||||
errorMessage: { type: 'string', description: 'Deployment error message', optional: true },
|
||||
aliasAssigned: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the alias has been assigned',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelCreateDnsRecordParams,
|
||||
VercelCreateDnsRecordResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCreateDnsRecordTool: ToolConfig<
|
||||
VercelCreateDnsRecordParams,
|
||||
VercelCreateDnsRecordResponse
|
||||
> = {
|
||||
id: 'vercel_create_dns_record',
|
||||
name: 'Vercel Create DNS Record',
|
||||
description: 'Create a DNS record for a domain in a Vercel account',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The domain name to create the record for',
|
||||
},
|
||||
recordName: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The subdomain or record name',
|
||||
},
|
||||
recordType: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'DNS record type (A, AAAA, ALIAS, CAA, CNAME, HTTPS, MX, SRV, TXT, NS)',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The value of the DNS record (not used for SRV/HTTPS records)',
|
||||
},
|
||||
ttl: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Time to live in seconds',
|
||||
},
|
||||
mxPriority: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Priority for MX records',
|
||||
},
|
||||
srvTarget: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target hostname for SRV records (required when recordType is SRV)',
|
||||
},
|
||||
srvWeight: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Weight for SRV records (required when recordType is SRV)',
|
||||
},
|
||||
srvPort: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Port for SRV records (required when recordType is SRV)',
|
||||
},
|
||||
srvPriority: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Priority for SRV records (required when recordType is SRV)',
|
||||
},
|
||||
httpsTarget: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target hostname for HTTPS records (required when recordType is HTTPS)',
|
||||
},
|
||||
httpsPriority: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Priority for HTTPS records (required when recordType is HTTPS)',
|
||||
},
|
||||
httpsParams: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional service parameters for HTTPS records (e.g. "alpn=h2,h3")',
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'A comment to add context on what this DNS record is for (max 500 characters)',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCreateDnsRecordParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v2/domains/${params.domain.trim()}/records${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelCreateDnsRecordParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelCreateDnsRecordParams) => {
|
||||
const type = params.recordType.trim().toUpperCase()
|
||||
const body: Record<string, unknown> = {
|
||||
name: params.recordName.trim(),
|
||||
type,
|
||||
}
|
||||
if (params.ttl != null) body.ttl = params.ttl
|
||||
|
||||
if (type === 'SRV') {
|
||||
body.srv = {
|
||||
target: params.srvTarget?.trim(),
|
||||
weight: params.srvWeight,
|
||||
port: params.srvPort,
|
||||
priority: params.srvPriority,
|
||||
}
|
||||
} else if (type === 'HTTPS') {
|
||||
body.https = {
|
||||
target: params.httpsTarget?.trim(),
|
||||
priority: params.httpsPriority,
|
||||
...(params.httpsParams ? { params: params.httpsParams.trim() } : {}),
|
||||
}
|
||||
} else {
|
||||
if (params.value != null) body.value = params.value.trim()
|
||||
if (type === 'MX' && params.mxPriority != null) body.mxPriority = params.mxPriority
|
||||
}
|
||||
|
||||
if (params.comment != null && params.comment !== '') body.comment = params.comment
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const d = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
uid: d.uid ?? null,
|
||||
updated: d.updated ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
uid: { type: 'string', description: 'The DNS record ID' },
|
||||
updated: { type: 'number', description: 'Timestamp of the update' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelCreateEdgeConfigParams,
|
||||
VercelCreateEdgeConfigResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCreateEdgeConfigTool: ToolConfig<
|
||||
VercelCreateEdgeConfigParams,
|
||||
VercelCreateEdgeConfigResponse
|
||||
> = {
|
||||
id: 'vercel_create_edge_config',
|
||||
name: 'Vercel Create Edge Config',
|
||||
description: 'Create a new Edge Config store',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The name/slug for the new Edge Config',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCreateEdgeConfigParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/edge-config${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelCreateEdgeConfigParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelCreateEdgeConfigParams) => ({
|
||||
slug: params.slug.trim(),
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id ?? null,
|
||||
slug: data.slug ?? null,
|
||||
ownerId: data.ownerId ?? null,
|
||||
digest: data.digest ?? null,
|
||||
createdAt: data.createdAt ?? null,
|
||||
updatedAt: data.updatedAt ?? null,
|
||||
itemCount: data.itemCount ?? 0,
|
||||
sizeInBytes: data.sizeInBytes ?? 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Edge Config ID',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
description: 'Edge Config slug',
|
||||
},
|
||||
ownerId: {
|
||||
type: 'string',
|
||||
description: 'Owner ID',
|
||||
},
|
||||
digest: {
|
||||
type: 'string',
|
||||
description: 'Content digest hash',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'number',
|
||||
description: 'Creation timestamp',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'number',
|
||||
description: 'Last update timestamp',
|
||||
},
|
||||
itemCount: {
|
||||
type: 'number',
|
||||
description: 'Number of items',
|
||||
},
|
||||
sizeInBytes: {
|
||||
type: 'number',
|
||||
description: 'Size in bytes',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelCreateEnvVarParams, VercelCreateEnvVarResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCreateEnvVarTool: ToolConfig<
|
||||
VercelCreateEnvVarParams,
|
||||
VercelCreateEnvVarResponse
|
||||
> = {
|
||||
id: 'vercel_create_env_var',
|
||||
name: 'Vercel Create Environment Variable',
|
||||
description: 'Create an environment variable for a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
key: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Environment variable name',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Environment variable value',
|
||||
},
|
||||
target: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of target environments (production, preview, development)',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Variable type: system, encrypted, plain, or sensitive (default: plain)',
|
||||
},
|
||||
gitBranch: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Git branch to associate with the variable (requires target to include preview)',
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comment to add context to the variable (max 500 characters)',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCreateEnvVarParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v10/projects/${params.projectId.trim()}/env${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelCreateEnvVarParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelCreateEnvVarParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
key: params.key,
|
||||
value: params.value,
|
||||
target: params.target.split(',').map((t) => t.trim()),
|
||||
type: params.type || 'plain',
|
||||
}
|
||||
if (params.gitBranch) body.gitBranch = params.gitBranch
|
||||
if (params.comment) body.comment = params.comment
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const env = data.created ?? data
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: env.id,
|
||||
key: env.key,
|
||||
value: env.value ?? '',
|
||||
type: env.type ?? 'plain',
|
||||
target: env.target ?? [],
|
||||
gitBranch: env.gitBranch ?? null,
|
||||
comment: env.comment ?? null,
|
||||
createdAt: env.createdAt ?? null,
|
||||
updatedAt: env.updatedAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Environment variable ID',
|
||||
},
|
||||
key: {
|
||||
type: 'string',
|
||||
description: 'Variable name',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
description: 'Variable value',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'Variable type (secret, system, encrypted, plain, sensitive)',
|
||||
},
|
||||
target: {
|
||||
type: 'array',
|
||||
description: 'Target environments',
|
||||
items: { type: 'string', description: 'Environment name' },
|
||||
},
|
||||
gitBranch: {
|
||||
type: 'string',
|
||||
description: 'Git branch filter',
|
||||
optional: true,
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
description: 'Comment providing context for the variable',
|
||||
optional: true,
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp', optional: true },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelCreateProjectParams, VercelCreateProjectResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCreateProjectTool: ToolConfig<
|
||||
VercelCreateProjectParams,
|
||||
VercelCreateProjectResponse
|
||||
> = {
|
||||
id: 'vercel_create_project',
|
||||
name: 'Vercel Create Project',
|
||||
description: 'Create a new Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project name',
|
||||
},
|
||||
framework: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project framework (e.g. nextjs, remix, vite)',
|
||||
},
|
||||
gitRepository: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Git repository connection object with type and repo',
|
||||
},
|
||||
buildCommand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom build command',
|
||||
},
|
||||
outputDirectory: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom output directory',
|
||||
},
|
||||
installCommand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom install command',
|
||||
},
|
||||
rootDirectory: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Subdirectory of the repository the project lives in (for monorepos)',
|
||||
},
|
||||
nodeVersion: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Node.js version to use (e.g. 22.x, 20.x, 18.x)',
|
||||
},
|
||||
devCommand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom dev server command',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCreateProjectParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v11/projects${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelCreateProjectParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelCreateProjectParams) => {
|
||||
const body: Record<string, unknown> = { name: params.name.trim() }
|
||||
if (params.framework) body.framework = params.framework.trim()
|
||||
if (params.gitRepository) body.gitRepository = params.gitRepository
|
||||
if (params.buildCommand) body.buildCommand = params.buildCommand.trim()
|
||||
if (params.outputDirectory) body.outputDirectory = params.outputDirectory.trim()
|
||||
if (params.installCommand) body.installCommand = params.installCommand.trim()
|
||||
if (params.rootDirectory) body.rootDirectory = params.rootDirectory.trim()
|
||||
if (params.nodeVersion) body.nodeVersion = params.nodeVersion.trim()
|
||||
if (params.devCommand) body.devCommand = params.devCommand.trim()
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
framework: data.framework ?? null,
|
||||
createdAt: data.createdAt,
|
||||
updatedAt: data.updatedAt,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Project ID' },
|
||||
name: { type: 'string', description: 'Project name' },
|
||||
framework: { type: 'string', description: 'Project framework', optional: true },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelCreateWebhookParams, VercelCreateWebhookResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelCreateWebhookTool: ToolConfig<
|
||||
VercelCreateWebhookParams,
|
||||
VercelCreateWebhookResponse
|
||||
> = {
|
||||
id: 'vercel_create_webhook',
|
||||
name: 'Vercel Create Webhook',
|
||||
description: 'Create a new webhook for a Vercel team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Webhook URL (must be https)',
|
||||
},
|
||||
events: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated event names to subscribe to',
|
||||
},
|
||||
projectIds: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated project IDs to scope the webhook to',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the webhook to (optional; omit for personal account)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelCreateWebhookParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/webhooks${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelCreateWebhookParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelCreateWebhookParams) => {
|
||||
const body: Record<string, any> = {
|
||||
url: params.url.trim(),
|
||||
events: params.events.split(',').map((e) => e.trim()),
|
||||
}
|
||||
if (params.projectIds) {
|
||||
body.projectIds = params.projectIds.split(',').map((p) => p.trim())
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id ?? null,
|
||||
url: data.url ?? null,
|
||||
secret: data.secret ?? null,
|
||||
events: data.events ?? [],
|
||||
ownerId: data.ownerId ?? null,
|
||||
projectIds: data.projectIds ?? [],
|
||||
createdAt: data.createdAt ?? null,
|
||||
updatedAt: data.updatedAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Webhook ID' },
|
||||
url: { type: 'string', description: 'Webhook URL' },
|
||||
secret: { type: 'string', description: 'Webhook signing secret' },
|
||||
events: {
|
||||
type: 'array',
|
||||
description: 'Events the webhook listens to',
|
||||
items: { type: 'string', description: 'Event name' },
|
||||
},
|
||||
ownerId: { type: 'string', description: 'Owner ID' },
|
||||
projectIds: {
|
||||
type: 'array',
|
||||
description: 'Associated project IDs',
|
||||
items: { type: 'string', description: 'Project ID' },
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelDeleteAliasParams, VercelDeleteAliasResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelDeleteAliasTool: ToolConfig<VercelDeleteAliasParams, VercelDeleteAliasResponse> =
|
||||
{
|
||||
id: 'vercel_delete_alias',
|
||||
name: 'Vercel Delete Alias',
|
||||
description: 'Delete an alias by its ID',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
aliasId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Alias ID to delete',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelDeleteAliasParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v2/aliases/${params.aliasId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelDeleteAliasParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
status: data.status ?? 'SUCCESS',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Deletion status (SUCCESS)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelDeleteDeploymentParams,
|
||||
VercelDeleteDeploymentResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelDeleteDeploymentTool: ToolConfig<
|
||||
VercelDeleteDeploymentParams,
|
||||
VercelDeleteDeploymentResponse
|
||||
> = {
|
||||
id: 'vercel_delete_deployment',
|
||||
name: 'Vercel Delete Deployment',
|
||||
description: 'Delete a Vercel deployment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The deployment ID or URL to delete',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelDeleteDeploymentParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const id = params.deploymentId.trim()
|
||||
if (id.includes('.')) {
|
||||
query.set('url', id)
|
||||
}
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v13/deployments/${id}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelDeleteDeploymentParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
uid: data.uid ?? data.id ?? null,
|
||||
state: data.state ?? 'DELETED',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'The removed deployment ID',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
description: 'Deployment state after deletion (DELETED)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelDeleteDnsRecordParams,
|
||||
VercelDeleteDnsRecordResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelDeleteDnsRecordTool: ToolConfig<
|
||||
VercelDeleteDnsRecordParams,
|
||||
VercelDeleteDnsRecordResponse
|
||||
> = {
|
||||
id: 'vercel_delete_dns_record',
|
||||
name: 'Vercel Delete DNS Record',
|
||||
description: 'Delete a DNS record for a domain in a Vercel account',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The domain name the record belongs to',
|
||||
},
|
||||
recordId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the DNS record to delete',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelDeleteDnsRecordParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v2/domains/${params.domain.trim()}/records/${params.recordId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelDeleteDnsRecordParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async () => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: { type: 'boolean', description: 'Whether the record was deleted' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelDeleteDomainParams, VercelDeleteDomainResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelDeleteDomainTool: ToolConfig<
|
||||
VercelDeleteDomainParams,
|
||||
VercelDeleteDomainResponse
|
||||
> = {
|
||||
id: 'vercel_delete_domain',
|
||||
name: 'Vercel Delete Domain',
|
||||
description: 'Delete a domain from a Vercel account or team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The domain name to delete',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelDeleteDomainParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v6/domains/${params.domain.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelDeleteDomainParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const d = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
uid: d.uid ?? null,
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
uid: { type: 'string', description: 'The ID of the deleted domain' },
|
||||
deleted: { type: 'boolean', description: 'Whether the domain was deleted' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelDeleteEdgeConfigParams,
|
||||
VercelDeleteEdgeConfigResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelDeleteEdgeConfigTool: ToolConfig<
|
||||
VercelDeleteEdgeConfigParams,
|
||||
VercelDeleteEdgeConfigResponse
|
||||
> = {
|
||||
id: 'vercel_delete_edge_config',
|
||||
name: 'Vercel Delete Edge Config',
|
||||
description: 'Delete an Edge Config store by ID',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
edgeConfigId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Edge Config ID to delete',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelDeleteEdgeConfigParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/edge-config/${params.edgeConfigId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelDeleteEdgeConfigParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async () => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the Edge Config was successfully deleted',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelDeleteEnvVarParams, VercelDeleteEnvVarResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelDeleteEnvVarTool: ToolConfig<
|
||||
VercelDeleteEnvVarParams,
|
||||
VercelDeleteEnvVarResponse
|
||||
> = {
|
||||
id: 'vercel_delete_env_var',
|
||||
name: 'Vercel Delete Environment Variable',
|
||||
description: 'Delete an environment variable from a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
envId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Environment variable ID to delete',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelDeleteEnvVarParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}/env/${params.envId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelDeleteEnvVarParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async () => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the environment variable was successfully deleted',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelDeleteProjectParams, VercelDeleteProjectResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelDeleteProjectTool: ToolConfig<
|
||||
VercelDeleteProjectParams,
|
||||
VercelDeleteProjectResponse
|
||||
> = {
|
||||
id: 'vercel_delete_project',
|
||||
name: 'Vercel Delete Project',
|
||||
description: 'Delete a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelDeleteProjectParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelDeleteProjectParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async () => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: { type: 'boolean', description: 'Whether the project was successfully deleted' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelDeleteWebhookParams, VercelDeleteWebhookResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelDeleteWebhookTool: ToolConfig<
|
||||
VercelDeleteWebhookParams,
|
||||
VercelDeleteWebhookResponse
|
||||
> = {
|
||||
id: 'vercel_delete_webhook',
|
||||
name: 'Vercel Delete Webhook',
|
||||
description: 'Delete a webhook from a Vercel team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
webhookId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The webhook ID to delete',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelDeleteWebhookParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/webhooks/${params.webhookId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelDeleteWebhookParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async () => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the webhook was successfully deleted',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetAliasParams, VercelGetAliasResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetAliasTool: ToolConfig<VercelGetAliasParams, VercelGetAliasResponse> = {
|
||||
id: 'vercel_get_alias',
|
||||
name: 'Vercel Get Alias',
|
||||
description: 'Get details about a specific alias by ID or hostname',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
aliasId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Alias ID or hostname to look up',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetAliasParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v4/aliases/${params.aliasId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetAliasParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
uid: data.uid ?? null,
|
||||
alias: data.alias ?? null,
|
||||
deploymentId: data.deploymentId ?? null,
|
||||
projectId: data.projectId ?? null,
|
||||
createdAt: data.createdAt ?? null,
|
||||
updatedAt: data.updatedAt ?? null,
|
||||
redirect: data.redirect ?? null,
|
||||
redirectStatusCode: data.redirectStatusCode ?? null,
|
||||
deployment: data.deployment
|
||||
? { id: data.deployment.id ?? null, url: data.deployment.url ?? null }
|
||||
: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Alias ID',
|
||||
},
|
||||
alias: {
|
||||
type: 'string',
|
||||
description: 'Alias hostname',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
description: 'Associated deployment ID',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
description: 'Associated project ID',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'number',
|
||||
description: 'Creation timestamp in milliseconds',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'number',
|
||||
description: 'Last update timestamp in milliseconds',
|
||||
},
|
||||
redirect: {
|
||||
type: 'string',
|
||||
description: 'Target domain for redirect aliases',
|
||||
},
|
||||
redirectStatusCode: {
|
||||
type: 'number',
|
||||
description: 'HTTP status code for redirect (301, 302, 307, or 308)',
|
||||
},
|
||||
deployment: {
|
||||
type: 'object',
|
||||
description: 'Associated deployment (id, url)',
|
||||
optional: true,
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Deployment ID' },
|
||||
url: { type: 'string', description: 'Deployment URL' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelCheckResponse, VercelGetCheckParams } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetCheckTool: ToolConfig<VercelGetCheckParams, VercelCheckResponse> = {
|
||||
id: 'vercel_get_check',
|
||||
name: 'Vercel Get Check',
|
||||
description: 'Get details of a specific deployment check',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Deployment ID the check belongs to',
|
||||
},
|
||||
checkId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Check ID to retrieve',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetCheckParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/deployments/${params.deploymentId.trim()}/checks/${params.checkId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetCheckParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
status: data.status ?? 'registered',
|
||||
conclusion: data.conclusion ?? null,
|
||||
blocking: data.blocking ?? false,
|
||||
deploymentId: data.deploymentId,
|
||||
integrationId: data.integrationId ?? null,
|
||||
externalId: data.externalId ?? null,
|
||||
detailsUrl: data.detailsUrl ?? null,
|
||||
path: data.path ?? null,
|
||||
rerequestable: data.rerequestable ?? false,
|
||||
createdAt: data.createdAt,
|
||||
updatedAt: data.updatedAt,
|
||||
startedAt: data.startedAt ?? null,
|
||||
completedAt: data.completedAt ?? null,
|
||||
output: data.output ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Check ID' },
|
||||
name: { type: 'string', description: 'Check name' },
|
||||
status: { type: 'string', description: 'Check status: registered, running, or completed' },
|
||||
conclusion: {
|
||||
type: 'string',
|
||||
description: 'Check conclusion: canceled, failed, neutral, succeeded, skipped, or stale',
|
||||
optional: true,
|
||||
},
|
||||
blocking: { type: 'boolean', description: 'Whether the check blocks the deployment' },
|
||||
deploymentId: { type: 'string', description: 'Associated deployment ID' },
|
||||
integrationId: { type: 'string', description: 'Associated integration ID', optional: true },
|
||||
externalId: { type: 'string', description: 'External identifier', optional: true },
|
||||
detailsUrl: { type: 'string', description: 'URL with details about the check', optional: true },
|
||||
path: { type: 'string', description: 'Page path being checked', optional: true },
|
||||
rerequestable: { type: 'boolean', description: 'Whether the check can be rerequested' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp in milliseconds' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp in milliseconds' },
|
||||
startedAt: { type: 'number', description: 'Start timestamp in milliseconds', optional: true },
|
||||
completedAt: {
|
||||
type: 'number',
|
||||
description: 'Completion timestamp in milliseconds',
|
||||
optional: true,
|
||||
},
|
||||
output: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Check result output including metrics (FCP, LCP, CLS, TBT, virtualExperienceScore)',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetDeploymentParams, VercelGetDeploymentResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetDeploymentTool: ToolConfig<
|
||||
VercelGetDeploymentParams,
|
||||
VercelGetDeploymentResponse
|
||||
> = {
|
||||
id: 'vercel_get_deployment',
|
||||
name: 'Vercel Get Deployment',
|
||||
description: 'Get details of a specific Vercel deployment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The unique deployment identifier or hostname',
|
||||
},
|
||||
withGitRepoInfo: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to add in gitRepo information (true/false)',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetDeploymentParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.withGitRepoInfo) query.set('withGitRepoInfo', params.withGitRepoInfo)
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v13/deployments/${params.deploymentId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetDeploymentParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
url: data.url ?? '',
|
||||
readyState: data.readyState ?? 'UNKNOWN',
|
||||
status: data.status ?? data.readyState ?? 'UNKNOWN',
|
||||
target: data.target ?? null,
|
||||
createdAt: data.createdAt ?? data.created,
|
||||
buildingAt: data.buildingAt ?? null,
|
||||
ready: data.ready ?? null,
|
||||
source: data.source ?? '',
|
||||
alias: data.alias ?? [],
|
||||
regions: data.regions ?? [],
|
||||
inspectorUrl: data.inspectorUrl ?? '',
|
||||
projectId: data.projectId ?? '',
|
||||
creator: {
|
||||
uid: data.creator?.uid ?? '',
|
||||
username: data.creator?.username ?? '',
|
||||
},
|
||||
project: data.project
|
||||
? {
|
||||
id: data.project.id,
|
||||
name: data.project.name,
|
||||
framework: data.project.framework ?? null,
|
||||
}
|
||||
: null,
|
||||
meta: data.meta ?? {},
|
||||
gitSource: data.gitSource ?? null,
|
||||
errorCode: data.errorCode ?? null,
|
||||
errorMessage: data.errorMessage ?? null,
|
||||
aliasAssigned: data.aliasAssigned ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Deployment ID' },
|
||||
name: { type: 'string', description: 'Deployment name' },
|
||||
url: { type: 'string', description: 'Unique deployment URL' },
|
||||
readyState: {
|
||||
type: 'string',
|
||||
description: 'Deployment ready state: QUEUED, BUILDING, ERROR, INITIALIZING, READY, CANCELED',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Deployment status',
|
||||
},
|
||||
target: { type: 'string', description: 'Target environment', optional: true },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp in milliseconds' },
|
||||
buildingAt: { type: 'number', description: 'Build start timestamp', optional: true },
|
||||
ready: { type: 'number', description: 'Ready timestamp', optional: true },
|
||||
source: {
|
||||
type: 'string',
|
||||
description: 'Deployment source: cli, git, redeploy, import, v0-web, etc.',
|
||||
},
|
||||
alias: {
|
||||
type: 'array',
|
||||
description: 'Assigned aliases',
|
||||
items: { type: 'string', description: 'Alias domain' },
|
||||
},
|
||||
regions: {
|
||||
type: 'array',
|
||||
description: 'Deployment regions',
|
||||
items: { type: 'string', description: 'Region code' },
|
||||
},
|
||||
inspectorUrl: { type: 'string', description: 'Vercel inspector URL' },
|
||||
projectId: { type: 'string', description: 'Associated project ID' },
|
||||
creator: {
|
||||
type: 'object',
|
||||
description: 'Creator information',
|
||||
properties: {
|
||||
uid: { type: 'string', description: 'Creator user ID' },
|
||||
username: { type: 'string', description: 'Creator username' },
|
||||
},
|
||||
},
|
||||
project: {
|
||||
type: 'object',
|
||||
description: 'Associated project',
|
||||
optional: true,
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Project ID' },
|
||||
name: { type: 'string', description: 'Project name' },
|
||||
framework: { type: 'string', description: 'Project framework', optional: true },
|
||||
},
|
||||
},
|
||||
meta: {
|
||||
type: 'object',
|
||||
description: 'Deployment metadata (key-value strings)',
|
||||
properties: {
|
||||
githubCommitSha: { type: 'string', description: 'GitHub commit SHA', optional: true },
|
||||
githubCommitMessage: {
|
||||
type: 'string',
|
||||
description: 'GitHub commit message',
|
||||
optional: true,
|
||||
},
|
||||
githubCommitRef: { type: 'string', description: 'GitHub branch/ref', optional: true },
|
||||
githubRepo: { type: 'string', description: 'GitHub repository', optional: true },
|
||||
githubOrg: { type: 'string', description: 'GitHub organization', optional: true },
|
||||
githubCommitAuthorName: {
|
||||
type: 'string',
|
||||
description: 'Commit author name',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
gitSource: {
|
||||
type: 'object',
|
||||
description: 'Git source information',
|
||||
optional: true,
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'Git provider type (e.g., github, gitlab, bitbucket)',
|
||||
},
|
||||
ref: { type: 'string', description: 'Git ref (branch or tag)' },
|
||||
sha: { type: 'string', description: 'Git commit SHA' },
|
||||
repoId: { type: 'string', description: 'Repository ID', optional: true },
|
||||
},
|
||||
},
|
||||
errorCode: { type: 'string', description: 'Deployment error code', optional: true },
|
||||
errorMessage: { type: 'string', description: 'Deployment error message', optional: true },
|
||||
aliasAssigned: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the alias has been assigned',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelGetDeploymentEventsParams,
|
||||
VercelGetDeploymentEventsResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetDeploymentEventsTool: ToolConfig<
|
||||
VercelGetDeploymentEventsParams,
|
||||
VercelGetDeploymentEventsResponse
|
||||
> = {
|
||||
id: 'vercel_get_deployment_events',
|
||||
name: 'Vercel Get Deployment Events',
|
||||
description: 'Get build and runtime events for a Vercel deployment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The unique deployment identifier or hostname',
|
||||
},
|
||||
direction: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Order of events by timestamp: backward or forward (default: forward)',
|
||||
},
|
||||
follow: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'When set to 1, returns live events as they happen',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of events to return (-1 for all)',
|
||||
},
|
||||
since: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Timestamp to start pulling build logs from',
|
||||
},
|
||||
until: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Timestamp to stop pulling build logs at',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetDeploymentEventsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.direction) query.set('direction', params.direction)
|
||||
if (params.follow !== undefined) query.set('follow', String(params.follow))
|
||||
if (params.limit !== undefined) query.set('limit', String(params.limit))
|
||||
if (params.since !== undefined) query.set('since', String(params.since))
|
||||
if (params.until !== undefined) query.set('until', String(params.until))
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v3/deployments/${params.deploymentId.trim()}/events${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetDeploymentEventsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const events = (Array.isArray(data) ? data : (data.events ?? [])).map((e: any) => ({
|
||||
type: e.type ?? null,
|
||||
created: e.created ?? null,
|
||||
date: e.date ?? e.payload?.date ?? null,
|
||||
text: e.text ?? e.payload?.text ?? null,
|
||||
serial: e.serial ?? e.payload?.serial ?? null,
|
||||
deploymentId: e.deploymentId ?? e.payload?.deploymentId ?? null,
|
||||
id: e.id ?? e.payload?.id ?? null,
|
||||
level: e.level ?? null,
|
||||
info: e.info ?? e.payload?.info ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
events,
|
||||
count: events.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
events: {
|
||||
type: 'array',
|
||||
description: 'List of deployment events',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Event type: delimiter, command, stdout, stderr, exit, deployment-state, middleware, middleware-invocation, edge-function-invocation, metric, report, fatal',
|
||||
},
|
||||
created: { type: 'number', description: 'Event creation timestamp' },
|
||||
date: { type: 'number', description: 'Event date timestamp' },
|
||||
text: { type: 'string', description: 'Event text content' },
|
||||
serial: { type: 'string', description: 'Event serial identifier' },
|
||||
deploymentId: { type: 'string', description: 'Associated deployment ID' },
|
||||
id: { type: 'string', description: 'Event unique identifier' },
|
||||
level: { type: 'string', description: 'Event level: error or warning' },
|
||||
info: {
|
||||
type: 'object',
|
||||
description: 'Build step info (type, name, entrypoint, path, step, readyState)',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of events returned',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetDomainParams, VercelGetDomainResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetDomainTool: ToolConfig<VercelGetDomainParams, VercelGetDomainResponse> = {
|
||||
id: 'vercel_get_domain',
|
||||
name: 'Vercel Get Domain',
|
||||
description: 'Get information about a specific domain in a Vercel account',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The domain name to retrieve',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetDomainParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v5/domains/${params.domain.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetDomainParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const d = data.domain ?? data
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: d.id ?? null,
|
||||
name: d.name ?? null,
|
||||
verified: d.verified ?? false,
|
||||
createdAt: d.createdAt ?? null,
|
||||
expiresAt: d.expiresAt ?? null,
|
||||
serviceType: d.serviceType ?? null,
|
||||
nameservers: d.nameservers ?? [],
|
||||
intendedNameservers: d.intendedNameservers ?? [],
|
||||
customNameservers: d.customNameservers ?? [],
|
||||
renew: d.renew ?? false,
|
||||
boughtAt: d.boughtAt ?? null,
|
||||
transferredAt: d.transferredAt ?? null,
|
||||
creator: d.creator
|
||||
? {
|
||||
id: d.creator.id ?? null,
|
||||
username: d.creator.username ?? null,
|
||||
email: d.creator.email ?? null,
|
||||
}
|
||||
: null,
|
||||
userId: d.userId ?? null,
|
||||
teamId: d.teamId ?? null,
|
||||
transferStartedAt: d.transferStartedAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Domain ID' },
|
||||
name: { type: 'string', description: 'Domain name' },
|
||||
verified: { type: 'boolean', description: 'Whether domain is verified' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
expiresAt: { type: 'number', description: 'Expiration timestamp' },
|
||||
serviceType: { type: 'string', description: 'Service type (zeit.world, external, na)' },
|
||||
nameservers: {
|
||||
type: 'array',
|
||||
description: 'Current nameservers',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
intendedNameservers: {
|
||||
type: 'array',
|
||||
description: 'Intended nameservers',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
customNameservers: {
|
||||
type: 'array',
|
||||
description: 'Custom nameservers',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
renew: { type: 'boolean', description: 'Whether auto-renewal is enabled' },
|
||||
boughtAt: { type: 'number', description: 'Purchase timestamp' },
|
||||
transferredAt: { type: 'number', description: 'Transfer completion timestamp' },
|
||||
creator: {
|
||||
type: 'object',
|
||||
description: 'Domain creator (id, username, email)',
|
||||
optional: true,
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Creator ID' },
|
||||
username: { type: 'string', description: 'Creator username' },
|
||||
email: { type: 'string', description: 'Creator email' },
|
||||
},
|
||||
},
|
||||
userId: { type: 'string', description: 'Owner user ID', optional: true },
|
||||
teamId: { type: 'string', description: 'Owner team ID', optional: true },
|
||||
transferStartedAt: { type: 'number', description: 'Transfer start timestamp', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelGetDomainConfigParams,
|
||||
VercelGetDomainConfigResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetDomainConfigTool: ToolConfig<
|
||||
VercelGetDomainConfigParams,
|
||||
VercelGetDomainConfigResponse
|
||||
> = {
|
||||
id: 'vercel_get_domain_config',
|
||||
name: 'Vercel Get Domain Config',
|
||||
description: 'Get the configuration for a domain in a Vercel account',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The domain name to get configuration for',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetDomainConfigParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v6/domains/${params.domain.trim()}/config${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetDomainConfigParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const d = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
configuredBy: d.configuredBy ?? null,
|
||||
acceptedChallenges: d.acceptedChallenges ?? [],
|
||||
misconfigured: d.misconfigured ?? false,
|
||||
recommendedIPv4: d.recommendedIPv4 ?? [],
|
||||
recommendedCNAME: d.recommendedCNAME ?? [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
configuredBy: {
|
||||
type: 'string',
|
||||
description: 'How the domain is configured (CNAME, A, http, dns-01, or null)',
|
||||
},
|
||||
acceptedChallenges: {
|
||||
type: 'array',
|
||||
description: 'Accepted challenge types for certificate issuance (dns-01, http-01)',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
misconfigured: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the domain is misconfigured for TLS certificate generation',
|
||||
},
|
||||
recommendedIPv4: {
|
||||
type: 'array',
|
||||
description: 'Recommended IPv4 addresses with rank values',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
rank: { type: 'number', description: 'Priority rank (1 is preferred)' },
|
||||
value: {
|
||||
type: 'array',
|
||||
description: 'IPv4 addresses',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
recommendedCNAME: {
|
||||
type: 'array',
|
||||
description: 'Recommended CNAME records with rank values',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
rank: { type: 'number', description: 'Priority rank (1 is preferred)' },
|
||||
value: { type: 'string', description: 'CNAME value' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetEdgeConfigParams, VercelGetEdgeConfigResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetEdgeConfigTool: ToolConfig<
|
||||
VercelGetEdgeConfigParams,
|
||||
VercelGetEdgeConfigResponse
|
||||
> = {
|
||||
id: 'vercel_get_edge_config',
|
||||
name: 'Vercel Get Edge Config',
|
||||
description: 'Get details about a specific Edge Config store',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
edgeConfigId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Edge Config ID to look up',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetEdgeConfigParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/edge-config/${params.edgeConfigId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetEdgeConfigParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id ?? null,
|
||||
slug: data.slug ?? null,
|
||||
ownerId: data.ownerId ?? null,
|
||||
digest: data.digest ?? null,
|
||||
createdAt: data.createdAt ?? null,
|
||||
updatedAt: data.updatedAt ?? null,
|
||||
itemCount: data.itemCount ?? 0,
|
||||
sizeInBytes: data.sizeInBytes ?? 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Edge Config ID',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
description: 'Edge Config slug',
|
||||
},
|
||||
ownerId: {
|
||||
type: 'string',
|
||||
description: 'Owner ID',
|
||||
},
|
||||
digest: {
|
||||
type: 'string',
|
||||
description: 'Content digest hash',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'number',
|
||||
description: 'Creation timestamp',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'number',
|
||||
description: 'Last update timestamp',
|
||||
},
|
||||
itemCount: {
|
||||
type: 'number',
|
||||
description: 'Number of items',
|
||||
},
|
||||
sizeInBytes: {
|
||||
type: 'number',
|
||||
description: 'Size in bytes',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelGetEdgeConfigItemsParams,
|
||||
VercelGetEdgeConfigItemsResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetEdgeConfigItemsTool: ToolConfig<
|
||||
VercelGetEdgeConfigItemsParams,
|
||||
VercelGetEdgeConfigItemsResponse
|
||||
> = {
|
||||
id: 'vercel_get_edge_config_items',
|
||||
name: 'Vercel Get Edge Config Items',
|
||||
description: 'Get all items in an Edge Config store',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
edgeConfigId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Edge Config ID to get items from',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetEdgeConfigItemsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/edge-config/${params.edgeConfigId.trim()}/items${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetEdgeConfigItemsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const rawItems = Array.isArray(data) ? data : (data.items ?? [])
|
||||
const items = rawItems.map((item: any) => ({
|
||||
key: item.key ?? null,
|
||||
value: item.value ?? null,
|
||||
description: item.description ?? null,
|
||||
edgeConfigId: item.edgeConfigId ?? null,
|
||||
createdAt: item.createdAt ?? null,
|
||||
updatedAt: item.updatedAt ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
items,
|
||||
count: items.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'List of Edge Config items',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
key: { type: 'string', description: 'Item key' },
|
||||
value: { type: 'json', description: 'Item value' },
|
||||
description: { type: 'string', description: 'Item description' },
|
||||
edgeConfigId: { type: 'string', description: 'Parent Edge Config ID' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of items returned',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetEnvVarsParams, VercelGetEnvVarsResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetEnvVarsTool: ToolConfig<VercelGetEnvVarsParams, VercelGetEnvVarsResponse> = {
|
||||
id: 'vercel_get_env_vars',
|
||||
name: 'Vercel Get Environment Variables',
|
||||
description: 'Retrieve environment variables for a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
decrypt: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'If true, decrypted variable values are returned instead of ciphertext',
|
||||
},
|
||||
gitBranch: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Filter results to the environment variables for this git branch (must have target=preview)',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetEnvVarsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.decrypt) query.set('decrypt', 'true')
|
||||
if (params.gitBranch) query.set('gitBranch', params.gitBranch.trim())
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v10/projects/${params.projectId.trim()}/env${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetEnvVarsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const envs = (data.envs ?? []).map((e: any) => ({
|
||||
id: e.id,
|
||||
key: e.key,
|
||||
value: e.value ?? '',
|
||||
type: e.type ?? 'plain',
|
||||
target: e.target ?? [],
|
||||
gitBranch: e.gitBranch ?? null,
|
||||
comment: e.comment ?? null,
|
||||
createdAt: e.createdAt ?? null,
|
||||
updatedAt: e.updatedAt ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
envs,
|
||||
count: envs.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
envs: {
|
||||
type: 'array',
|
||||
description: 'List of environment variables',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Environment variable ID' },
|
||||
key: { type: 'string', description: 'Variable name' },
|
||||
value: { type: 'string', description: 'Variable value' },
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'Variable type (secret, system, encrypted, plain, sensitive)',
|
||||
},
|
||||
target: {
|
||||
type: 'array',
|
||||
description: 'Target environments',
|
||||
items: { type: 'string', description: 'Environment name' },
|
||||
},
|
||||
gitBranch: { type: 'string', description: 'Git branch filter', optional: true },
|
||||
comment: {
|
||||
type: 'string',
|
||||
description: 'Comment providing context for the variable',
|
||||
optional: true,
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp', optional: true },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp', optional: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of environment variables returned',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetProjectParams, VercelGetProjectResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetProjectTool: ToolConfig<VercelGetProjectParams, VercelGetProjectResponse> = {
|
||||
id: 'vercel_get_project',
|
||||
name: 'Vercel Get Project',
|
||||
description: 'Get details of a specific Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetProjectParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetProjectParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
framework: data.framework ?? null,
|
||||
rootDirectory: data.rootDirectory ?? null,
|
||||
nodeVersion: data.nodeVersion ?? null,
|
||||
createdAt: data.createdAt,
|
||||
updatedAt: data.updatedAt,
|
||||
link: data.link
|
||||
? {
|
||||
type: data.link.type,
|
||||
repo: data.link.repo,
|
||||
org: data.link.org,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Project ID' },
|
||||
name: { type: 'string', description: 'Project name' },
|
||||
framework: { type: 'string', description: 'Project framework', optional: true },
|
||||
rootDirectory: { type: 'string', description: 'Root directory of the project', optional: true },
|
||||
nodeVersion: { type: 'string', description: 'Node.js version', optional: true },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp' },
|
||||
link: {
|
||||
type: 'object',
|
||||
description: 'Git repository connection',
|
||||
optional: true,
|
||||
properties: {
|
||||
type: { type: 'string', description: 'Repository type (github, gitlab, bitbucket)' },
|
||||
repo: { type: 'string', description: 'Repository name' },
|
||||
org: { type: 'string', description: 'Organization or owner' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetTeamParams, VercelGetTeamResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetTeamTool: ToolConfig<VercelGetTeamParams, VercelGetTeamResponse> = {
|
||||
id: 'vercel_get_team',
|
||||
name: 'Vercel Get Team',
|
||||
description: 'Get information about a specific Vercel team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The team ID to retrieve',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetTeamParams) => `https://api.vercel.com/v2/teams/${params.teamId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetTeamParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const d = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: d.id ?? null,
|
||||
slug: d.slug ?? null,
|
||||
name: d.name ?? null,
|
||||
avatar: d.avatar ?? null,
|
||||
description: d.description ?? null,
|
||||
stagingPrefix: d.stagingPrefix ?? null,
|
||||
createdAt: d.createdAt ?? null,
|
||||
updatedAt: d.updatedAt ?? null,
|
||||
creatorId: d.creatorId ?? null,
|
||||
membership: d.membership
|
||||
? {
|
||||
uid: d.membership.uid ?? null,
|
||||
teamId: d.membership.teamId ?? null,
|
||||
role: d.membership.role ?? null,
|
||||
confirmed: d.membership.confirmed ?? false,
|
||||
created: d.membership.created ?? null,
|
||||
createdAt: d.membership.createdAt ?? null,
|
||||
accessRequestedAt: d.membership.accessRequestedAt ?? null,
|
||||
teamRoles: d.membership.teamRoles ?? [],
|
||||
teamPermissions: d.membership.teamPermissions ?? [],
|
||||
}
|
||||
: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Team ID' },
|
||||
slug: { type: 'string', description: 'Team slug' },
|
||||
name: { type: 'string', description: 'Team name' },
|
||||
avatar: { type: 'string', description: 'Avatar file ID' },
|
||||
description: { type: 'string', description: 'Short team description' },
|
||||
stagingPrefix: {
|
||||
type: 'string',
|
||||
description: 'Prefix used for staging deployments',
|
||||
optional: true,
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp in milliseconds' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp in milliseconds' },
|
||||
creatorId: { type: 'string', description: 'User ID of team creator' },
|
||||
membership: {
|
||||
type: 'object',
|
||||
description: 'Current user membership details',
|
||||
properties: {
|
||||
uid: { type: 'string', description: 'User ID of the member' },
|
||||
teamId: { type: 'string', description: 'Team ID' },
|
||||
role: { type: 'string', description: 'Membership role' },
|
||||
confirmed: { type: 'boolean', description: 'Whether membership is confirmed' },
|
||||
created: { type: 'number', description: 'Membership creation timestamp' },
|
||||
createdAt: { type: 'number', description: 'Membership creation timestamp (milliseconds)' },
|
||||
accessRequestedAt: { type: 'number', description: 'When access was requested' },
|
||||
teamRoles: {
|
||||
type: 'array',
|
||||
description: 'Team role assignments',
|
||||
items: { type: 'string', description: 'Role name' },
|
||||
},
|
||||
teamPermissions: {
|
||||
type: 'array',
|
||||
description: 'Team permission assignments',
|
||||
items: { type: 'string', description: 'Permission name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetUserParams, VercelGetUserResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetUserTool: ToolConfig<VercelGetUserParams, VercelGetUserResponse> = {
|
||||
id: 'vercel_get_user',
|
||||
name: 'Vercel Get User',
|
||||
description: 'Get information about the authenticated Vercel user',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: () => 'https://api.vercel.com/v2/user',
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetUserParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const d = data.user ?? data
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: d.id ?? null,
|
||||
email: d.email ?? null,
|
||||
username: d.username ?? null,
|
||||
name: d.name ?? null,
|
||||
avatar: d.avatar ?? null,
|
||||
defaultTeamId: d.defaultTeamId ?? null,
|
||||
createdAt: d.createdAt ?? null,
|
||||
stagingPrefix: d.stagingPrefix ?? null,
|
||||
softBlock: d.softBlock
|
||||
? {
|
||||
blockedAt: d.softBlock.blockedAt ?? null,
|
||||
reason: d.softBlock.reason ?? null,
|
||||
}
|
||||
: null,
|
||||
hasTrialAvailable: d.hasTrialAvailable ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'User ID' },
|
||||
email: { type: 'string', description: 'User email' },
|
||||
username: { type: 'string', description: 'Username' },
|
||||
name: { type: 'string', description: 'Display name' },
|
||||
avatar: { type: 'string', description: 'SHA1 hash of the avatar' },
|
||||
defaultTeamId: { type: 'string', description: 'Default team ID' },
|
||||
createdAt: { type: 'number', description: 'Account creation timestamp in milliseconds' },
|
||||
stagingPrefix: { type: 'string', description: 'Prefix for preview deployment URLs' },
|
||||
softBlock: {
|
||||
type: 'object',
|
||||
description: 'Account restriction details if blocked',
|
||||
properties: {
|
||||
blockedAt: { type: 'number', description: 'When the account was blocked' },
|
||||
reason: { type: 'string', description: 'Reason for the block' },
|
||||
},
|
||||
},
|
||||
hasTrialAvailable: { type: 'boolean', description: 'Whether a trial is available' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelGetWebhookParams, VercelGetWebhookResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelGetWebhookTool: ToolConfig<VercelGetWebhookParams, VercelGetWebhookResponse> = {
|
||||
id: 'vercel_get_webhook',
|
||||
name: 'Vercel Get Webhook',
|
||||
description: 'Get details about a specific Vercel webhook',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
webhookId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Webhook ID to look up',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelGetWebhookParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/webhooks/${params.webhookId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelGetWebhookParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id ?? null,
|
||||
url: data.url ?? null,
|
||||
events: data.events ?? [],
|
||||
ownerId: data.ownerId ?? null,
|
||||
projectIds: data.projectIds ?? [],
|
||||
createdAt: data.createdAt ?? null,
|
||||
updatedAt: data.updatedAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Webhook ID',
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
description: 'Webhook URL',
|
||||
},
|
||||
events: {
|
||||
type: 'array',
|
||||
description: 'Events the webhook listens to',
|
||||
items: { type: 'string', description: 'Event name' },
|
||||
},
|
||||
ownerId: {
|
||||
type: 'string',
|
||||
description: 'Owner ID',
|
||||
},
|
||||
projectIds: {
|
||||
type: 'array',
|
||||
description: 'Associated project IDs',
|
||||
optional: true,
|
||||
items: { type: 'string', description: 'Project ID' },
|
||||
},
|
||||
createdAt: {
|
||||
type: 'number',
|
||||
description: 'Creation timestamp',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'number',
|
||||
description: 'Last updated timestamp',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import { vercelAddDomainTool } from '@/tools/vercel/add_domain'
|
||||
import { vercelAddProjectDomainTool } from '@/tools/vercel/add_project_domain'
|
||||
import { vercelCancelDeploymentTool } from '@/tools/vercel/cancel_deployment'
|
||||
import { vercelCreateAliasTool } from '@/tools/vercel/create_alias'
|
||||
import { vercelCreateCheckTool } from '@/tools/vercel/create_check'
|
||||
import { vercelCreateDeploymentTool } from '@/tools/vercel/create_deployment'
|
||||
import { vercelCreateDnsRecordTool } from '@/tools/vercel/create_dns_record'
|
||||
import { vercelCreateEdgeConfigTool } from '@/tools/vercel/create_edge_config'
|
||||
import { vercelCreateEnvVarTool } from '@/tools/vercel/create_env_var'
|
||||
import { vercelCreateProjectTool } from '@/tools/vercel/create_project'
|
||||
import { vercelCreateWebhookTool } from '@/tools/vercel/create_webhook'
|
||||
import { vercelDeleteAliasTool } from '@/tools/vercel/delete_alias'
|
||||
import { vercelDeleteDeploymentTool } from '@/tools/vercel/delete_deployment'
|
||||
import { vercelDeleteDnsRecordTool } from '@/tools/vercel/delete_dns_record'
|
||||
import { vercelDeleteDomainTool } from '@/tools/vercel/delete_domain'
|
||||
import { vercelDeleteEdgeConfigTool } from '@/tools/vercel/delete_edge_config'
|
||||
import { vercelDeleteEnvVarTool } from '@/tools/vercel/delete_env_var'
|
||||
import { vercelDeleteProjectTool } from '@/tools/vercel/delete_project'
|
||||
import { vercelDeleteWebhookTool } from '@/tools/vercel/delete_webhook'
|
||||
import { vercelGetAliasTool } from '@/tools/vercel/get_alias'
|
||||
import { vercelGetCheckTool } from '@/tools/vercel/get_check'
|
||||
import { vercelGetDeploymentTool } from '@/tools/vercel/get_deployment'
|
||||
import { vercelGetDeploymentEventsTool } from '@/tools/vercel/get_deployment_events'
|
||||
import { vercelGetDomainTool } from '@/tools/vercel/get_domain'
|
||||
import { vercelGetDomainConfigTool } from '@/tools/vercel/get_domain_config'
|
||||
import { vercelGetEdgeConfigTool } from '@/tools/vercel/get_edge_config'
|
||||
import { vercelGetEdgeConfigItemsTool } from '@/tools/vercel/get_edge_config_items'
|
||||
import { vercelGetEnvVarsTool } from '@/tools/vercel/get_env_vars'
|
||||
import { vercelGetProjectTool } from '@/tools/vercel/get_project'
|
||||
import { vercelGetTeamTool } from '@/tools/vercel/get_team'
|
||||
import { vercelGetUserTool } from '@/tools/vercel/get_user'
|
||||
import { vercelGetWebhookTool } from '@/tools/vercel/get_webhook'
|
||||
import { vercelListAliasesTool } from '@/tools/vercel/list_aliases'
|
||||
import { vercelListChecksTool } from '@/tools/vercel/list_checks'
|
||||
import { vercelListDeploymentFilesTool } from '@/tools/vercel/list_deployment_files'
|
||||
import { vercelListDeploymentsTool } from '@/tools/vercel/list_deployments'
|
||||
import { vercelListDnsRecordsTool } from '@/tools/vercel/list_dns_records'
|
||||
import { vercelListDomainsTool } from '@/tools/vercel/list_domains'
|
||||
import { vercelListEdgeConfigsTool } from '@/tools/vercel/list_edge_configs'
|
||||
import { vercelListProjectDomainsTool } from '@/tools/vercel/list_project_domains'
|
||||
import { vercelListProjectsTool } from '@/tools/vercel/list_projects'
|
||||
import { vercelListTeamMembersTool } from '@/tools/vercel/list_team_members'
|
||||
import { vercelListTeamsTool } from '@/tools/vercel/list_teams'
|
||||
import { vercelListWebhooksTool } from '@/tools/vercel/list_webhooks'
|
||||
import { vercelPauseProjectTool } from '@/tools/vercel/pause_project'
|
||||
import { vercelPromoteDeploymentTool } from '@/tools/vercel/promote_deployment'
|
||||
import { vercelRemoveProjectDomainTool } from '@/tools/vercel/remove_project_domain'
|
||||
import { vercelRerequestCheckTool } from '@/tools/vercel/rerequest_check'
|
||||
import { vercelUnpauseProjectTool } from '@/tools/vercel/unpause_project'
|
||||
import { vercelUpdateCheckTool } from '@/tools/vercel/update_check'
|
||||
import { vercelUpdateDnsRecordTool } from '@/tools/vercel/update_dns_record'
|
||||
import { vercelUpdateEdgeConfigItemsTool } from '@/tools/vercel/update_edge_config_items'
|
||||
import { vercelUpdateEnvVarTool } from '@/tools/vercel/update_env_var'
|
||||
import { vercelUpdateProjectTool } from '@/tools/vercel/update_project'
|
||||
import { vercelUpdateProjectDomainTool } from '@/tools/vercel/update_project_domain'
|
||||
import { vercelVerifyProjectDomainTool } from '@/tools/vercel/verify_project_domain'
|
||||
|
||||
export {
|
||||
vercelListDeploymentsTool,
|
||||
vercelGetDeploymentTool,
|
||||
vercelCreateDeploymentTool,
|
||||
vercelCancelDeploymentTool,
|
||||
vercelDeleteDeploymentTool,
|
||||
vercelGetDeploymentEventsTool,
|
||||
vercelListDeploymentFilesTool,
|
||||
vercelPromoteDeploymentTool,
|
||||
vercelListProjectsTool,
|
||||
vercelGetProjectTool,
|
||||
vercelCreateProjectTool,
|
||||
vercelUpdateProjectTool,
|
||||
vercelDeleteProjectTool,
|
||||
vercelPauseProjectTool,
|
||||
vercelUnpauseProjectTool,
|
||||
vercelListProjectDomainsTool,
|
||||
vercelAddProjectDomainTool,
|
||||
vercelRemoveProjectDomainTool,
|
||||
vercelUpdateProjectDomainTool,
|
||||
vercelVerifyProjectDomainTool,
|
||||
vercelGetEnvVarsTool,
|
||||
vercelCreateEnvVarTool,
|
||||
vercelUpdateEnvVarTool,
|
||||
vercelDeleteEnvVarTool,
|
||||
vercelListDomainsTool,
|
||||
vercelGetDomainTool,
|
||||
vercelAddDomainTool,
|
||||
vercelDeleteDomainTool,
|
||||
vercelGetDomainConfigTool,
|
||||
vercelListDnsRecordsTool,
|
||||
vercelCreateDnsRecordTool,
|
||||
vercelUpdateDnsRecordTool,
|
||||
vercelDeleteDnsRecordTool,
|
||||
vercelListAliasesTool,
|
||||
vercelGetAliasTool,
|
||||
vercelCreateAliasTool,
|
||||
vercelDeleteAliasTool,
|
||||
vercelListEdgeConfigsTool,
|
||||
vercelGetEdgeConfigTool,
|
||||
vercelCreateEdgeConfigTool,
|
||||
vercelDeleteEdgeConfigTool,
|
||||
vercelGetEdgeConfigItemsTool,
|
||||
vercelUpdateEdgeConfigItemsTool,
|
||||
vercelListTeamsTool,
|
||||
vercelGetTeamTool,
|
||||
vercelListTeamMembersTool,
|
||||
vercelGetUserTool,
|
||||
vercelListWebhooksTool,
|
||||
vercelGetWebhookTool,
|
||||
vercelCreateWebhookTool,
|
||||
vercelDeleteWebhookTool,
|
||||
vercelCreateCheckTool,
|
||||
vercelGetCheckTool,
|
||||
vercelListChecksTool,
|
||||
vercelUpdateCheckTool,
|
||||
vercelRerequestCheckTool,
|
||||
}
|
||||
|
||||
export * from './types'
|
||||
@@ -0,0 +1,138 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelListAliasesParams, VercelListAliasesResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListAliasesTool: ToolConfig<VercelListAliasesParams, VercelListAliasesResponse> =
|
||||
{
|
||||
id: 'vercel_list_aliases',
|
||||
name: 'Vercel List Aliases',
|
||||
description: 'List aliases for a Vercel project or team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter aliases by project ID',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter aliases by domain',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of aliases to return',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListAliasesParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.projectId) query.set('projectId', params.projectId.trim())
|
||||
if (params.domain) query.set('domain', params.domain.trim())
|
||||
if (params.limit) query.set('limit', String(params.limit))
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v4/aliases${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListAliasesParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const aliases = (data.aliases ?? []).map((a: any) => ({
|
||||
uid: a.uid ?? null,
|
||||
alias: a.alias ?? null,
|
||||
deploymentId: a.deploymentId ?? null,
|
||||
projectId: a.projectId ?? null,
|
||||
createdAt: a.createdAt ?? null,
|
||||
updatedAt: a.updatedAt ?? null,
|
||||
deployment: a.deployment
|
||||
? { id: a.deployment.id ?? null, url: a.deployment.url ?? null }
|
||||
: null,
|
||||
redirect: a.redirect ?? null,
|
||||
redirectStatusCode: a.redirectStatusCode ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
aliases,
|
||||
count: aliases.length,
|
||||
hasMore: data.pagination?.next != null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
aliases: {
|
||||
type: 'array',
|
||||
description: 'List of aliases',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
uid: { type: 'string', description: 'Alias ID' },
|
||||
alias: { type: 'string', description: 'Alias hostname' },
|
||||
deploymentId: { type: 'string', description: 'Associated deployment ID' },
|
||||
projectId: { type: 'string', description: 'Associated project ID' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp in milliseconds' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp in milliseconds' },
|
||||
deployment: {
|
||||
type: 'object',
|
||||
description: 'Associated deployment (id, url)',
|
||||
optional: true,
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Deployment ID' },
|
||||
url: { type: 'string', description: 'Deployment URL' },
|
||||
},
|
||||
},
|
||||
redirect: {
|
||||
type: 'string',
|
||||
description: 'Target domain for redirect aliases',
|
||||
optional: true,
|
||||
},
|
||||
redirectStatusCode: {
|
||||
type: 'number',
|
||||
description: 'HTTP status code for redirect (301, 302, 307, or 308)',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of aliases returned',
|
||||
},
|
||||
hasMore: {
|
||||
type: 'boolean',
|
||||
description: 'Whether more aliases are available',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelListChecksParams, VercelListChecksResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListChecksTool: ToolConfig<VercelListChecksParams, VercelListChecksResponse> = {
|
||||
id: 'vercel_list_checks',
|
||||
name: 'Vercel List Checks',
|
||||
description: 'List all checks for a deployment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Deployment ID to list checks for',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListChecksParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/deployments/${params.deploymentId.trim()}/checks${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListChecksParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const checks = (data.checks ?? []).map((check: Record<string, unknown>) => ({
|
||||
id: check.id,
|
||||
name: check.name,
|
||||
status: check.status ?? 'registered',
|
||||
conclusion: check.conclusion ?? null,
|
||||
blocking: check.blocking ?? false,
|
||||
deploymentId: check.deploymentId,
|
||||
integrationId: check.integrationId ?? null,
|
||||
externalId: check.externalId ?? null,
|
||||
detailsUrl: check.detailsUrl ?? null,
|
||||
path: check.path ?? null,
|
||||
rerequestable: check.rerequestable ?? false,
|
||||
createdAt: check.createdAt,
|
||||
updatedAt: check.updatedAt,
|
||||
startedAt: check.startedAt ?? null,
|
||||
completedAt: check.completedAt ?? null,
|
||||
output: check.output ?? null,
|
||||
}))
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
checks,
|
||||
count: checks.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
checks: {
|
||||
type: 'array',
|
||||
description: 'List of deployment checks',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Check ID' },
|
||||
name: { type: 'string', description: 'Check name' },
|
||||
status: { type: 'string', description: 'Check status' },
|
||||
conclusion: { type: 'string', description: 'Check conclusion', optional: true },
|
||||
blocking: { type: 'boolean', description: 'Whether the check blocks the deployment' },
|
||||
deploymentId: { type: 'string', description: 'Associated deployment ID' },
|
||||
integrationId: {
|
||||
type: 'string',
|
||||
description: 'Associated integration ID',
|
||||
optional: true,
|
||||
},
|
||||
externalId: { type: 'string', description: 'External identifier', optional: true },
|
||||
detailsUrl: {
|
||||
type: 'string',
|
||||
description: 'URL with details about the check',
|
||||
optional: true,
|
||||
},
|
||||
path: { type: 'string', description: 'Page path being checked', optional: true },
|
||||
rerequestable: { type: 'boolean', description: 'Whether the check can be rerequested' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp' },
|
||||
startedAt: { type: 'number', description: 'Start timestamp', optional: true },
|
||||
completedAt: { type: 'number', description: 'Completion timestamp', optional: true },
|
||||
output: {
|
||||
type: 'json',
|
||||
description: 'Check result output including metrics',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Total number of checks' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelListDeploymentFilesParams,
|
||||
VercelListDeploymentFilesResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListDeploymentFilesTool: ToolConfig<
|
||||
VercelListDeploymentFilesParams,
|
||||
VercelListDeploymentFilesResponse
|
||||
> = {
|
||||
id: 'vercel_list_deployment_files',
|
||||
name: 'Vercel List Deployment Files',
|
||||
description: 'List files in a Vercel deployment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The deployment ID to list files for',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListDeploymentFilesParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v6/deployments/${params.deploymentId.trim()}/files${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListDeploymentFilesParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const files = (Array.isArray(data) ? data : (data.files ?? [])).map((f: any) => ({
|
||||
name: f.name ?? null,
|
||||
type: f.type ?? null,
|
||||
uid: f.uid ?? null,
|
||||
mode: f.mode ?? null,
|
||||
contentType: f.contentType ?? null,
|
||||
children: f.children ?? [],
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
files,
|
||||
count: files.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
files: {
|
||||
type: 'array',
|
||||
description: 'List of deployment files',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'The name of the file tree entry' },
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'File type: directory, file, symlink, lambda, middleware, or invalid',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique file identifier (only valid for file type)',
|
||||
optional: true,
|
||||
},
|
||||
mode: { type: 'number', description: 'File mode indicating file type and permissions' },
|
||||
contentType: {
|
||||
type: 'string',
|
||||
description: 'Content-type of the file (only valid for file type)',
|
||||
optional: true,
|
||||
},
|
||||
children: {
|
||||
type: 'array',
|
||||
description: 'Child files of the directory (only valid for directory type)',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'File name' },
|
||||
type: { type: 'string', description: 'Entry type' },
|
||||
uid: { type: 'string', description: 'File identifier', optional: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of files returned',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelListDeploymentsParams,
|
||||
VercelListDeploymentsResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListDeploymentsTool: ToolConfig<
|
||||
VercelListDeploymentsParams,
|
||||
VercelListDeploymentsResponse
|
||||
> = {
|
||||
id: 'vercel_list_deployments',
|
||||
name: 'Vercel List Deployments',
|
||||
description: 'List deployments for a Vercel project or team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter deployments by project ID or name',
|
||||
},
|
||||
target: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by environment: production or staging',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Filter by state: BUILDING, ERROR, INITIALIZING, QUEUED, READY, CANCELED, BLOCKED',
|
||||
},
|
||||
app: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by deployment name',
|
||||
},
|
||||
since: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Get deployments created after this JavaScript timestamp',
|
||||
},
|
||||
until: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Get deployments created before this JavaScript timestamp',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of deployments to return per request',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListDeploymentsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.projectId) query.set('projectId', params.projectId.trim())
|
||||
if (params.target) query.set('target', params.target)
|
||||
if (params.state) query.set('state', params.state)
|
||||
if (params.app) query.set('app', params.app.trim())
|
||||
if (params.since) query.set('since', String(params.since))
|
||||
if (params.until) query.set('until', String(params.until))
|
||||
if (params.limit) query.set('limit', String(params.limit))
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v7/deployments${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListDeploymentsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const deployments = (data.deployments ?? []).map((d: any) => ({
|
||||
uid: d.uid,
|
||||
name: d.name,
|
||||
url: d.url ?? null,
|
||||
state: d.state ?? d.readyState ?? 'UNKNOWN',
|
||||
target: d.target ?? null,
|
||||
created: d.created ?? d.createdAt,
|
||||
projectId: d.projectId ?? '',
|
||||
source: d.source ?? '',
|
||||
inspectorUrl: d.inspectorUrl ?? '',
|
||||
checksState: d.checksState ?? null,
|
||||
checksConclusion: d.checksConclusion ?? null,
|
||||
errorMessage: d.errorMessage ?? null,
|
||||
creator: {
|
||||
uid: d.creator?.uid ?? '',
|
||||
email: d.creator?.email ?? '',
|
||||
username: d.creator?.username ?? '',
|
||||
},
|
||||
meta: d.meta ?? {},
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deployments,
|
||||
count: deployments.length,
|
||||
hasMore: data.pagination?.next != null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deployments: {
|
||||
type: 'array',
|
||||
description: 'List of deployments',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
uid: { type: 'string', description: 'Unique deployment identifier' },
|
||||
name: { type: 'string', description: 'Deployment name' },
|
||||
url: { type: 'string', description: 'Deployment URL', optional: true },
|
||||
state: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Deployment state: BUILDING, ERROR, INITIALIZING, QUEUED, READY, CANCELED, DELETED, BLOCKED',
|
||||
},
|
||||
target: { type: 'string', description: 'Target environment', optional: true },
|
||||
created: { type: 'number', description: 'Creation timestamp' },
|
||||
projectId: { type: 'string', description: 'Associated project ID' },
|
||||
source: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Deployment source: api-trigger-git-deploy, cli, clone/repo, git, import, import/repo, redeploy, v0-web',
|
||||
},
|
||||
inspectorUrl: { type: 'string', description: 'Vercel inspector URL' },
|
||||
checksState: {
|
||||
type: 'string',
|
||||
description: 'Checks state: completed, registered, running',
|
||||
optional: true,
|
||||
},
|
||||
checksConclusion: {
|
||||
type: 'string',
|
||||
description: 'Checks conclusion: succeeded, failed, skipped, canceled',
|
||||
optional: true,
|
||||
},
|
||||
errorMessage: {
|
||||
type: 'string',
|
||||
description: 'Deployment error message',
|
||||
optional: true,
|
||||
},
|
||||
creator: {
|
||||
type: 'object',
|
||||
description: 'Creator information',
|
||||
properties: {
|
||||
uid: { type: 'string', description: 'Creator user ID' },
|
||||
email: { type: 'string', description: 'Creator email' },
|
||||
username: { type: 'string', description: 'Creator username' },
|
||||
},
|
||||
},
|
||||
meta: { type: 'object', description: 'Git provider metadata (key-value strings)' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of deployments returned',
|
||||
},
|
||||
hasMore: {
|
||||
type: 'boolean',
|
||||
description: 'Whether more deployments are available',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelListDnsRecordsParams, VercelListDnsRecordsResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListDnsRecordsTool: ToolConfig<
|
||||
VercelListDnsRecordsParams,
|
||||
VercelListDnsRecordsResponse
|
||||
> = {
|
||||
id: 'vercel_list_dns_records',
|
||||
name: 'Vercel List DNS Records',
|
||||
description: 'List all DNS records for a domain in a Vercel account',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The domain name to list records for',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of records to return',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListDnsRecordsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.limit) query.set('limit', String(params.limit))
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v5/domains/${params.domain.trim()}/records${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListDnsRecordsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const records = (data.records ?? []).map((r: any) => ({
|
||||
id: r.id ?? null,
|
||||
slug: r.slug ?? null,
|
||||
name: r.name ?? null,
|
||||
type: r.type ?? null,
|
||||
value: r.value ?? null,
|
||||
ttl: r.ttl ?? null,
|
||||
mxPriority: r.mxPriority ?? null,
|
||||
priority: r.priority ?? null,
|
||||
creator: r.creator ?? null,
|
||||
createdAt: r.createdAt ?? null,
|
||||
updatedAt: r.updatedAt ?? null,
|
||||
comment: r.comment ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
records,
|
||||
count: records.length,
|
||||
hasMore: data.pagination?.next != null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
records: {
|
||||
type: 'array',
|
||||
description: 'List of DNS records',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Record ID' },
|
||||
slug: { type: 'string', description: 'Record slug' },
|
||||
name: { type: 'string', description: 'Record name' },
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'Record type (A, AAAA, ALIAS, CAA, CNAME, HTTPS, MX, SRV, TXT, NS)',
|
||||
},
|
||||
value: { type: 'string', description: 'Record value' },
|
||||
ttl: { type: 'number', description: 'Time to live in seconds' },
|
||||
mxPriority: { type: 'number', description: 'MX record priority' },
|
||||
priority: { type: 'number', description: 'Record priority' },
|
||||
creator: { type: 'string', description: 'Creator identifier' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp' },
|
||||
comment: { type: 'string', description: 'Record comment' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of records returned',
|
||||
},
|
||||
hasMore: {
|
||||
type: 'boolean',
|
||||
description: 'Whether more records are available',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelListDomainsParams, VercelListDomainsResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListDomainsTool: ToolConfig<VercelListDomainsParams, VercelListDomainsResponse> =
|
||||
{
|
||||
id: 'vercel_list_domains',
|
||||
name: 'Vercel List Domains',
|
||||
description: 'List all domains in a Vercel account or team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of domains to return (default 20)',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListDomainsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.limit) query.set('limit', String(params.limit))
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v5/domains${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListDomainsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const domains = (data.domains ?? []).map((d: any) => ({
|
||||
id: d.id,
|
||||
name: d.name,
|
||||
verified: d.verified ?? false,
|
||||
createdAt: d.createdAt,
|
||||
expiresAt: d.expiresAt ?? null,
|
||||
serviceType: d.serviceType ?? 'external',
|
||||
nameservers: d.nameservers ?? [],
|
||||
intendedNameservers: d.intendedNameservers ?? [],
|
||||
renew: d.renew ?? false,
|
||||
boughtAt: d.boughtAt ?? null,
|
||||
transferredAt: d.transferredAt ?? null,
|
||||
creator: d.creator
|
||||
? {
|
||||
id: d.creator.id ?? null,
|
||||
username: d.creator.username ?? null,
|
||||
email: d.creator.email ?? null,
|
||||
}
|
||||
: null,
|
||||
customNameservers: d.customNameservers ?? [],
|
||||
userId: d.userId ?? null,
|
||||
teamId: d.teamId ?? null,
|
||||
transferStartedAt: d.transferStartedAt ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
domains,
|
||||
count: domains.length,
|
||||
hasMore: data.pagination?.next != null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
domains: {
|
||||
type: 'array',
|
||||
description: 'List of domains',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Domain ID' },
|
||||
name: { type: 'string', description: 'Domain name' },
|
||||
verified: { type: 'boolean', description: 'Whether domain is verified' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
expiresAt: { type: 'number', description: 'Expiration timestamp' },
|
||||
serviceType: { type: 'string', description: 'Service type (zeit.world, external, na)' },
|
||||
nameservers: {
|
||||
type: 'array',
|
||||
description: 'Current nameservers',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
intendedNameservers: {
|
||||
type: 'array',
|
||||
description: 'Intended nameservers',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
renew: { type: 'boolean', description: 'Whether auto-renewal is enabled' },
|
||||
boughtAt: { type: 'number', description: 'Purchase timestamp' },
|
||||
transferredAt: {
|
||||
type: 'number',
|
||||
description: 'Transfer completion timestamp',
|
||||
optional: true,
|
||||
},
|
||||
creator: {
|
||||
type: 'object',
|
||||
description: 'Domain creator (id, username, email)',
|
||||
optional: true,
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Creator ID' },
|
||||
username: { type: 'string', description: 'Creator username' },
|
||||
email: { type: 'string', description: 'Creator email' },
|
||||
},
|
||||
},
|
||||
customNameservers: {
|
||||
type: 'array',
|
||||
description: 'Custom nameservers',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
userId: { type: 'string', description: 'Owner user ID', optional: true },
|
||||
teamId: { type: 'string', description: 'Owner team ID', optional: true },
|
||||
transferStartedAt: {
|
||||
type: 'number',
|
||||
description: 'Transfer start timestamp',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of domains returned',
|
||||
},
|
||||
hasMore: {
|
||||
type: 'boolean',
|
||||
description: 'Whether more domains are available',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelListEdgeConfigsParams,
|
||||
VercelListEdgeConfigsResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListEdgeConfigsTool: ToolConfig<
|
||||
VercelListEdgeConfigsParams,
|
||||
VercelListEdgeConfigsResponse
|
||||
> = {
|
||||
id: 'vercel_list_edge_configs',
|
||||
name: 'Vercel List Edge Configs',
|
||||
description: 'List all Edge Config stores for a team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListEdgeConfigsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/edge-config${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListEdgeConfigsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const items = Array.isArray(data) ? data : (data.edgeConfigs ?? [])
|
||||
const edgeConfigs = items.map((ec: any) => ({
|
||||
id: ec.id ?? null,
|
||||
slug: ec.slug ?? null,
|
||||
ownerId: ec.ownerId ?? null,
|
||||
digest: ec.digest ?? null,
|
||||
createdAt: ec.createdAt ?? null,
|
||||
updatedAt: ec.updatedAt ?? null,
|
||||
itemCount: ec.itemCount ?? 0,
|
||||
sizeInBytes: ec.sizeInBytes ?? 0,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
edgeConfigs,
|
||||
count: edgeConfigs.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
edgeConfigs: {
|
||||
type: 'array',
|
||||
description: 'List of Edge Config stores',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Edge Config ID' },
|
||||
slug: { type: 'string', description: 'Edge Config slug' },
|
||||
ownerId: { type: 'string', description: 'Owner ID' },
|
||||
digest: { type: 'string', description: 'Content digest hash' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp' },
|
||||
itemCount: { type: 'number', description: 'Number of items' },
|
||||
sizeInBytes: { type: 'number', description: 'Size in bytes' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of Edge Configs returned',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelListProjectDomainsParams,
|
||||
VercelListProjectDomainsResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListProjectDomainsTool: ToolConfig<
|
||||
VercelListProjectDomainsParams,
|
||||
VercelListProjectDomainsResponse
|
||||
> = {
|
||||
id: 'vercel_list_project_domains',
|
||||
name: 'Vercel List Project Domains',
|
||||
description: 'List all domains for a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of domains to return',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListProjectDomainsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
if (params.limit) query.set('limit', String(params.limit))
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}/domains${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListProjectDomainsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const domains = (data.domains ?? []).map(
|
||||
(d: {
|
||||
name: string
|
||||
apexName: string
|
||||
projectId: string
|
||||
redirect: string | null
|
||||
redirectStatusCode: number | null
|
||||
verified: boolean
|
||||
gitBranch: string | null
|
||||
verification?: unknown[]
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}) => ({
|
||||
name: d.name,
|
||||
apexName: d.apexName,
|
||||
projectId: d.projectId,
|
||||
redirect: d.redirect ?? null,
|
||||
redirectStatusCode: d.redirectStatusCode ?? null,
|
||||
verified: d.verified,
|
||||
gitBranch: d.gitBranch ?? null,
|
||||
verification: d.verification ?? [],
|
||||
createdAt: d.createdAt,
|
||||
updatedAt: d.updatedAt,
|
||||
})
|
||||
)
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
domains,
|
||||
count: domains.length,
|
||||
hasMore: data.pagination?.next != null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
domains: {
|
||||
type: 'array',
|
||||
description: 'List of project domains',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Domain name' },
|
||||
apexName: { type: 'string', description: 'Apex domain name' },
|
||||
projectId: { type: 'string', description: 'Project ID the domain belongs to' },
|
||||
redirect: { type: 'string', description: 'Redirect target', optional: true },
|
||||
redirectStatusCode: {
|
||||
type: 'number',
|
||||
description: 'Redirect status code',
|
||||
optional: true,
|
||||
},
|
||||
verified: { type: 'boolean', description: 'Whether the domain is verified' },
|
||||
gitBranch: { type: 'string', description: 'Git branch for the domain', optional: true },
|
||||
verification: {
|
||||
type: 'array',
|
||||
description: 'Domain verification challenges (type, domain, value, reason)',
|
||||
optional: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: { type: 'string', description: 'Challenge type' },
|
||||
domain: { type: 'string', description: 'Domain to add the record to' },
|
||||
value: { type: 'string', description: 'Expected record value' },
|
||||
reason: { type: 'string', description: 'Why verification is needed' },
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of domains returned' },
|
||||
hasMore: { type: 'boolean', description: 'Whether more domains are available' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelListProjectsParams, VercelListProjectsResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListProjectsTool: ToolConfig<
|
||||
VercelListProjectsParams,
|
||||
VercelListProjectsResponse
|
||||
> = {
|
||||
id: 'vercel_list_projects',
|
||||
name: 'Vercel List Projects',
|
||||
description: 'List all projects in a Vercel team or account',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
search: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search projects by name',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of projects to return',
|
||||
},
|
||||
from: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
"Continuation token for pagination, taken from the previous response's pagination.next value. Query only projects updated after this timestamp or continuation token.",
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListProjectsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.search) query.set('search', params.search)
|
||||
if (params.limit) query.set('limit', String(params.limit))
|
||||
if (params.from) query.set('from', params.from.trim())
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v10/projects${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListProjectsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const projects = (data.projects ?? []).map((p: any) => ({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
framework: p.framework ?? null,
|
||||
rootDirectory: p.rootDirectory ?? null,
|
||||
nodeVersion: p.nodeVersion ?? null,
|
||||
createdAt: p.createdAt,
|
||||
updatedAt: p.updatedAt,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
projects,
|
||||
count: projects.length,
|
||||
hasMore: data.pagination?.next != null,
|
||||
nextFrom: data.pagination?.next != null ? String(data.pagination.next) : null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
projects: {
|
||||
type: 'array',
|
||||
description: 'List of projects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Project ID' },
|
||||
name: { type: 'string', description: 'Project name' },
|
||||
framework: { type: 'string', description: 'Framework', optional: true },
|
||||
rootDirectory: {
|
||||
type: 'string',
|
||||
description: 'Root directory of the project',
|
||||
optional: true,
|
||||
},
|
||||
nodeVersion: { type: 'string', description: 'Node.js version', optional: true },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of projects returned',
|
||||
},
|
||||
hasMore: {
|
||||
type: 'boolean',
|
||||
description: 'Whether more projects are available',
|
||||
},
|
||||
nextFrom: {
|
||||
type: 'string',
|
||||
description: 'Continuation token to pass as `from` to fetch the next page',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelListTeamMembersParams,
|
||||
VercelListTeamMembersResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListTeamMembersTool: ToolConfig<
|
||||
VercelListTeamMembersParams,
|
||||
VercelListTeamMembersResponse
|
||||
> = {
|
||||
id: 'vercel_list_team_members',
|
||||
name: 'Vercel List Team Members',
|
||||
description: 'List all members of a Vercel team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The team ID to list members for',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of members to return',
|
||||
},
|
||||
role: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Filter by role (OWNER, MEMBER, DEVELOPER, SECURITY, BILLING, VIEWER, VIEWER_FOR_PLUS, CONTRIBUTOR)',
|
||||
},
|
||||
since: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Timestamp in milliseconds to only include members added since then',
|
||||
},
|
||||
until: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Timestamp in milliseconds to only include members added until then',
|
||||
},
|
||||
search: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search team members by their name, username, and email',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListTeamMembersParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.limit) query.set('limit', String(params.limit))
|
||||
if (params.role) query.set('role', params.role.trim())
|
||||
if (params.since) query.set('since', String(params.since))
|
||||
if (params.until) query.set('until', String(params.until))
|
||||
if (params.search) query.set('search', params.search.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v3/teams/${params.teamId.trim()}/members${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListTeamMembersParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const members = (data.members ?? []).map((m: any) => ({
|
||||
uid: m.uid ?? null,
|
||||
email: m.email ?? null,
|
||||
username: m.username ?? null,
|
||||
name: m.name ?? null,
|
||||
avatar: m.avatar ?? null,
|
||||
role: m.role ?? null,
|
||||
confirmed: m.confirmed ?? false,
|
||||
createdAt: m.createdAt ?? null,
|
||||
accessRequestedAt: m.accessRequestedAt ?? null,
|
||||
isEnterpriseManaged: m.isEnterpriseManaged ?? null,
|
||||
joinedFrom: m.joinedFrom
|
||||
? {
|
||||
origin: m.joinedFrom.origin ?? null,
|
||||
}
|
||||
: null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
members,
|
||||
count: members.length,
|
||||
pagination: data.pagination
|
||||
? {
|
||||
hasNext: data.pagination.hasNext ?? false,
|
||||
count: data.pagination.count ?? 0,
|
||||
next: data.pagination.next ?? null,
|
||||
prev: data.pagination.prev ?? null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
members: {
|
||||
type: 'array',
|
||||
description: 'List of team members',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
uid: { type: 'string', description: 'Member user ID' },
|
||||
email: { type: 'string', description: 'Member email' },
|
||||
username: { type: 'string', description: 'Member username' },
|
||||
name: { type: 'string', description: 'Member full name' },
|
||||
avatar: { type: 'string', description: 'Avatar file ID' },
|
||||
role: { type: 'string', description: 'Member role' },
|
||||
confirmed: { type: 'boolean', description: 'Whether membership is confirmed' },
|
||||
createdAt: { type: 'number', description: 'Join timestamp in milliseconds' },
|
||||
accessRequestedAt: {
|
||||
type: 'number',
|
||||
description: 'When access was requested in milliseconds',
|
||||
optional: true,
|
||||
},
|
||||
isEnterpriseManaged: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the member is enterprise managed',
|
||||
optional: true,
|
||||
},
|
||||
joinedFrom: {
|
||||
type: 'object',
|
||||
description: 'Origin of how the member joined',
|
||||
properties: {
|
||||
origin: { type: 'string', description: 'Join origin identifier' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of members returned',
|
||||
},
|
||||
pagination: {
|
||||
type: 'object',
|
||||
description: 'Pagination information',
|
||||
properties: {
|
||||
hasNext: { type: 'boolean', description: 'Whether there are more pages' },
|
||||
count: { type: 'number', description: 'Items in current page' },
|
||||
next: {
|
||||
type: 'number',
|
||||
description: 'Timestamp to request the next page',
|
||||
optional: true,
|
||||
},
|
||||
prev: {
|
||||
type: 'number',
|
||||
description: 'Timestamp to request the previous page',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelListTeamsParams, VercelListTeamsResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListTeamsTool: ToolConfig<VercelListTeamsParams, VercelListTeamsResponse> = {
|
||||
id: 'vercel_list_teams',
|
||||
name: 'Vercel List Teams',
|
||||
description: 'List all teams in a Vercel account',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of teams to return',
|
||||
},
|
||||
since: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Timestamp in milliseconds to only include teams created since then',
|
||||
},
|
||||
until: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Timestamp in milliseconds to only include teams created until then',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListTeamsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.limit) query.set('limit', String(params.limit))
|
||||
if (params.since) query.set('since', String(params.since))
|
||||
if (params.until) query.set('until', String(params.until))
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v2/teams${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListTeamsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const teams = (data.teams ?? []).map((t: any) => ({
|
||||
id: t.id ?? null,
|
||||
slug: t.slug ?? null,
|
||||
name: t.name ?? null,
|
||||
avatar: t.avatar ?? null,
|
||||
description: t.description ?? null,
|
||||
stagingPrefix: t.stagingPrefix ?? null,
|
||||
createdAt: t.createdAt ?? null,
|
||||
updatedAt: t.updatedAt ?? null,
|
||||
creatorId: t.creatorId ?? null,
|
||||
membership: t.membership
|
||||
? {
|
||||
role: t.membership.role ?? null,
|
||||
confirmed: t.membership.confirmed ?? false,
|
||||
created: t.membership.created ?? null,
|
||||
uid: t.membership.uid ?? null,
|
||||
teamId: t.membership.teamId ?? null,
|
||||
}
|
||||
: null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
teams,
|
||||
count: teams.length,
|
||||
pagination: data.pagination
|
||||
? {
|
||||
count: data.pagination.count ?? 0,
|
||||
next: data.pagination.next ?? null,
|
||||
prev: data.pagination.prev ?? null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
teams: {
|
||||
type: 'array',
|
||||
description: 'List of teams',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Team ID' },
|
||||
slug: { type: 'string', description: 'Team slug' },
|
||||
name: { type: 'string', description: 'Team name' },
|
||||
avatar: { type: 'string', description: 'Avatar file ID' },
|
||||
description: { type: 'string', description: 'Short team description', optional: true },
|
||||
stagingPrefix: {
|
||||
type: 'string',
|
||||
description: 'Prefix used for staging deployments',
|
||||
optional: true,
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp in milliseconds' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp in milliseconds' },
|
||||
creatorId: { type: 'string', description: 'User ID of team creator' },
|
||||
membership: {
|
||||
type: 'object',
|
||||
description: 'Current user membership details',
|
||||
properties: {
|
||||
role: { type: 'string', description: 'Membership role' },
|
||||
confirmed: { type: 'boolean', description: 'Whether membership is confirmed' },
|
||||
created: { type: 'number', description: 'Membership creation timestamp' },
|
||||
uid: { type: 'string', description: 'User ID of the member' },
|
||||
teamId: { type: 'string', description: 'Team ID' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of teams returned',
|
||||
},
|
||||
pagination: {
|
||||
type: 'object',
|
||||
description: 'Pagination information',
|
||||
properties: {
|
||||
count: { type: 'number', description: 'Items in current page' },
|
||||
next: { type: 'number', description: 'Timestamp for next page request' },
|
||||
prev: { type: 'number', description: 'Timestamp for previous page request' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelListWebhooksParams, VercelListWebhooksResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelListWebhooksTool: ToolConfig<
|
||||
VercelListWebhooksParams,
|
||||
VercelListWebhooksResponse
|
||||
> = {
|
||||
id: 'vercel_list_webhooks',
|
||||
name: 'Vercel List Webhooks',
|
||||
description: 'List webhooks for a Vercel project or team',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter webhooks by project ID',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelListWebhooksParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.projectId) query.set('projectId', params.projectId.trim())
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/webhooks${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: VercelListWebhooksParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
const webhooks = (Array.isArray(data) ? data : []).map((w: any) => ({
|
||||
id: w.id ?? null,
|
||||
url: w.url ?? null,
|
||||
events: w.events ?? [],
|
||||
ownerId: w.ownerId ?? null,
|
||||
projectIds: w.projectIds ?? [],
|
||||
projectsMetadata: w.projectsMetadata ?? [],
|
||||
createdAt: w.createdAt ?? null,
|
||||
updatedAt: w.updatedAt ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
webhooks,
|
||||
count: webhooks.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
webhooks: {
|
||||
type: 'array',
|
||||
description: 'List of webhooks',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Webhook ID' },
|
||||
url: { type: 'string', description: 'Webhook URL' },
|
||||
events: {
|
||||
type: 'array',
|
||||
description: 'Events the webhook listens to',
|
||||
items: { type: 'string', description: 'Event name' },
|
||||
},
|
||||
ownerId: { type: 'string', description: 'Owner ID' },
|
||||
projectIds: {
|
||||
type: 'array',
|
||||
description: 'Associated project IDs',
|
||||
items: { type: 'string', description: 'Project ID' },
|
||||
},
|
||||
projectsMetadata: {
|
||||
type: 'array',
|
||||
description: 'Metadata for the projects the webhook is associated with',
|
||||
optional: true,
|
||||
items: { type: 'object', description: 'Project metadata' },
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: {
|
||||
type: 'number',
|
||||
description: 'Number of webhooks returned',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelPauseProjectParams, VercelPauseProjectResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelPauseProjectTool: ToolConfig<
|
||||
VercelPauseProjectParams,
|
||||
VercelPauseProjectResponse
|
||||
> = {
|
||||
id: 'vercel_pause_project',
|
||||
name: 'Vercel Pause Project',
|
||||
description: 'Pause a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelPauseProjectParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/projects/${params.projectId.trim()}/pause${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelPauseProjectParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json().catch(() => ({}))
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id ?? null,
|
||||
name: data.name ?? null,
|
||||
paused: data.paused ?? true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Project ID' },
|
||||
name: { type: 'string', description: 'Project name' },
|
||||
paused: { type: 'boolean', description: 'Whether the project is paused' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelPromoteDeploymentParams,
|
||||
VercelPromoteDeploymentResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelPromoteDeploymentTool: ToolConfig<
|
||||
VercelPromoteDeploymentParams,
|
||||
VercelPromoteDeploymentResponse
|
||||
> = {
|
||||
id: 'vercel_promote_deployment',
|
||||
name: 'Vercel Promote Deployment',
|
||||
description: 'Promote a deployment by pointing the production deployment to the given deployment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the deployment to promote to production',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelPromoteDeploymentParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v10/projects/${params.projectId.trim()}/promote/${params.deploymentId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelPromoteDeploymentParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
await response.json().catch(() => ({}))
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
promoted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
promoted: { type: 'boolean', description: 'Whether the deployment was promoted to production' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelRemoveProjectDomainParams,
|
||||
VercelRemoveProjectDomainResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelRemoveProjectDomainTool: ToolConfig<
|
||||
VercelRemoveProjectDomainParams,
|
||||
VercelRemoveProjectDomainResponse
|
||||
> = {
|
||||
id: 'vercel_remove_project_domain',
|
||||
name: 'Vercel Remove Project Domain',
|
||||
description: 'Remove a domain from a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain name to remove',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelRemoveProjectDomainParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}/domains/${params.domain.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: VercelRemoveProjectDomainParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async () => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: { type: 'boolean', description: 'Whether the domain was successfully removed' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelRerequestCheckParams, VercelRerequestCheckResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelRerequestCheckTool: ToolConfig<
|
||||
VercelRerequestCheckParams,
|
||||
VercelRerequestCheckResponse
|
||||
> = {
|
||||
id: 'vercel_rerequest_check',
|
||||
name: 'Vercel Rerequest Check',
|
||||
description: 'Rerequest a deployment check',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Deployment ID the check belongs to',
|
||||
},
|
||||
checkId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Check ID to rerequest',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
autoUpdate: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to mark the check as running immediately on rerequest',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelRerequestCheckParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
if (params.autoUpdate !== undefined) query.set('autoUpdate', String(params.autoUpdate))
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/deployments/${params.deploymentId.trim()}/checks/${params.checkId.trim()}/rerequest${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelRerequestCheckParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async () => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
rerequested: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
rerequested: { type: 'boolean', description: 'Whether the check was successfully rerequested' },
|
||||
},
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelUnpauseProjectParams, VercelUnpauseProjectResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelUnpauseProjectTool: ToolConfig<
|
||||
VercelUnpauseProjectParams,
|
||||
VercelUnpauseProjectResponse
|
||||
> = {
|
||||
id: 'vercel_unpause_project',
|
||||
name: 'Vercel Unpause Project',
|
||||
description: 'Unpause a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelUnpauseProjectParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/projects/${params.projectId.trim()}/unpause${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelUnpauseProjectParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json().catch(() => ({}))
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id ?? null,
|
||||
name: data.name ?? null,
|
||||
paused: data.paused ?? false,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Project ID' },
|
||||
name: { type: 'string', description: 'Project name' },
|
||||
paused: { type: 'boolean', description: 'Whether the project is paused' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelCheckResponse, VercelUpdateCheckParams } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelUpdateCheckTool: ToolConfig<VercelUpdateCheckParams, VercelCheckResponse> = {
|
||||
id: 'vercel_update_check',
|
||||
name: 'Vercel Update Check',
|
||||
description: 'Update an existing deployment check',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
deploymentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Deployment ID the check belongs to',
|
||||
},
|
||||
checkId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Check ID to update',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Updated name of the check',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Updated status: running or completed',
|
||||
},
|
||||
conclusion: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Check conclusion: canceled, failed, neutral, succeeded, or skipped',
|
||||
},
|
||||
detailsUrl: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'URL with details about the check',
|
||||
},
|
||||
externalId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'External identifier for the check',
|
||||
},
|
||||
path: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page path being checked',
|
||||
},
|
||||
output: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'JSON string with check output metrics',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelUpdateCheckParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/deployments/${params.deploymentId.trim()}/checks/${params.checkId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: VercelUpdateCheckParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelUpdateCheckParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.name) body.name = params.name.trim()
|
||||
if (params.status) body.status = params.status
|
||||
if (params.conclusion) body.conclusion = params.conclusion
|
||||
if (params.detailsUrl) body.detailsUrl = params.detailsUrl
|
||||
if (params.externalId) body.externalId = params.externalId
|
||||
if (params.path) body.path = params.path
|
||||
if (params.output) {
|
||||
try {
|
||||
body.output = JSON.parse(params.output)
|
||||
} catch {
|
||||
body.output = params.output
|
||||
}
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
status: data.status ?? 'registered',
|
||||
conclusion: data.conclusion ?? null,
|
||||
blocking: data.blocking ?? false,
|
||||
deploymentId: data.deploymentId,
|
||||
integrationId: data.integrationId ?? null,
|
||||
externalId: data.externalId ?? null,
|
||||
detailsUrl: data.detailsUrl ?? null,
|
||||
path: data.path ?? null,
|
||||
rerequestable: data.rerequestable ?? false,
|
||||
createdAt: data.createdAt,
|
||||
updatedAt: data.updatedAt,
|
||||
startedAt: data.startedAt ?? null,
|
||||
completedAt: data.completedAt ?? null,
|
||||
output: data.output ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Check ID' },
|
||||
name: { type: 'string', description: 'Check name' },
|
||||
status: { type: 'string', description: 'Check status: registered, running, or completed' },
|
||||
conclusion: {
|
||||
type: 'string',
|
||||
description: 'Check conclusion: canceled, failed, neutral, succeeded, skipped, or stale',
|
||||
optional: true,
|
||||
},
|
||||
blocking: { type: 'boolean', description: 'Whether the check blocks the deployment' },
|
||||
deploymentId: { type: 'string', description: 'Associated deployment ID' },
|
||||
integrationId: { type: 'string', description: 'Associated integration ID', optional: true },
|
||||
externalId: { type: 'string', description: 'External identifier', optional: true },
|
||||
detailsUrl: { type: 'string', description: 'URL with details about the check', optional: true },
|
||||
path: { type: 'string', description: 'Page path being checked', optional: true },
|
||||
rerequestable: { type: 'boolean', description: 'Whether the check can be rerequested' },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp in milliseconds' },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp in milliseconds' },
|
||||
startedAt: { type: 'number', description: 'Start timestamp in milliseconds', optional: true },
|
||||
completedAt: {
|
||||
type: 'number',
|
||||
description: 'Completion timestamp in milliseconds',
|
||||
optional: true,
|
||||
},
|
||||
output: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Check result output including metrics (FCP, LCP, CLS, TBT, virtualExperienceScore)',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelUpdateDnsRecordParams,
|
||||
VercelUpdateDnsRecordResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelUpdateDnsRecordTool: ToolConfig<
|
||||
VercelUpdateDnsRecordParams,
|
||||
VercelUpdateDnsRecordResponse
|
||||
> = {
|
||||
id: 'vercel_update_dns_record',
|
||||
name: 'Vercel Update DNS Record',
|
||||
description: 'Update an existing DNS record for a domain in a Vercel account',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
recordId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the DNS record to update',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The name of the DNS record',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The value of the DNS record',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'DNS record type (A, AAAA, ALIAS, CAA, CNAME, HTTPS, MX, SRV, TXT, NS)',
|
||||
},
|
||||
ttl: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Time to live in seconds (60 to 2147483647)',
|
||||
},
|
||||
mxPriority: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Priority for MX records',
|
||||
},
|
||||
srvTarget: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target hostname for SRV records (required together when updating SRV data)',
|
||||
},
|
||||
srvWeight: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Weight for SRV records (required together when updating SRV data)',
|
||||
},
|
||||
srvPort: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Port for SRV records (required together when updating SRV data)',
|
||||
},
|
||||
srvPriority: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Priority for SRV records (required together when updating SRV data)',
|
||||
},
|
||||
httpsTarget: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target hostname for HTTPS records (required together when updating HTTPS data)',
|
||||
},
|
||||
httpsPriority: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Priority for HTTPS records (required together when updating HTTPS data)',
|
||||
},
|
||||
httpsParams: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional service parameters for HTTPS records (e.g. "alpn=h2,h3")',
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'A comment to add context on what this DNS record is for (max 500 characters)',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelUpdateDnsRecordParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/domains/records/${params.recordId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: VercelUpdateDnsRecordParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelUpdateDnsRecordParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.name != null && params.name !== '') body.name = params.name
|
||||
const type =
|
||||
params.type != null && params.type !== '' ? params.type.trim().toUpperCase() : null
|
||||
if (type != null) body.type = type
|
||||
if (params.ttl != null) {
|
||||
const ttl = Number(params.ttl)
|
||||
if (!Number.isNaN(ttl)) body.ttl = ttl
|
||||
}
|
||||
|
||||
if (type === 'SRV') {
|
||||
body.srv = {
|
||||
target: params.srvTarget?.trim(),
|
||||
weight: params.srvWeight,
|
||||
port: params.srvPort,
|
||||
priority: params.srvPriority,
|
||||
}
|
||||
} else if (type === 'HTTPS') {
|
||||
body.https = {
|
||||
target: params.httpsTarget?.trim(),
|
||||
priority: params.httpsPriority,
|
||||
...(params.httpsParams ? { params: params.httpsParams.trim() } : {}),
|
||||
}
|
||||
} else {
|
||||
if (params.value != null && params.value !== '') body.value = params.value
|
||||
if (params.mxPriority != null) {
|
||||
const mxPriority = Number(params.mxPriority)
|
||||
if (!Number.isNaN(mxPriority)) body.mxPriority = mxPriority
|
||||
}
|
||||
}
|
||||
|
||||
if (params.comment != null && params.comment !== '') body.comment = params.comment
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json().catch(() => ({}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id ?? null,
|
||||
name: data.name ?? null,
|
||||
type: data.type ?? null,
|
||||
value: data.value ?? null,
|
||||
creator: data.creator ?? null,
|
||||
domain: data.domain ?? null,
|
||||
ttl: data.ttl ?? null,
|
||||
comment: data.comment ?? null,
|
||||
recordType: data.recordType ?? null,
|
||||
createdAt: data.createdAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'The DNS record ID', optional: true },
|
||||
name: { type: 'string', description: 'The name of the DNS record', optional: true },
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'The record class (record or record-sys)',
|
||||
optional: true,
|
||||
},
|
||||
value: { type: 'string', description: 'The value of the DNS record', optional: true },
|
||||
creator: { type: 'string', description: 'The creator of the DNS record', optional: true },
|
||||
domain: { type: 'string', description: 'The domain the record belongs to', optional: true },
|
||||
ttl: { type: 'number', description: 'Time to live in seconds', optional: true },
|
||||
comment: {
|
||||
type: 'string',
|
||||
description: 'Comment providing context for the record',
|
||||
optional: true,
|
||||
},
|
||||
recordType: {
|
||||
type: 'string',
|
||||
description: 'DNS record type (A, AAAA, ALIAS, CAA, CNAME, HTTPS, MX, NS, SRV, TXT)',
|
||||
optional: true,
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Timestamp of record creation', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelUpdateEdgeConfigItemsParams,
|
||||
VercelUpdateEdgeConfigItemsResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelUpdateEdgeConfigItemsTool: ToolConfig<
|
||||
VercelUpdateEdgeConfigItemsParams,
|
||||
VercelUpdateEdgeConfigItemsResponse
|
||||
> = {
|
||||
id: 'vercel_update_edge_config_items',
|
||||
name: 'Vercel Update Edge Config Items',
|
||||
description: 'Create, update, upsert, or delete items in an Edge Config store',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
edgeConfigId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Edge Config ID to update items in',
|
||||
},
|
||||
items: {
|
||||
type: 'json',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of operations: [{operation: "create"|"update"|"upsert"|"delete", key: string, value?: any}]',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelUpdateEdgeConfigItemsParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v1/edge-config/${params.edgeConfigId.trim()}/items${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: VercelUpdateEdgeConfigItemsParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelUpdateEdgeConfigItemsParams) => {
|
||||
const parsedItems = typeof params.items === 'string' ? JSON.parse(params.items) : params.items
|
||||
return { items: parsedItems }
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async () => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
status: 'ok',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Operation status',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelUpdateEnvVarParams, VercelUpdateEnvVarResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelUpdateEnvVarTool: ToolConfig<
|
||||
VercelUpdateEnvVarParams,
|
||||
VercelUpdateEnvVarResponse
|
||||
> = {
|
||||
id: 'vercel_update_env_var',
|
||||
name: 'Vercel Update Environment Variable',
|
||||
description: 'Update an environment variable for a Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
envId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Environment variable ID to update',
|
||||
},
|
||||
key: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New variable name',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New variable value',
|
||||
},
|
||||
target: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of target environments (production, preview, development)',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Variable type: system, encrypted, plain, or sensitive',
|
||||
},
|
||||
gitBranch: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Git branch to associate with the variable (requires target to include preview)',
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comment to add context to the variable (max 500 characters)',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelUpdateEnvVarParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}/env/${params.envId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: VercelUpdateEnvVarParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelUpdateEnvVarParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.key) body.key = params.key
|
||||
if (params.value) body.value = params.value
|
||||
if (params.target) body.target = params.target.split(',').map((t) => t.trim())
|
||||
if (params.type) body.type = params.type
|
||||
if (params.gitBranch) body.gitBranch = params.gitBranch
|
||||
if (params.comment) body.comment = params.comment
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
key: data.key,
|
||||
value: data.value ?? '',
|
||||
type: data.type ?? 'plain',
|
||||
target: data.target ?? [],
|
||||
gitBranch: data.gitBranch ?? null,
|
||||
comment: data.comment ?? null,
|
||||
createdAt: data.createdAt ?? null,
|
||||
updatedAt: data.updatedAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Environment variable ID',
|
||||
},
|
||||
key: {
|
||||
type: 'string',
|
||||
description: 'Variable name',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
description: 'Variable value',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'Variable type (secret, system, encrypted, plain, sensitive)',
|
||||
},
|
||||
target: {
|
||||
type: 'array',
|
||||
description: 'Target environments',
|
||||
items: { type: 'string', description: 'Environment name' },
|
||||
},
|
||||
gitBranch: {
|
||||
type: 'string',
|
||||
description: 'Git branch filter',
|
||||
optional: true,
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
description: 'Comment providing context for the variable',
|
||||
optional: true,
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp', optional: true },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { VercelUpdateProjectParams, VercelUpdateProjectResponse } from '@/tools/vercel/types'
|
||||
|
||||
export const vercelUpdateProjectTool: ToolConfig<
|
||||
VercelUpdateProjectParams,
|
||||
VercelUpdateProjectResponse
|
||||
> = {
|
||||
id: 'vercel_update_project',
|
||||
name: 'Vercel Update Project',
|
||||
description: 'Update an existing Vercel project',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New project name',
|
||||
},
|
||||
framework: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project framework (e.g. nextjs, remix, vite)',
|
||||
},
|
||||
buildCommand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom build command',
|
||||
},
|
||||
outputDirectory: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom output directory',
|
||||
},
|
||||
installCommand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom install command',
|
||||
},
|
||||
rootDirectory: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Subdirectory of the repository the project lives in (for monorepos)',
|
||||
},
|
||||
nodeVersion: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Node.js version to use (e.g. 22.x, 20.x, 18.x)',
|
||||
},
|
||||
devCommand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom dev server command',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelUpdateProjectParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: VercelUpdateProjectParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelUpdateProjectParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.name) body.name = params.name.trim()
|
||||
if (params.framework) body.framework = params.framework.trim()
|
||||
if (params.buildCommand) body.buildCommand = params.buildCommand.trim()
|
||||
if (params.outputDirectory) body.outputDirectory = params.outputDirectory.trim()
|
||||
if (params.installCommand) body.installCommand = params.installCommand.trim()
|
||||
if (params.rootDirectory) body.rootDirectory = params.rootDirectory.trim()
|
||||
if (params.nodeVersion) body.nodeVersion = params.nodeVersion.trim()
|
||||
if (params.devCommand) body.devCommand = params.devCommand.trim()
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
framework: data.framework ?? null,
|
||||
updatedAt: data.updatedAt,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Project ID' },
|
||||
name: { type: 'string', description: 'Project name' },
|
||||
framework: { type: 'string', description: 'Project framework', optional: true },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelUpdateProjectDomainParams,
|
||||
VercelUpdateProjectDomainResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelUpdateProjectDomainTool: ToolConfig<
|
||||
VercelUpdateProjectDomainParams,
|
||||
VercelUpdateProjectDomainResponse
|
||||
> = {
|
||||
id: 'vercel_update_project_domain',
|
||||
name: 'Vercel Update Project Domain',
|
||||
description: "Update a project domain's configuration on Vercel",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain name to update',
|
||||
},
|
||||
redirect: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target destination domain for redirect',
|
||||
},
|
||||
redirectStatusCode: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'HTTP status code for redirect (301, 302, 307, 308)',
|
||||
},
|
||||
gitBranch: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Git branch to link the domain to',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelUpdateProjectDomainParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}/domains/${params.domain.trim()}${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: VercelUpdateProjectDomainParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: VercelUpdateProjectDomainParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.redirect) body.redirect = params.redirect.trim()
|
||||
if (params.redirectStatusCode) body.redirectStatusCode = Number(params.redirectStatusCode)
|
||||
if (params.gitBranch) body.gitBranch = params.gitBranch.trim()
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
name: data.name,
|
||||
apexName: data.apexName,
|
||||
projectId: data.projectId,
|
||||
verified: data.verified,
|
||||
redirect: data.redirect ?? null,
|
||||
redirectStatusCode: data.redirectStatusCode ?? null,
|
||||
gitBranch: data.gitBranch ?? null,
|
||||
verification: data.verification ?? [],
|
||||
createdAt: data.createdAt ?? null,
|
||||
updatedAt: data.updatedAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
name: { type: 'string', description: 'Domain name' },
|
||||
apexName: { type: 'string', description: 'Apex domain name' },
|
||||
projectId: { type: 'string', description: 'Project ID the domain belongs to' },
|
||||
verified: { type: 'boolean', description: 'Whether the domain is verified' },
|
||||
redirect: { type: 'string', description: 'Redirect target domain', optional: true },
|
||||
redirectStatusCode: {
|
||||
type: 'number',
|
||||
description: 'HTTP status code for redirect (301, 302, 307, 308)',
|
||||
optional: true,
|
||||
},
|
||||
gitBranch: { type: 'string', description: 'Git branch for the domain', optional: true },
|
||||
verification: {
|
||||
type: 'array',
|
||||
description: 'Domain verification challenges (type, domain, value, reason)',
|
||||
optional: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: { type: 'string', description: 'Challenge type' },
|
||||
domain: { type: 'string', description: 'Domain to add the record to' },
|
||||
value: { type: 'string', description: 'Expected record value' },
|
||||
reason: { type: 'string', description: 'Why verification is needed' },
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Creation timestamp', optional: true },
|
||||
updatedAt: { type: 'number', description: 'Last updated timestamp', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
VercelVerifyProjectDomainParams,
|
||||
VercelVerifyProjectDomainResponse,
|
||||
} from '@/tools/vercel/types'
|
||||
|
||||
export const vercelVerifyProjectDomainTool: ToolConfig<
|
||||
VercelVerifyProjectDomainParams,
|
||||
VercelVerifyProjectDomainResponse
|
||||
> = {
|
||||
id: 'vercel_verify_project_domain',
|
||||
name: 'Vercel Verify Project Domain',
|
||||
description: 'Verify a Vercel project domain by checking its verification challenge',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vercel Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or name',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain name to verify',
|
||||
},
|
||||
teamId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team ID to scope the request',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Team slug to scope the request (alternative to teamId)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: VercelVerifyProjectDomainParams) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params.teamId) query.set('teamId', params.teamId.trim())
|
||||
if (params.slug) query.set('slug', params.slug.trim())
|
||||
const qs = query.toString()
|
||||
return `https://api.vercel.com/v9/projects/${params.projectId.trim()}/domains/${params.domain.trim()}/verify${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: VercelVerifyProjectDomainParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json().catch(() => ({}))
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
name: data.name ?? null,
|
||||
apexName: data.apexName ?? null,
|
||||
projectId: data.projectId ?? null,
|
||||
verified: data.verified ?? false,
|
||||
redirect: data.redirect ?? null,
|
||||
redirectStatusCode: data.redirectStatusCode ?? null,
|
||||
gitBranch: data.gitBranch ?? null,
|
||||
createdAt: data.createdAt ?? null,
|
||||
updatedAt: data.updatedAt ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
name: { type: 'string', description: 'Domain name' },
|
||||
apexName: { type: 'string', description: 'Apex domain name' },
|
||||
projectId: { type: 'string', description: 'Project ID' },
|
||||
verified: { type: 'boolean', description: 'Whether the domain is verified' },
|
||||
redirect: { type: 'string', description: 'Redirect target domain', optional: true },
|
||||
redirectStatusCode: {
|
||||
type: 'number',
|
||||
description: 'Redirect status code (301, 302, 307, 308)',
|
||||
optional: true,
|
||||
},
|
||||
gitBranch: { type: 'string', description: 'Git branch linked to the domain', optional: true },
|
||||
createdAt: { type: 'number', description: 'Creation timestamp', optional: true },
|
||||
updatedAt: { type: 'number', description: 'Last update timestamp', optional: true },
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user