@sentry/junior-vercel 0.108.0 → 0.109.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 to Junior through the Vercel CLI.
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.
4
4
 
5
5
  ## Install
6
6
 
@@ -10,12 +10,13 @@ pnpm add @sentry/junior @sentry/junior-vercel
10
10
 
11
11
  ## Configure
12
12
 
13
- Add the package name to the plugin set exported from `plugins.ts`:
13
+ Add the plugin factory to the plugin set exported from `plugins.ts`:
14
14
 
15
15
  ```ts
16
16
  import { defineJuniorPlugins } from "@sentry/junior";
17
+ import { vercelPlugin } from "@sentry/junior-vercel";
17
18
 
18
- export const plugins = defineJuniorPlugins(["@sentry/junior-vercel"]);
19
+ export const plugins = defineJuniorPlugins([vercelPlugin()]);
19
20
  ```
20
21
 
21
22
  Point `juniorNitro()` at that plugin module:
@@ -32,11 +33,25 @@ JUNIOR_VERCEL_TOKEN=...
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
35
 
36
+ ## Optional deployment webhooks
37
+
38
+ In **Vercel Team Settings → Webhooks**, create a project-scoped [account webhook](https://vercel.com/docs/webhooks#account-webhooks). Account webhooks are available for Pro and Enterprise teams.
39
+
40
+ ```text
41
+ https://<junior-host>/api/webhooks/vercel
42
+ ```
43
+
44
+ The endpoint must be publicly reachable. Subscribe it to `deployment.succeeded`, `deployment.error`, and `deployment.canceled`, select the projects Junior should monitor, and save the one-time secret as a sensitive `VERCEL_WEBHOOK_SECRET` value in Junior's Production environment. Redeploy Junior after adding it.
45
+
46
+ Deployment watches use Vercel's canonical `prj_...` ID. Junior resolves that ID from the project name or ID and optional team slug or ID through Vercel's authenticated project API.
47
+
48
+ Create the conversation watch before the terminal deployment event. A valid webhook delivery does not create a watch by itself, and unmatched deliveries are not replayed later.
49
+
35
50
  ## Auth model
36
51
 
37
52
  - This package uses a deployment-level Vercel token, not per-user OAuth.
38
53
  - Junior keeps the real `JUNIOR_VERCEL_TOKEN` host-side.
39
- - Matching Vercel API requests from the CLI receive a host-managed `Authorization` header.
54
+ - Matching Vercel API requests from the CLI and plugin tools receive a host-managed `Authorization` header.
40
55
  - The sandbox receives only a non-secret placeholder `VERCEL_TOKEN` so the Vercel CLI can run normally before making API requests.
41
56
 
42
57
  ## Optional channel defaults
@@ -0,0 +1,256 @@
1
+ // src/webhooks/secret.ts
2
+ function vercelWebhookSecret() {
3
+ return process.env.VERCEL_WEBHOOK_SECRET?.trim() || void 0;
4
+ }
5
+
6
+ // src/tools/deployment-source.ts
7
+ import {
8
+ definePluginTool,
9
+ pluginToolResultSchema,
10
+ subscribableResourceSchema
11
+ } from "@sentry/junior-plugin-api";
12
+ import { z } from "zod";
13
+
14
+ // src/resource-events/deployment-source.ts
15
+ var VERCEL_DEPLOYMENT_EVENTS = [
16
+ "deployment.succeeded",
17
+ "deployment.error",
18
+ "deployment.canceled"
19
+ ];
20
+ function vercelDeploymentSourceResource(input) {
21
+ const commitSha2 = input.commitSha.toLowerCase();
22
+ return {
23
+ label: `Vercel ${input.target} deployment for ${input.projectId} at ${commitSha2.slice(0, 12)}`,
24
+ provider: "vercel",
25
+ resourceRef: `vercel:deployment-source:${input.projectId}:${input.target}:${commitSha2}`
26
+ };
27
+ }
28
+ function vercelDeploymentSourceSubscribable(input) {
29
+ if (!input.webhookSecret) return void 0;
30
+ return {
31
+ ...vercelDeploymentSourceResource(input),
32
+ suggestedEvents: [...VERCEL_DEPLOYMENT_EVENTS],
33
+ supportedEvents: [...VERCEL_DEPLOYMENT_EVENTS],
34
+ type: "deployment_source"
35
+ };
36
+ }
37
+
38
+ // src/tools/deployment-source.ts
39
+ var projectIdSchema = z.string().regex(/^prj_[A-Za-z0-9]+$/);
40
+ var commitShaSchema = z.string().regex(/^[0-9a-f]{40}$/i);
41
+ var targetSchema = z.enum(["preview", "production", "staging"]);
42
+ var nonEmptyStringSchema = z.string().trim().min(1);
43
+ var inputSchema = z.object({
44
+ commitSha: commitShaSchema.describe("Full 40-character Git commit SHA."),
45
+ project: nonEmptyStringSchema.describe("Vercel project name or prj_ ID."),
46
+ target: targetSchema.describe("Deployment target to monitor.").default("production"),
47
+ team: nonEmptyStringSchema.describe("Optional Vercel team slug or team_ ID that owns the project.").optional()
48
+ }).strict();
49
+ var deploymentSourceSchema = z.object({
50
+ commitSha: commitShaSchema,
51
+ deploymentTarget: targetSchema,
52
+ projectId: projectIdSchema,
53
+ subscribable: subscribableResourceSchema.optional()
54
+ });
55
+ var outputSchema = pluginToolResultSchema.extend({
56
+ data: deploymentSourceSchema,
57
+ ok: z.literal(true),
58
+ status: z.literal("success"),
59
+ target: z.literal("deploymentSource"),
60
+ ...deploymentSourceSchema.shape
61
+ });
62
+ async function readJson(response) {
63
+ const text = await response.text();
64
+ if (!text) return void 0;
65
+ try {
66
+ return JSON.parse(text);
67
+ } catch {
68
+ return text;
69
+ }
70
+ }
71
+ function projectLookupUrl(project, team) {
72
+ const url = new URL(
73
+ `https://api.vercel.com/v9/projects/${encodeURIComponent(project)}`
74
+ );
75
+ if (team) {
76
+ url.searchParams.set(team.startsWith("team_") ? "teamId" : "slug", team);
77
+ }
78
+ return url.toString();
79
+ }
80
+ function createVercelDeploymentSourceTool(ctx) {
81
+ return definePluginTool({
82
+ description: "Resolve a Vercel project name or ID and describe its deployment target and full Git commit SHA as a subscribable deployment source. Use the user's explicit project and team, otherwise the vercel.project and vercel.team conversation defaults. Use this after the final deployed commit is known and before waiting for a deployment outcome.",
83
+ inputSchema,
84
+ outputSchema,
85
+ async execute(input) {
86
+ const response = await ctx.egress.fetch({
87
+ operation: "vercel.project.get",
88
+ provider: "vercel",
89
+ request: new Request(projectLookupUrl(input.project, input.team))
90
+ });
91
+ const parsed = await readJson(response);
92
+ if (!response.ok) {
93
+ throw new Error(
94
+ `Vercel project lookup failed with HTTP ${response.status}`
95
+ );
96
+ }
97
+ const projectId = z.object({ id: projectIdSchema }).parse(parsed).id;
98
+ const commitSha2 = input.commitSha.toLowerCase();
99
+ const subscribable = vercelDeploymentSourceSubscribable({
100
+ commitSha: commitSha2,
101
+ projectId,
102
+ target: input.target,
103
+ webhookSecret: vercelWebhookSecret()
104
+ });
105
+ const data = {
106
+ commitSha: commitSha2,
107
+ deploymentTarget: input.target,
108
+ projectId,
109
+ ...subscribable ? { subscribable } : {}
110
+ };
111
+ return {
112
+ data,
113
+ ok: true,
114
+ status: "success",
115
+ target: "deploymentSource",
116
+ ...data
117
+ };
118
+ }
119
+ });
120
+ }
121
+
122
+ // src/webhooks/resource-events.ts
123
+ import { z as z2 } from "zod";
124
+ var projectIdSchema2 = z2.string().regex(/^prj_[A-Za-z0-9]+$/);
125
+ var deploymentIdSchema = z2.string().regex(/^dpl_[A-Za-z0-9]+$/);
126
+ var commitShaSchema2 = z2.string().regex(/^[0-9a-f]{40}$/i);
127
+ var webhookEnvelopeSchema = z2.object({
128
+ createdAt: z2.number().finite(),
129
+ id: z2.string().min(1),
130
+ payload: z2.unknown(),
131
+ region: z2.unknown().optional(),
132
+ type: z2.string().min(1)
133
+ }).strict();
134
+ var deploymentPayloadSchema = z2.object({
135
+ alias: z2.unknown().optional(),
136
+ deployment: z2.object({
137
+ id: deploymentIdSchema,
138
+ meta: z2.record(z2.string(), z2.unknown()),
139
+ name: z2.unknown().optional(),
140
+ url: z2.unknown().optional()
141
+ }).strict(),
142
+ links: z2.unknown().optional(),
143
+ plan: z2.unknown().optional(),
144
+ project: z2.object({
145
+ id: projectIdSchema2,
146
+ name: z2.unknown().optional()
147
+ }).strict(),
148
+ regions: z2.unknown().optional(),
149
+ target: z2.string().nullable(),
150
+ team: z2.unknown().optional(),
151
+ user: z2.unknown().optional()
152
+ }).strict().transform((payload) => ({
153
+ commitSha: commitSha(payload.deployment.meta),
154
+ deploymentId: payload.deployment.id,
155
+ projectId: payload.project.id,
156
+ target: deploymentTarget(payload.target)
157
+ }));
158
+ function deploymentTarget(value) {
159
+ if (value === null) return "preview";
160
+ if (value === "production" || value === "staging") return value;
161
+ return void 0;
162
+ }
163
+ function commitSha(meta) {
164
+ for (const key of [
165
+ "githubCommitSha",
166
+ "gitlabCommitSha",
167
+ "bitbucketCommitSha",
168
+ "gitCommitSha"
169
+ ]) {
170
+ const parsed = commitShaSchema2.safeParse(meta[key]);
171
+ if (parsed.success) return parsed.data.toLowerCase();
172
+ }
173
+ return void 0;
174
+ }
175
+ function isDeploymentEvent(value) {
176
+ return VERCEL_DEPLOYMENT_EVENTS.includes(
177
+ value
178
+ );
179
+ }
180
+ function normalizeVercelResourceEvents(args) {
181
+ const envelope = webhookEnvelopeSchema.safeParse(args.body);
182
+ if (!envelope.success || !isDeploymentEvent(envelope.data.type)) return [];
183
+ const payload = deploymentPayloadSchema.safeParse(envelope.data.payload);
184
+ if (!payload.success) return [];
185
+ const target = payload.data.target;
186
+ const sha = payload.data.commitSha;
187
+ if (!target || !sha) return [];
188
+ const resource = vercelDeploymentSourceResource({
189
+ commitSha: sha,
190
+ projectId: payload.data.projectId,
191
+ target
192
+ });
193
+ const eventType = envelope.data.type;
194
+ const deploymentId = payload.data.deploymentId;
195
+ const outcome = eventType === "deployment.succeeded" ? "succeeded" : eventType === "deployment.error" ? "failed" : "was canceled";
196
+ return [
197
+ {
198
+ eventKey: `vercel:${envelope.data.id}:${eventType}`,
199
+ eventType,
200
+ occurredAtMs: envelope.data.createdAt,
201
+ provider: "vercel",
202
+ resourceRef: resource.resourceRef,
203
+ terminal: true,
204
+ trustedSummary: `${resource.label} (${deploymentId}) ${outcome}.`
205
+ }
206
+ ];
207
+ }
208
+
209
+ // src/webhooks/handler.ts
210
+ import { createHmac, timingSafeEqual } from "crypto";
211
+ function verifyVercelSignature(body, signature, secret) {
212
+ if (!secret || !/^[0-9a-f]{40}$/i.test(signature)) return false;
213
+ const actual = Buffer.from(signature.toLowerCase());
214
+ const expected = Buffer.from(
215
+ createHmac("sha1", secret).update(body).digest("hex")
216
+ );
217
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
218
+ }
219
+ function parseJson(body) {
220
+ try {
221
+ return JSON.parse(body);
222
+ } catch {
223
+ return void 0;
224
+ }
225
+ }
226
+ function createVercelWebhookRoute(args) {
227
+ return {
228
+ method: "POST",
229
+ path: "/api/webhooks/vercel",
230
+ async handler(request) {
231
+ const rawBody = await request.text();
232
+ const signature = request.headers.get("x-vercel-signature") ?? "";
233
+ if (!verifyVercelSignature(rawBody, signature, args.webhookSecret())) {
234
+ return new Response("Unauthorized", { status: 401 });
235
+ }
236
+ const body = parseJson(rawBody);
237
+ if (body === void 0) {
238
+ return new Response("Malformed Vercel webhook", { status: 400 });
239
+ }
240
+ const resourceEvents = normalizeVercelResourceEvents({ body });
241
+ for (const event of resourceEvents) {
242
+ await args.resourceEvents.publish(event);
243
+ }
244
+ return new Response(resourceEvents.length ? "Accepted" : "Ignored", {
245
+ status: 202
246
+ });
247
+ }
248
+ };
249
+ }
250
+
251
+ export {
252
+ vercelWebhookSecret,
253
+ createVercelDeploymentSourceTool,
254
+ normalizeVercelResourceEvents,
255
+ createVercelWebhookRoute
256
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Vercel plugin runtime boundary.
3
+ *
4
+ * This package owns Vercel CLI setup, host-managed API authentication, signed
5
+ * webhook normalization, and deployment-source tools. Junior core owns the
6
+ * resulting conversation subscriptions and event delivery.
7
+ */
8
+ import { type PluginRegistration } from "@sentry/junior-plugin-api";
9
+ /** Register Vercel runtime metadata, tools, and signed webhook ingress. */
10
+ export declare function vercelPlugin(): PluginRegistration;
package/dist/index.js ADDED
@@ -0,0 +1,58 @@
1
+ import {
2
+ createVercelDeploymentSourceTool,
3
+ createVercelWebhookRoute,
4
+ vercelWebhookSecret
5
+ } from "./chunk-GIY5FD3W.js";
6
+
7
+ // src/index.ts
8
+ import {
9
+ defineJuniorPlugin
10
+ } from "@sentry/junior-plugin-api";
11
+ function vercelPlugin() {
12
+ return defineJuniorPlugin({
13
+ packageName: "@sentry/junior-vercel",
14
+ manifest: {
15
+ apiHeaders: {
16
+ Authorization: "Bearer ${JUNIOR_VERCEL_TOKEN}"
17
+ },
18
+ capabilities: ["api"],
19
+ commandEnv: {
20
+ VERCEL_TOKEN: "host_managed_credential"
21
+ },
22
+ configKeys: ["project", "team"],
23
+ description: "Query Vercel deployments and logs and monitor deployment outcomes",
24
+ displayName: "Vercel",
25
+ domains: ["api.vercel.com"],
26
+ envVars: {
27
+ JUNIOR_VERCEL_TOKEN: {},
28
+ VERCEL_WEBHOOK_SECRET: {}
29
+ },
30
+ name: "vercel",
31
+ runtimeDependencies: [
32
+ {
33
+ package: "vercel",
34
+ type: "npm",
35
+ version: "latest"
36
+ }
37
+ ]
38
+ },
39
+ hooks: {
40
+ routes(ctx) {
41
+ return [
42
+ createVercelWebhookRoute({
43
+ resourceEvents: ctx.resourceEvents,
44
+ webhookSecret: vercelWebhookSecret
45
+ })
46
+ ];
47
+ },
48
+ tools(ctx) {
49
+ return {
50
+ deploymentSource: createVercelDeploymentSourceTool(ctx)
51
+ };
52
+ }
53
+ }
54
+ });
55
+ }
56
+ export {
57
+ vercelPlugin
58
+ };
@@ -0,0 +1,16 @@
1
+ import type { SubscribableResource } from "@sentry/junior-plugin-api";
2
+ export declare const VERCEL_DEPLOYMENT_EVENTS: readonly ["deployment.succeeded", "deployment.error", "deployment.canceled"];
3
+ export type VercelDeploymentTarget = "preview" | "production" | "staging";
4
+ /** Build the stable deployment-source identity shared by tools and webhooks. */
5
+ export declare function vercelDeploymentSourceResource(input: {
6
+ commitSha: string;
7
+ projectId: string;
8
+ target: VercelDeploymentTarget;
9
+ }): Pick<SubscribableResource, "label" | "provider" | "resourceRef">;
10
+ /** Describe a deployment source when signed Vercel webhooks are enabled. */
11
+ export declare function vercelDeploymentSourceSubscribable(input: {
12
+ commitSha: string;
13
+ projectId: string;
14
+ target: VercelDeploymentTarget;
15
+ webhookSecret?: string;
16
+ }): SubscribableResource | undefined;
@@ -0,0 +1,3 @@
1
+ export { createVercelDeploymentSourceTool } from "./tools/deployment-source.js";
2
+ export { createVercelWebhookRoute } from "./webhooks/handler.js";
3
+ export { normalizeVercelResourceEvents } from "./webhooks/resource-events.js";
@@ -0,0 +1,10 @@
1
+ import {
2
+ createVercelDeploymentSourceTool,
3
+ createVercelWebhookRoute,
4
+ normalizeVercelResourceEvents
5
+ } from "./chunk-GIY5FD3W.js";
6
+ export {
7
+ createVercelDeploymentSourceTool,
8
+ createVercelWebhookRoute,
9
+ normalizeVercelResourceEvents
10
+ };
@@ -0,0 +1,47 @@
1
+ import { type ToolRegistrationHookContext } from "@sentry/junior-plugin-api";
2
+ /** Resolve and return the resource identity for one Vercel deployment source. */
3
+ export declare function createVercelDeploymentSourceTool(ctx: ToolRegistrationHookContext): import("@sentry/junior-plugin-api").PluginToolDefinition<{
4
+ commitSha: string;
5
+ project: string;
6
+ target: "preview" | "production" | "staging";
7
+ team?: string | undefined;
8
+ }, {
9
+ [x: string]: unknown;
10
+ commitSha: string;
11
+ deploymentTarget: "preview" | "production" | "staging";
12
+ projectId: string;
13
+ data: {
14
+ commitSha: string;
15
+ deploymentTarget: "preview" | "production" | "staging";
16
+ projectId: string;
17
+ subscribable?: {
18
+ label: string;
19
+ provider: string;
20
+ resourceRef: string;
21
+ supportedEvents: string[];
22
+ type: string;
23
+ suggestedEvents?: string[] | undefined;
24
+ } | undefined;
25
+ };
26
+ ok: true;
27
+ status: "success";
28
+ target: "deploymentSource";
29
+ truncated?: boolean | undefined;
30
+ continuation?: {
31
+ arguments: Record<string, unknown>;
32
+ reason?: string | undefined;
33
+ } | undefined;
34
+ error?: string | {
35
+ kind: string;
36
+ message: string;
37
+ retryable?: boolean | undefined;
38
+ } | undefined;
39
+ subscribable?: {
40
+ label: string;
41
+ provider: string;
42
+ resourceRef: string;
43
+ supportedEvents: string[];
44
+ type: string;
45
+ suggestedEvents?: string[] | undefined;
46
+ } | undefined;
47
+ }>;
@@ -0,0 +1,6 @@
1
+ import type { PluginRoute, ResourceEventPublisher } from "@sentry/junior-plugin-api";
2
+ /** Create the public, signed Vercel deployment webhook route. */
3
+ export declare function createVercelWebhookRoute(args: {
4
+ resourceEvents: ResourceEventPublisher;
5
+ webhookSecret(): string | undefined;
6
+ }): PluginRoute;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Owns Vercel's deployment webhook wire-format boundary.
3
+ *
4
+ * It validates provider payloads, ignores unsupported or incomplete deliveries,
5
+ * and emits only canonical terminal resource events.
6
+ */
7
+ import type { ResourceEvent } from "@sentry/junior-plugin-api";
8
+ /** Normalize one verified Vercel delivery into a terminal deployment event. */
9
+ export declare function normalizeVercelResourceEvents(args: {
10
+ body: unknown;
11
+ }): ResourceEvent[];
@@ -0,0 +1,2 @@
1
+ /** Read the normalized secret shared by watch creation and webhook ingress. */
2
+ export declare function vercelWebhookSecret(): string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-vercel",
3
- "version": "0.108.0",
3
+ "version": "0.109.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -11,8 +11,35 @@
11
11
  "url": "git+https://github.com/getsentry/junior.git",
12
12
  "directory": "packages/junior-vercel"
13
13
  },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "./testing": {
20
+ "types": "./dist/testing.d.ts",
21
+ "default": "./dist/testing.js"
22
+ }
23
+ },
14
24
  "files": [
15
- "plugin.yaml",
25
+ "dist",
16
26
  "skills"
17
- ]
27
+ ],
28
+ "dependencies": {
29
+ "zod": "^4.4.3",
30
+ "@sentry/junior-plugin-api": "0.109.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^25.9.1",
34
+ "oxlint": "^1.66.0",
35
+ "tsup": "^8.5.1",
36
+ "typescript": "^6.0.3",
37
+ "vitest": "^4.1.7"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup && tsc -p tsconfig.build.json --emitDeclarationOnly",
41
+ "lint": "oxlint --config ../junior/.oxlintrc.json --deny-warnings src tests tsup.config.ts vitest.config.ts",
42
+ "test": "vitest run",
43
+ "typecheck": "tsc --noEmit"
44
+ }
18
45
  }
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: vercel
3
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.
4
- allowed-tools: bash
5
4
  ---
