@sentry/junior-vercel 0.222.0 → 0.224.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @sentry/junior-vercel
2
2
 
3
- `@sentry/junior-vercel` adds read-only Vercel deployment and log investigation workflows through the Vercel CLI. Signed Vercel webhooks can also notify an existing Junior conversation when a deployment succeeds, fails, or is canceled.
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 smallest project/team access that covers the deployments users need to inspect.
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
- ## Read-only scope
74
+ ## Deployment and alias tools
75
75
 
76
- The bundled skill limits Junior to:
76
+ `vercelPlugin()` registers:
77
77
 
78
- - `vercel logs`
79
- - `vercel inspect`
80
- - `vercel list` / `vercel ls`
81
- - Vercel CLI help commands
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
- It is intended for deployment status, build-log, runtime-log, and failed-deployment investigations. It is not for deploys, rollbacks, env vars, domains, caches, storage, aliases, or other Vercel mutations.
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: "Query Vercel deployments and logs and monitor deployment outcomes",
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.222.0",
3
+ "version": "0.224.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.222.0"
30
+ "@sentry/junior-plugin-api": "0.224.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@oxlint/plugins": "1.79.0",
@@ -1,63 +1,52 @@
1
1
  ---
2
2
  name: vercel
3
- description: Query Vercel deployments, build logs, runtime logs, and deployment status through the Vercel CLI. Use when users ask to debug Vercel deployments, inspect failed builds, fetch production or preview runtime logs, find a deployment for a project or commit SHA, or investigate Vercel-hosted app errors. Do not use it for deploying, rolling back, changing project settings, domains, env vars, caches, storage, or any other Vercel mutation.
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
- Use this skill for read-only Vercel deployment and log investigations.
9
-
10
- ## Read-only command allowlist
11
-
12
- Run only these Vercel CLI commands:
13
-
14
- - `vercel logs`
15
- - `vercel inspect`
16
- - `vercel list` or `vercel ls`
17
- - `vercel help`, `vercel --help`, or `vercel <command> --help`
18
-
19
- Do not run `deploy`, `rollback`, `promote`, `remove`, `env`, `alias`, `dns`, `project`, `cache`, `blob`, `certs`, `teams`, `domains`, `git`, `link`, `login`, `logout`, `switch`, `pull`, `build`, `dev`, `redeploy`, `bisect`, `api`, or any command that creates, updates, deletes, purges, promotes, deploys, links, authenticates, or changes Vercel state.
20
-
21
- ## Workflow
22
-
23
- 1. Resolve the target:
24
-
25
- - Determine whether the user needs runtime logs, build logs, deployment status, or deployment discovery.
26
- - Prefer explicit deployment IDs, deployment URLs, project names, environments, branch names, commit SHAs, status filters, and time windows from the user.
27
- - When the user did not specify a project or team, read `vercel.project` and `vercel.team` with `jr-rpc config get` and treat them as optional conversation defaults. Explicit user input always wins.
28
- - Only set or change `vercel.project` and `vercel.team` when the user explicitly asks to store a default for this conversation or channel.
29
- - Ask one concise follow-up only when the request cannot be bounded to a project, deployment, commit, or time window from the thread or config.
30
-
31
- 2. Run the narrowest safe command:
32
-
33
- - The runtime provides Vercel authentication. Do not set, print, echo, write, or ask for `JUNIOR_VERCEL_TOKEN` or `VERCEL_TOKEN`.
34
- - If a command shape or flag is unclear, inspect `vercel <command> --help` before guessing.
35
- - Add `--scope <team>` when a team is known.
36
- - Add `--project <project>` when a project is known and the command supports it.
37
- - For runtime logs, prefer `vercel logs --project <project> --since <window> --limit 20 --json` plus user-provided filters such as `--environment`, `--level`, `--status-code`, `--source`, `--query`, or `--deployment`.
38
- - Use `vercel inspect <deployment-id-or-url> --logs` for build logs. Add `--wait` only when the user explicitly wants to wait for an active build; also bound it with `--timeout`.
39
- - Use `vercel list <project>` or `vercel ls <project>` to find deployments. Prefer filters such as `--status`, `--environment`, `--prod`, or `--meta githubCommitSha=<sha>` when available.
40
- - For a deployment watch or event automation, call the `vercel_deployment` plugin tool with the project name and optional team slug or ID. Omit `commitSha` to watch every deployment for the project; add `target` (`production`, `preview`, or `staging`) to limit the watch to one environment; add a full 40-character `commitSha` to watch one deployment (`target` defaults to `production` when omitted with a commit). The tool resolves the canonical project ID through Vercel before Junior creates the conversation subscription or event automation.
41
- - Use `--follow` only when the user asks for live logs, and stop once enough evidence is captured. Do not leave a streaming command running indefinitely.
42
-
43
- 3. Bound and minimize output:
44
-
45
- - Always use a time window for log searches. Default to the last hour for "right now" incidents and the last 24 hours for retrospective deployment investigations.
46
- - Prefer JSON output for `vercel logs` when parsing or summarizing.
47
- - Keep page sizes small. Start with 20 log lines or fewer unless the user asked for more.
48
- - Quote only the minimum log text needed as evidence. Vercel logs may contain customer data, secrets, request headers, or other sensitive payloads.
49
-
50
- 4. Report the result:
51
-
52
- - Answer the user first with deployment status, error pattern, top failing route/function, or the absence of matching logs.
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.