@sentry/junior-vercel 0.222.0 → 0.223.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -9
- package/dist/index.js +264 -2
- package/dist/tools/actions.d.ts +274 -0
- package/dist/tools/deployment.d.ts +24 -0
- package/package.json +2 -2
- package/skills/vercel/SKILL.md +46 -57
- package/skills/vercel/SPEC.md +25 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @sentry/junior-vercel
|
|
2
2
|
|
|
3
|
-
`@sentry/junior-vercel` adds
|
|
3
|
+
`@sentry/junior-vercel` adds Vercel deployment and alias tools, plus CLI workflows for deployment and log investigation. Signed Vercel webhooks can also notify an existing Junior conversation when a deployment succeeds, fails, or is canceled.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -31,7 +31,7 @@ Set a Vercel token in the Junior deployment environment:
|
|
|
31
31
|
JUNIOR_VERCEL_TOKEN=...
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Use a Vercel service account or token with the
|
|
34
|
+
Use a Vercel service account or token with access to the required projects and actions. The same token handles reads and writes.
|
|
35
35
|
|
|
36
36
|
## Optional deployment webhooks
|
|
37
37
|
|
|
@@ -71,15 +71,36 @@ jr-rpc config set vercel.team sentry
|
|
|
71
71
|
|
|
72
72
|
These defaults are optional fallbacks. If a user names a different project, team, deployment, or URL in a request, Junior should follow the explicit request instead.
|
|
73
73
|
|
|
74
|
-
##
|
|
74
|
+
## Deployment and alias tools
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
`vercelPlugin()` registers:
|
|
77
77
|
|
|
78
|
-
- `
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
- `vercel_deploymentCreate`: deploy a branch, tag, or commit from an existing
|
|
79
|
+
project's linked GitHub repository. Preview is the default; Production is an
|
|
80
|
+
explicit target. An optional full commit SHA pins the source while preserving
|
|
81
|
+
branch context for Vercel integrations.
|
|
82
|
+
- `vercel_deploymentInspect`: inspect an ID or hostname and return deployment
|
|
83
|
+
identity, state, environment, and source when available.
|
|
84
|
+
- `vercel_aliasAssign`: assign a hostname to an exact deployment ID and read
|
|
85
|
+
back the alias. `matches` is false if it no longer points at that deployment.
|
|
86
|
+
- `vercel_aliasInspect`: return the alias's deployment ID or redirect.
|
|
87
|
+
- `vercel_deploymentDelete`: delete an exact deployment ID when requested.
|
|
82
88
|
|
|
83
|
-
|
|
89
|
+
Tools use the host-managed token and normal Guardian review. Vercel permissions
|
|
90
|
+
still apply.
|
|
91
|
+
|
|
92
|
+
Tools return selected fields, not full deployment records that may contain
|
|
93
|
+
secrets. Creates start a build; inspect readiness before using the deployment.
|
|
94
|
+
Check provider state before retrying a write whose response was lost.
|
|
95
|
+
|
|
96
|
+
Use the Vercel CLI for logs, local source uploads, and other operations not
|
|
97
|
+
covered by the tools.
|
|
98
|
+
|
|
99
|
+
## Limits
|
|
100
|
+
|
|
101
|
+
Alias checks are not locks. Moving an alias does not stop older workers or
|
|
102
|
+
identify which build handled a delayed event. Builds inherit project settings
|
|
103
|
+
and credentials and may run migrations. The plugin does not isolate databases
|
|
104
|
+
or other state. Preview deployments do not run Vercel Cron.
|
|
84
105
|
|
|
85
106
|
Full setup guide: https://junior.sentry.dev/extend/vercel-plugin/
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,267 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
defineJuniorPlugin
|
|
12
12
|
} from "@sentry/junior-plugin-api";
|
|
13
|
+
|
|
14
|
+
// src/tools/actions.ts
|
|
15
|
+
import {
|
|
16
|
+
definePluginTool,
|
|
17
|
+
PluginToolInputError,
|
|
18
|
+
pluginToolOutputSchema
|
|
19
|
+
} from "@sentry/junior-plugin-api";
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
var text = z.string().trim().min(1);
|
|
22
|
+
var team = text.describe(
|
|
23
|
+
"Vercel team slug or team_ ID. Omit for the token's default account."
|
|
24
|
+
).optional();
|
|
25
|
+
var deploymentId = z.string().regex(/^dpl_[a-zA-Z0-9]+$/).describe("Exact Vercel deployment ID, not an alias.");
|
|
26
|
+
var aliasName = z.string().regex(/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?\.[a-z]{2,}$/).describe("Alias hostname without a scheme or path.");
|
|
27
|
+
var deploymentSchema = z.object({
|
|
28
|
+
id: text,
|
|
29
|
+
url: text,
|
|
30
|
+
readyState: text,
|
|
31
|
+
target: z.string().nullable().optional(),
|
|
32
|
+
projectId: text.optional(),
|
|
33
|
+
gitSource: z.object({ sha: text.optional(), ref: text.optional() }).nullable().optional()
|
|
34
|
+
});
|
|
35
|
+
var deploymentOutput = pluginToolOutputSchema.extend({
|
|
36
|
+
target: z.literal("deployment"),
|
|
37
|
+
deploymentId: text,
|
|
38
|
+
url: text,
|
|
39
|
+
state: text,
|
|
40
|
+
deploymentTarget: z.string().nullable(),
|
|
41
|
+
projectId: text.nullable(),
|
|
42
|
+
commitSha: text.nullable(),
|
|
43
|
+
ref: text.nullable()
|
|
44
|
+
});
|
|
45
|
+
var aliasSchema = z.object({
|
|
46
|
+
alias: text,
|
|
47
|
+
deploymentId: text.nullable(),
|
|
48
|
+
redirect: text.nullable().optional()
|
|
49
|
+
});
|
|
50
|
+
var aliasOutput = pluginToolOutputSchema.extend({
|
|
51
|
+
target: z.literal("alias"),
|
|
52
|
+
alias: text,
|
|
53
|
+
deploymentId: text.nullable(),
|
|
54
|
+
redirect: text.nullable()
|
|
55
|
+
});
|
|
56
|
+
function deploymentResult(data) {
|
|
57
|
+
const value = deploymentSchema.parse(data);
|
|
58
|
+
return {
|
|
59
|
+
target: "deployment",
|
|
60
|
+
deploymentId: value.id,
|
|
61
|
+
url: `https://${value.url}`,
|
|
62
|
+
state: value.readyState,
|
|
63
|
+
deploymentTarget: value.target ?? null,
|
|
64
|
+
projectId: value.projectId ?? null,
|
|
65
|
+
commitSha: value.gitSource?.sha ?? null,
|
|
66
|
+
ref: value.gitSource?.ref ?? null
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function createVercelActionTools(ctx) {
|
|
70
|
+
async function request(operation, path, scope, method = "GET", body) {
|
|
71
|
+
const url = new URL(path, "https://api.vercel.com");
|
|
72
|
+
if (scope)
|
|
73
|
+
url.searchParams.set(
|
|
74
|
+
scope.startsWith("team_") ? "teamId" : "slug",
|
|
75
|
+
scope
|
|
76
|
+
);
|
|
77
|
+
const init = {
|
|
78
|
+
method,
|
|
79
|
+
redirect: "error",
|
|
80
|
+
signal: AbortSignal.timeout(3e4)
|
|
81
|
+
};
|
|
82
|
+
if (body !== void 0) {
|
|
83
|
+
init.headers = { "Content-Type": "application/json" };
|
|
84
|
+
init.body = JSON.stringify(body);
|
|
85
|
+
}
|
|
86
|
+
const response = await ctx.egress.fetch({
|
|
87
|
+
provider: "vercel",
|
|
88
|
+
operation,
|
|
89
|
+
request: new Request(url, init)
|
|
90
|
+
});
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
const message = `${operation} failed with HTTP ${response.status}`;
|
|
93
|
+
if (response.status === 400 || response.status === 404)
|
|
94
|
+
throw new PluginToolInputError(message);
|
|
95
|
+
throw new Error(message);
|
|
96
|
+
}
|
|
97
|
+
if (response.status === 204) return void 0;
|
|
98
|
+
return response.json();
|
|
99
|
+
}
|
|
100
|
+
async function inspectAlias(alias, scope) {
|
|
101
|
+
const result = aliasSchema.parse(
|
|
102
|
+
await request(
|
|
103
|
+
"vercel.alias.get",
|
|
104
|
+
`/v4/aliases/${encodeURIComponent(alias)}`,
|
|
105
|
+
scope
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
return {
|
|
109
|
+
target: "alias",
|
|
110
|
+
alias: result.alias,
|
|
111
|
+
deploymentId: result.deploymentId,
|
|
112
|
+
redirect: result.redirect ?? null
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
deploymentCreate: definePluginTool({
|
|
117
|
+
annotations: {
|
|
118
|
+
destructiveHint: true,
|
|
119
|
+
idempotentHint: false,
|
|
120
|
+
openWorldHint: true,
|
|
121
|
+
readOnlyHint: false
|
|
122
|
+
},
|
|
123
|
+
description: "Start a deployment from a Vercel project's linked GitHub repository. Uses project build settings and environment credentials, so builds may run migrations. Returns the new deployment; inspect it to check readiness.",
|
|
124
|
+
inputSchema: z.object({
|
|
125
|
+
project: text.describe("Existing Vercel project name or ID."),
|
|
126
|
+
team,
|
|
127
|
+
ref: text.describe(
|
|
128
|
+
"Git branch, tag, or full commit SHA in the project's linked repository."
|
|
129
|
+
),
|
|
130
|
+
commitSha: z.string().regex(/^[a-f0-9]{40}$/i).describe(
|
|
131
|
+
"Full commit SHA to pin the source while retaining branch context in ref."
|
|
132
|
+
).optional(),
|
|
133
|
+
target: z.enum(["preview", "production"]).describe("Deployment environment; defaults to preview.").optional()
|
|
134
|
+
}).strict(),
|
|
135
|
+
outputSchema: deploymentOutput,
|
|
136
|
+
async execute(input) {
|
|
137
|
+
const project = z.object({
|
|
138
|
+
id: text,
|
|
139
|
+
name: text,
|
|
140
|
+
link: z.object({
|
|
141
|
+
type: text,
|
|
142
|
+
repoId: z.union([text, z.number()]).optional()
|
|
143
|
+
}).nullable().optional()
|
|
144
|
+
}).parse(
|
|
145
|
+
await request(
|
|
146
|
+
"vercel.project.get",
|
|
147
|
+
`/v9/projects/${encodeURIComponent(input.project)}`,
|
|
148
|
+
input.team
|
|
149
|
+
)
|
|
150
|
+
);
|
|
151
|
+
if (project.link?.type !== "github" || !project.link.repoId)
|
|
152
|
+
throw new PluginToolInputError(
|
|
153
|
+
"This deployment tool requires a project linked to GitHub. Use the Vercel CLI for other source types."
|
|
154
|
+
);
|
|
155
|
+
const gitSource = {
|
|
156
|
+
type: "github",
|
|
157
|
+
repoId: project.link.repoId,
|
|
158
|
+
ref: input.ref,
|
|
159
|
+
sha: input.commitSha?.toLowerCase()
|
|
160
|
+
};
|
|
161
|
+
return deploymentResult(
|
|
162
|
+
await request(
|
|
163
|
+
"vercel.deployment.create",
|
|
164
|
+
"/v13/deployments",
|
|
165
|
+
input.team,
|
|
166
|
+
"POST",
|
|
167
|
+
{
|
|
168
|
+
name: project.name,
|
|
169
|
+
project: project.id,
|
|
170
|
+
// Vercel uses an omitted target for Preview, not "preview".
|
|
171
|
+
target: input.target === "production" ? "production" : void 0,
|
|
172
|
+
gitSource
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}),
|
|
178
|
+
deploymentInspect: definePluginTool({
|
|
179
|
+
annotations: {
|
|
180
|
+
destructiveHint: false,
|
|
181
|
+
idempotentHint: true,
|
|
182
|
+
openWorldHint: true,
|
|
183
|
+
readOnlyHint: true
|
|
184
|
+
},
|
|
185
|
+
description: "Inspect a Vercel deployment by ID or hostname. Returns its ID, state, environment, and Git source when available. Use the CLI for logs.",
|
|
186
|
+
inputSchema: z.object({
|
|
187
|
+
deployment: text.describe(
|
|
188
|
+
"Deployment ID or hostname, without a scheme or path."
|
|
189
|
+
),
|
|
190
|
+
team
|
|
191
|
+
}).strict(),
|
|
192
|
+
outputSchema: deploymentOutput,
|
|
193
|
+
async execute(input) {
|
|
194
|
+
return deploymentResult(
|
|
195
|
+
await request(
|
|
196
|
+
"vercel.deployment.get",
|
|
197
|
+
`/v13/deployments/${encodeURIComponent(input.deployment)}?withGitRepoInfo=true`,
|
|
198
|
+
input.team
|
|
199
|
+
)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}),
|
|
203
|
+
aliasAssign: definePluginTool({
|
|
204
|
+
annotations: {
|
|
205
|
+
destructiveHint: true,
|
|
206
|
+
idempotentHint: true,
|
|
207
|
+
openWorldHint: true,
|
|
208
|
+
readOnlyHint: false
|
|
209
|
+
},
|
|
210
|
+
description: "Assign an alias hostname to a deployment ID. This can replace live traffic. Reads the alias back and returns matches=false if its target changed or it redirects.",
|
|
211
|
+
inputSchema: z.object({ deploymentId, alias: aliasName, team }).strict(),
|
|
212
|
+
outputSchema: aliasOutput.extend({ matches: z.boolean() }),
|
|
213
|
+
async execute(input) {
|
|
214
|
+
await request(
|
|
215
|
+
"vercel.alias.assign",
|
|
216
|
+
`/v2/deployments/${encodeURIComponent(input.deploymentId)}/aliases`,
|
|
217
|
+
input.team,
|
|
218
|
+
"POST",
|
|
219
|
+
{ alias: input.alias }
|
|
220
|
+
);
|
|
221
|
+
const result = await inspectAlias(input.alias, input.team);
|
|
222
|
+
return {
|
|
223
|
+
...result,
|
|
224
|
+
matches: result.deploymentId === input.deploymentId && !result.redirect
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}),
|
|
228
|
+
aliasInspect: definePluginTool({
|
|
229
|
+
annotations: {
|
|
230
|
+
destructiveHint: false,
|
|
231
|
+
idempotentHint: true,
|
|
232
|
+
openWorldHint: true,
|
|
233
|
+
readOnlyHint: true
|
|
234
|
+
},
|
|
235
|
+
description: "Read a Vercel alias's current deployment ID or redirect.",
|
|
236
|
+
inputSchema: z.object({ alias: aliasName, team }).strict(),
|
|
237
|
+
outputSchema: aliasOutput,
|
|
238
|
+
async execute(input) {
|
|
239
|
+
return inspectAlias(input.alias, input.team);
|
|
240
|
+
}
|
|
241
|
+
}),
|
|
242
|
+
deploymentDelete: definePluginTool({
|
|
243
|
+
annotations: {
|
|
244
|
+
destructiveHint: true,
|
|
245
|
+
idempotentHint: true,
|
|
246
|
+
openWorldHint: true,
|
|
247
|
+
readOnlyHint: false
|
|
248
|
+
},
|
|
249
|
+
description: "Delete a Vercel deployment by ID. This can remove a live deployment. Does not delete its database or other external state.",
|
|
250
|
+
inputSchema: z.object({ deploymentId, team }).strict(),
|
|
251
|
+
outputSchema: pluginToolOutputSchema.extend({
|
|
252
|
+
target: z.literal("deployment"),
|
|
253
|
+
deploymentId: text,
|
|
254
|
+
deleted: z.literal(true)
|
|
255
|
+
}),
|
|
256
|
+
async execute(input) {
|
|
257
|
+
await request(
|
|
258
|
+
"vercel.deployment.delete",
|
|
259
|
+
`/v13/deployments/${encodeURIComponent(input.deploymentId)}`,
|
|
260
|
+
input.team,
|
|
261
|
+
"DELETE"
|
|
262
|
+
);
|
|
263
|
+
return {
|
|
264
|
+
target: "deployment",
|
|
265
|
+
deploymentId: input.deploymentId,
|
|
266
|
+
deleted: true
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/index.ts
|
|
13
274
|
function vercelPlugin() {
|
|
14
275
|
return defineJuniorPlugin({
|
|
15
276
|
packageName: "@sentry/junior-vercel",
|
|
@@ -31,7 +292,7 @@ function vercelPlugin() {
|
|
|
31
292
|
VERCEL_TOKEN: "host_managed_credential"
|
|
32
293
|
},
|
|
33
294
|
configKeys: ["project", "team"],
|
|
34
|
-
description: "
|
|
295
|
+
description: "Deploy and inspect Vercel projects, manage aliases, query logs, and monitor outcomes",
|
|
35
296
|
displayName: "Vercel",
|
|
36
297
|
domains: ["api.vercel.com"],
|
|
37
298
|
envVars: {
|
|
@@ -58,7 +319,8 @@ function vercelPlugin() {
|
|
|
58
319
|
},
|
|
59
320
|
tools(ctx) {
|
|
60
321
|
return {
|
|
61
|
-
deployment: createVercelDeploymentTool(ctx)
|
|
322
|
+
deployment: createVercelDeploymentTool(ctx),
|
|
323
|
+
...createVercelActionTools(ctx)
|
|
62
324
|
};
|
|
63
325
|
}
|
|
64
326
|
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { type ToolRegistrationHookContext } from "@sentry/junior-plugin-api";
|
|
2
|
+
/** Provide Vercel deployment and alias operations. */
|
|
3
|
+
export declare function createVercelActionTools(ctx: ToolRegistrationHookContext): {
|
|
4
|
+
deploymentCreate: import("@sentry/junior-plugin-api").PluginToolDefinition<{
|
|
5
|
+
project: string;
|
|
6
|
+
ref: string;
|
|
7
|
+
team?: string | undefined;
|
|
8
|
+
commitSha?: string | undefined;
|
|
9
|
+
target?: "preview" | "production" | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
[x: string]: unknown;
|
|
12
|
+
target: "deployment";
|
|
13
|
+
deploymentId: string;
|
|
14
|
+
url: string;
|
|
15
|
+
state: string;
|
|
16
|
+
deploymentTarget: string | null;
|
|
17
|
+
projectId: string | null;
|
|
18
|
+
commitSha: string | null;
|
|
19
|
+
ref: string | null;
|
|
20
|
+
objectAnnotations?: {
|
|
21
|
+
kind: "object";
|
|
22
|
+
key: string;
|
|
23
|
+
label: string;
|
|
24
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
25
|
+
title: string;
|
|
26
|
+
url: string | null;
|
|
27
|
+
description?: string | undefined;
|
|
28
|
+
status?: string | undefined;
|
|
29
|
+
trigger?: string | undefined;
|
|
30
|
+
warning?: string | undefined;
|
|
31
|
+
}[] | undefined;
|
|
32
|
+
truncated?: boolean | undefined;
|
|
33
|
+
continuation?: {
|
|
34
|
+
arguments: Record<string, unknown>;
|
|
35
|
+
reason?: string | undefined;
|
|
36
|
+
} | undefined;
|
|
37
|
+
}, {
|
|
38
|
+
[x: string]: unknown;
|
|
39
|
+
target: "deployment";
|
|
40
|
+
deploymentId: string;
|
|
41
|
+
url: string;
|
|
42
|
+
state: string;
|
|
43
|
+
deploymentTarget: string | null;
|
|
44
|
+
projectId: string | null;
|
|
45
|
+
commitSha: string | null;
|
|
46
|
+
ref: string | null;
|
|
47
|
+
objectAnnotations?: {
|
|
48
|
+
kind: "object";
|
|
49
|
+
key: string;
|
|
50
|
+
label: string;
|
|
51
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
52
|
+
title: string;
|
|
53
|
+
url: string | null;
|
|
54
|
+
description?: string | undefined;
|
|
55
|
+
status?: string | undefined;
|
|
56
|
+
trigger?: string | undefined;
|
|
57
|
+
warning?: string | undefined;
|
|
58
|
+
}[] | undefined;
|
|
59
|
+
truncated?: boolean | undefined;
|
|
60
|
+
continuation?: {
|
|
61
|
+
arguments: Record<string, unknown>;
|
|
62
|
+
reason?: string | undefined;
|
|
63
|
+
} | undefined;
|
|
64
|
+
}>;
|
|
65
|
+
deploymentInspect: import("@sentry/junior-plugin-api").PluginToolDefinition<{
|
|
66
|
+
deployment: string;
|
|
67
|
+
team?: string | undefined;
|
|
68
|
+
}, {
|
|
69
|
+
[x: string]: unknown;
|
|
70
|
+
target: "deployment";
|
|
71
|
+
deploymentId: string;
|
|
72
|
+
url: string;
|
|
73
|
+
state: string;
|
|
74
|
+
deploymentTarget: string | null;
|
|
75
|
+
projectId: string | null;
|
|
76
|
+
commitSha: string | null;
|
|
77
|
+
ref: string | null;
|
|
78
|
+
objectAnnotations?: {
|
|
79
|
+
kind: "object";
|
|
80
|
+
key: string;
|
|
81
|
+
label: string;
|
|
82
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
83
|
+
title: string;
|
|
84
|
+
url: string | null;
|
|
85
|
+
description?: string | undefined;
|
|
86
|
+
status?: string | undefined;
|
|
87
|
+
trigger?: string | undefined;
|
|
88
|
+
warning?: string | undefined;
|
|
89
|
+
}[] | undefined;
|
|
90
|
+
truncated?: boolean | undefined;
|
|
91
|
+
continuation?: {
|
|
92
|
+
arguments: Record<string, unknown>;
|
|
93
|
+
reason?: string | undefined;
|
|
94
|
+
} | undefined;
|
|
95
|
+
}, {
|
|
96
|
+
[x: string]: unknown;
|
|
97
|
+
target: "deployment";
|
|
98
|
+
deploymentId: string;
|
|
99
|
+
url: string;
|
|
100
|
+
state: string;
|
|
101
|
+
deploymentTarget: string | null;
|
|
102
|
+
projectId: string | null;
|
|
103
|
+
commitSha: string | null;
|
|
104
|
+
ref: string | null;
|
|
105
|
+
objectAnnotations?: {
|
|
106
|
+
kind: "object";
|
|
107
|
+
key: string;
|
|
108
|
+
label: string;
|
|
109
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
110
|
+
title: string;
|
|
111
|
+
url: string | null;
|
|
112
|
+
description?: string | undefined;
|
|
113
|
+
status?: string | undefined;
|
|
114
|
+
trigger?: string | undefined;
|
|
115
|
+
warning?: string | undefined;
|
|
116
|
+
}[] | undefined;
|
|
117
|
+
truncated?: boolean | undefined;
|
|
118
|
+
continuation?: {
|
|
119
|
+
arguments: Record<string, unknown>;
|
|
120
|
+
reason?: string | undefined;
|
|
121
|
+
} | undefined;
|
|
122
|
+
}>;
|
|
123
|
+
aliasAssign: import("@sentry/junior-plugin-api").PluginToolDefinition<{
|
|
124
|
+
deploymentId: string;
|
|
125
|
+
alias: string;
|
|
126
|
+
team?: string | undefined;
|
|
127
|
+
}, {
|
|
128
|
+
[x: string]: unknown;
|
|
129
|
+
target: "alias";
|
|
130
|
+
alias: string;
|
|
131
|
+
deploymentId: string | null;
|
|
132
|
+
redirect: string | null;
|
|
133
|
+
matches: boolean;
|
|
134
|
+
objectAnnotations?: {
|
|
135
|
+
kind: "object";
|
|
136
|
+
key: string;
|
|
137
|
+
label: string;
|
|
138
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
139
|
+
title: string;
|
|
140
|
+
url: string | null;
|
|
141
|
+
description?: string | undefined;
|
|
142
|
+
status?: string | undefined;
|
|
143
|
+
trigger?: string | undefined;
|
|
144
|
+
warning?: string | undefined;
|
|
145
|
+
}[] | undefined;
|
|
146
|
+
truncated?: boolean | undefined;
|
|
147
|
+
continuation?: {
|
|
148
|
+
arguments: Record<string, unknown>;
|
|
149
|
+
reason?: string | undefined;
|
|
150
|
+
} | undefined;
|
|
151
|
+
}, {
|
|
152
|
+
[x: string]: unknown;
|
|
153
|
+
target: "alias";
|
|
154
|
+
alias: string;
|
|
155
|
+
deploymentId: string | null;
|
|
156
|
+
redirect: string | null;
|
|
157
|
+
matches: boolean;
|
|
158
|
+
objectAnnotations?: {
|
|
159
|
+
kind: "object";
|
|
160
|
+
key: string;
|
|
161
|
+
label: string;
|
|
162
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
163
|
+
title: string;
|
|
164
|
+
url: string | null;
|
|
165
|
+
description?: string | undefined;
|
|
166
|
+
status?: string | undefined;
|
|
167
|
+
trigger?: string | undefined;
|
|
168
|
+
warning?: string | undefined;
|
|
169
|
+
}[] | undefined;
|
|
170
|
+
truncated?: boolean | undefined;
|
|
171
|
+
continuation?: {
|
|
172
|
+
arguments: Record<string, unknown>;
|
|
173
|
+
reason?: string | undefined;
|
|
174
|
+
} | undefined;
|
|
175
|
+
}>;
|
|
176
|
+
aliasInspect: import("@sentry/junior-plugin-api").PluginToolDefinition<{
|
|
177
|
+
alias: string;
|
|
178
|
+
team?: string | undefined;
|
|
179
|
+
}, {
|
|
180
|
+
[x: string]: unknown;
|
|
181
|
+
target: "alias";
|
|
182
|
+
alias: string;
|
|
183
|
+
deploymentId: string | null;
|
|
184
|
+
redirect: string | null;
|
|
185
|
+
objectAnnotations?: {
|
|
186
|
+
kind: "object";
|
|
187
|
+
key: string;
|
|
188
|
+
label: string;
|
|
189
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
190
|
+
title: string;
|
|
191
|
+
url: string | null;
|
|
192
|
+
description?: string | undefined;
|
|
193
|
+
status?: string | undefined;
|
|
194
|
+
trigger?: string | undefined;
|
|
195
|
+
warning?: string | undefined;
|
|
196
|
+
}[] | undefined;
|
|
197
|
+
truncated?: boolean | undefined;
|
|
198
|
+
continuation?: {
|
|
199
|
+
arguments: Record<string, unknown>;
|
|
200
|
+
reason?: string | undefined;
|
|
201
|
+
} | undefined;
|
|
202
|
+
}, {
|
|
203
|
+
[x: string]: unknown;
|
|
204
|
+
target: "alias";
|
|
205
|
+
alias: string;
|
|
206
|
+
deploymentId: string | null;
|
|
207
|
+
redirect: string | null;
|
|
208
|
+
objectAnnotations?: {
|
|
209
|
+
kind: "object";
|
|
210
|
+
key: string;
|
|
211
|
+
label: string;
|
|
212
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
213
|
+
title: string;
|
|
214
|
+
url: string | null;
|
|
215
|
+
description?: string | undefined;
|
|
216
|
+
status?: string | undefined;
|
|
217
|
+
trigger?: string | undefined;
|
|
218
|
+
warning?: string | undefined;
|
|
219
|
+
}[] | undefined;
|
|
220
|
+
truncated?: boolean | undefined;
|
|
221
|
+
continuation?: {
|
|
222
|
+
arguments: Record<string, unknown>;
|
|
223
|
+
reason?: string | undefined;
|
|
224
|
+
} | undefined;
|
|
225
|
+
}>;
|
|
226
|
+
deploymentDelete: import("@sentry/junior-plugin-api").PluginToolDefinition<{
|
|
227
|
+
deploymentId: string;
|
|
228
|
+
team?: string | undefined;
|
|
229
|
+
}, {
|
|
230
|
+
[x: string]: unknown;
|
|
231
|
+
target: "deployment";
|
|
232
|
+
deploymentId: string;
|
|
233
|
+
deleted: true;
|
|
234
|
+
objectAnnotations?: {
|
|
235
|
+
kind: "object";
|
|
236
|
+
key: string;
|
|
237
|
+
label: string;
|
|
238
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
239
|
+
title: string;
|
|
240
|
+
url: string | null;
|
|
241
|
+
description?: string | undefined;
|
|
242
|
+
status?: string | undefined;
|
|
243
|
+
trigger?: string | undefined;
|
|
244
|
+
warning?: string | undefined;
|
|
245
|
+
}[] | undefined;
|
|
246
|
+
truncated?: boolean | undefined;
|
|
247
|
+
continuation?: {
|
|
248
|
+
arguments: Record<string, unknown>;
|
|
249
|
+
reason?: string | undefined;
|
|
250
|
+
} | undefined;
|
|
251
|
+
}, {
|
|
252
|
+
[x: string]: unknown;
|
|
253
|
+
target: "deployment";
|
|
254
|
+
deploymentId: string;
|
|
255
|
+
deleted: true;
|
|
256
|
+
objectAnnotations?: {
|
|
257
|
+
kind: "object";
|
|
258
|
+
key: string;
|
|
259
|
+
label: string;
|
|
260
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
261
|
+
title: string;
|
|
262
|
+
url: string | null;
|
|
263
|
+
description?: string | undefined;
|
|
264
|
+
status?: string | undefined;
|
|
265
|
+
trigger?: string | undefined;
|
|
266
|
+
warning?: string | undefined;
|
|
267
|
+
}[] | undefined;
|
|
268
|
+
truncated?: boolean | undefined;
|
|
269
|
+
continuation?: {
|
|
270
|
+
arguments: Record<string, unknown>;
|
|
271
|
+
reason?: string | undefined;
|
|
272
|
+
} | undefined;
|
|
273
|
+
}>;
|
|
274
|
+
};
|
|
@@ -10,6 +10,18 @@ export declare function createVercelDeploymentTool(ctx: ToolRegistrationHookCont
|
|
|
10
10
|
deploymentTarget: "preview" | "production" | "staging" | null;
|
|
11
11
|
projectId: string;
|
|
12
12
|
target: "deployment";
|
|
13
|
+
objectAnnotations?: {
|
|
14
|
+
kind: "object";
|
|
15
|
+
key: string;
|
|
16
|
+
label: string;
|
|
17
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
18
|
+
title: string;
|
|
19
|
+
url: string | null;
|
|
20
|
+
description?: string | undefined;
|
|
21
|
+
status?: string | undefined;
|
|
22
|
+
trigger?: string | undefined;
|
|
23
|
+
warning?: string | undefined;
|
|
24
|
+
}[] | undefined;
|
|
13
25
|
truncated?: boolean | undefined;
|
|
14
26
|
continuation?: {
|
|
15
27
|
arguments: Record<string, unknown>;
|
|
@@ -28,6 +40,18 @@ export declare function createVercelDeploymentTool(ctx: ToolRegistrationHookCont
|
|
|
28
40
|
deploymentTarget: "preview" | "production" | "staging" | null;
|
|
29
41
|
projectId: string;
|
|
30
42
|
target: "deployment";
|
|
43
|
+
objectAnnotations?: {
|
|
44
|
+
kind: "object";
|
|
45
|
+
key: string;
|
|
46
|
+
label: string;
|
|
47
|
+
objectType: "task" | "code_change" | "automation" | "item";
|
|
48
|
+
title: string;
|
|
49
|
+
url: string | null;
|
|
50
|
+
description?: string | undefined;
|
|
51
|
+
status?: string | undefined;
|
|
52
|
+
trigger?: string | undefined;
|
|
53
|
+
warning?: string | undefined;
|
|
54
|
+
}[] | undefined;
|
|
31
55
|
truncated?: boolean | undefined;
|
|
32
56
|
continuation?: {
|
|
33
57
|
arguments: Record<string, unknown>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-vercel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.223.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"zod": "^4.5.4",
|
|
30
|
-
"@sentry/junior-plugin-api": "0.
|
|
30
|
+
"@sentry/junior-plugin-api": "0.223.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@oxlint/plugins": "1.79.0",
|
package/skills/vercel/SKILL.md
CHANGED
|
@@ -1,63 +1,52 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vercel
|
|
3
|
-
description:
|
|
3
|
+
description: Deploy and inspect Vercel apps, assign aliases, delete deployments, investigate logs, and monitor deployment outcomes. Use for Vercel deployment and log requests, not GitHub code changes or other cloud providers.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Vercel Operations
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- Include the project, environment, deployment, time window, and filters used.
|
|
54
|
-
- Include Vercel deployment or dashboard URLs when the CLI output provides them. Do not fabricate URLs from incomplete IDs.
|
|
55
|
-
|
|
56
|
-
## Failure handling
|
|
57
|
-
|
|
58
|
-
- Missing `JUNIOR_VERCEL_TOKEN`: tell the operator to add `JUNIOR_VERCEL_TOKEN` to the Junior deployment environment and redeploy.
|
|
59
|
-
- `401`, invalid token, expired token, or revoked token: report that the configured Vercel token cannot authenticate.
|
|
60
|
-
- `403` or permission denied: report that the configured Vercel token or service account cannot read the requested project/deployment/logs. Do not guess missing Vercel permission scopes.
|
|
61
|
-
- Project not found: confirm `vercel.project`, `vercel.team`, and the user-provided project name or scope.
|
|
62
|
-
- Rate limiting or transient network failure: retry the same bounded read command once. If it still fails, report the throttle or network failure and stop.
|
|
63
|
-
- Mutation request: decline briefly and explain this skill is limited to read-only Vercel logs, deployment inspection, and deployment listing.
|
|
8
|
+
## Resolve the target
|
|
9
|
+
|
|
10
|
+
- Use the user's explicit project, team, deployment, alias, and environment.
|
|
11
|
+
- Read `vercel.project` and `vercel.team` with standalone `jr-rpc config get`
|
|
12
|
+
commands only when those defaults are needed. They are fallbacks, not limits.
|
|
13
|
+
- Do not change defaults unless requested.
|
|
14
|
+
- Resolve an ambiguous target before a write. Use Production only when requested.
|
|
15
|
+
|
|
16
|
+
## Tools and CLI
|
|
17
|
+
|
|
18
|
+
Discover deployment and alias tools in the Vercel catalog. Follow their schemas.
|
|
19
|
+
Use the CLI for logs, local source uploads, other Git providers, or operations
|
|
20
|
+
not covered by tools. Inspect `vercel <command> --help` when needed. Use
|
|
21
|
+
`--scope <team>` and explicit targets.
|
|
22
|
+
|
|
23
|
+
Authentication is host-managed. Do not set, print, copy, or request tokens.
|
|
24
|
+
Never use another command or API to bypass a denied action.
|
|
25
|
+
|
|
26
|
+
## Verification and failures
|
|
27
|
+
|
|
28
|
+
- Record the deployment ID, source commit when available, and environment.
|
|
29
|
+
Inspect readiness before using a new deployment.
|
|
30
|
+
- Inspect before retrying an uncertain write. A timeout can occur after Vercel
|
|
31
|
+
accepted it. Do not blindly repeat a deploy, alias assignment, or deletion.
|
|
32
|
+
- For QA, compare alias deployment IDs before and after testing. A changed
|
|
33
|
+
target makes affected results inconclusive. Alias checks are not locks.
|
|
34
|
+
If an assignment returns `matches=false`, do not overwrite the changed target.
|
|
35
|
+
- Verify isolated state before QA that must not affect shared data. Builds can
|
|
36
|
+
run migrations. Moving an alias does not stop older workers.
|
|
37
|
+
- Report missing credentials or provider permission failures. Do not guess
|
|
38
|
+
permission scopes or change credentials as a workaround.
|
|
39
|
+
- Retry a transient read once. Bound waits and report unresolved failures.
|
|
40
|
+
|
|
41
|
+
## Logs and watches
|
|
42
|
+
|
|
43
|
+
- Prefer `vercel logs` with a project, time window, and limit. Default to the
|
|
44
|
+
last hour for current incidents and the last 24 hours for retrospective work.
|
|
45
|
+
- Use `vercel inspect <deployment> --logs` for build logs and
|
|
46
|
+
`vercel list <project>` for deployment discovery. Quote only decisive
|
|
47
|
+
diagnostics; logs can contain private data.
|
|
48
|
+
- Use live log streaming only when requested and stop after collecting evidence.
|
|
49
|
+
- For watches, call `vercel_deployment` with project and optional team, target,
|
|
50
|
+
and full commit SHA. Use its returned resource. A commit defaults to
|
|
51
|
+
Production unless `target` is supplied. Create the watch before completion;
|
|
52
|
+
earlier webhook events are not replayed.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Vercel skill contract
|
|
2
|
+
|
|
3
|
+
## Intent and shape
|
|
4
|
+
|
|
5
|
+
Guide Vercel operations through plugin tools and the CLI. Use inline guidance;
|
|
6
|
+
tool schemas own API inputs and outputs.
|
|
7
|
+
|
|
8
|
+
## Evidence and limits
|
|
9
|
+
|
|
10
|
+
Tool schemas and official Vercel APIs define operation inputs. Provider
|
|
11
|
+
responses supply deployment and alias evidence. The existing token and runtime
|
|
12
|
+
review remain authoritative; the skill does not grant permission.
|
|
13
|
+
|
|
14
|
+
Alias checks are not a lock. Builds inherit credentials and can run migrations.
|
|
15
|
+
A ready deployment does not prove Slack QA passed.
|
|
16
|
+
|
|
17
|
+
## Validation and maintenance
|
|
18
|
+
|
|
19
|
+
Trigger for requests such as "deploy this commit to Vercel", "move this alias",
|
|
20
|
+
"delete this Vercel deployment", and "show Vercel build logs". Do not trigger
|
|
21
|
+
for "open a GitHub PR" or "deploy to AWS".
|
|
22
|
+
|
|
23
|
+
The plugin's action tests cover request payloads, environment selection, alias
|
|
24
|
+
changes, and failures. Run `pnpm skills:check` after skill edits. Live Vercel
|
|
25
|
+
execution and Slack QA need separate validation.
|