6
5
 
7
6
  # Vercel Operations
@@ -25,7 +24,7 @@ Do not run `deploy`, `rollback`, `promote`, `remove`, `env`, `alias`, `dns`, `pr
25
24
 
26
25
  - Determine whether the user needs runtime logs, build logs, deployment status, or deployment discovery.
27
26
  - Prefer explicit deployment IDs, deployment URLs, project names, environments, branch names, commit SHAs, status filters, and time windows from the user.
28
- - When the user did not specify a project or team, treat `vercel.project` and `vercel.team` conversation config as optional defaults. Explicit user input always wins.
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.
29
28
  - Only set or change `vercel.project` and `vercel.team` when the user explicitly asks to store a default for this conversation or channel.
30
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.
31
30
 
@@ -38,6 +37,7 @@ Do not run `deploy`, `rollback`, `promote`, `remove`, `env`, `alias`, `dns`, `pr
38
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`.
39
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`.
40
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, call the `vercel_deploymentSource` plugin tool with the project name, optional team slug or ID, deployment target, and full 40-character commit SHA. The tool resolves the canonical project ID through Vercel before Junior creates the conversation subscription.
41
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
42
 
43
43
  3. Bound and minimize output:
package/plugin.yaml DELETED
@@ -1,26 +0,0 @@
1
- name: vercel
2
- display-name: Vercel
3
- description: Query Vercel deployments and logs with the Vercel CLI
4
-
5
- config-keys:
6
- - project
7
- - team
8
-
9
- capabilities:
10
- - api
11
-
12
- env-vars:
13
- JUNIOR_VERCEL_TOKEN:
14
-
15
- domains:
16
- - api.vercel.com
17
-
18
- api-headers:
19
- Authorization: Bearer ${JUNIOR_VERCEL_TOKEN}
20
-
21
- command-env:
22
- VERCEL_TOKEN: host_managed_credential
23
-
24
- runtime-dependencies:
25
- - type: npm
26
- package: vercel