@sentry/junior-plugin-api 0.74.1 → 0.76.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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // src/index.ts
1
+ // src/schemas.ts
2
2
  import { z } from "zod";
3
3
  var slackTeamIdSchema = z.string().regex(/^T[A-Z0-9]+$/);
4
4
  var slackConversationIdSchema = z.string().regex(/^(C|G|D)[A-Z0-9]+$/);
@@ -7,11 +7,14 @@ var exactActorUserIdSchema = z.string().min(1).refine(
7
7
  (value) => value === value.trim() && value.toLowerCase() !== "unknown"
8
8
  );
9
9
  var nonBlankStringSchema = z.string().refine((value) => value.trim().length > 0);
10
- var slackDestinationSchema = z.object({
10
+ var platformSchema = z.enum(["slack", "local"]);
11
+ var sourceTypeSchema = z.enum(["pub", "priv"]);
12
+ var slackAddressSchema = z.object({
11
13
  platform: z.literal("slack"),
12
14
  teamId: slackTeamIdSchema,
13
15
  channelId: slackConversationIdSchema
14
16
  }).strict();
17
+ var slackDestinationSchema = slackAddressSchema;
15
18
  var localDestinationSchema = z.object({
16
19
  platform: z.literal("local"),
17
20
  conversationId: localConversationIdSchema
@@ -20,19 +23,21 @@ var destinationSchema = z.discriminatedUnion("platform", [
20
23
  slackDestinationSchema,
21
24
  localDestinationSchema
22
25
  ]);
23
- var slackSourceSchema = z.object({
24
- platform: z.literal("slack"),
25
- teamId: slackTeamIdSchema,
26
- channelId: slackConversationIdSchema,
26
+ var slackSourceSchema = slackAddressSchema.extend({
27
+ type: sourceTypeSchema,
27
28
  messageTs: nonBlankStringSchema.optional(),
28
29
  threadTs: nonBlankStringSchema.optional()
29
30
  }).strict();
30
- var localSourceSchema = localDestinationSchema;
31
+ var localSourceSchema = z.object({
32
+ platform: z.literal("local"),
33
+ type: z.literal("priv"),
34
+ conversationId: localConversationIdSchema
35
+ }).strict();
31
36
  var sourceSchema = z.discriminatedUnion("platform", [
32
37
  slackSourceSchema,
33
38
  localSourceSchema
34
39
  ]);
35
- var agentPluginCredentialSubjectSchema = z.object({
40
+ var pluginCredentialSubjectSchema = z.object({
36
41
  type: z.literal("user"),
37
42
  userId: exactActorUserIdSchema,
38
43
  allowedWhen: z.literal("private-direct-conversation")
@@ -81,6 +86,20 @@ var dispatchMetadataSchema = z.record(z.string(), z.string()).superRefine((metad
81
86
  path: [key]
82
87
  });
83
88
  }
89
+ if (/[\r\n]/.test(key)) {
90
+ ctx.addIssue({
91
+ code: z.ZodIssueCode.custom,
92
+ message: "Dispatch metadata keys must be single-line strings",
93
+ path: [key]
94
+ });
95
+ }
96
+ if (/[\r\n]/.test(value)) {
97
+ ctx.addIssue({
98
+ code: z.ZodIssueCode.custom,
99
+ message: "Dispatch metadata values must be single-line strings",
100
+ path: [key]
101
+ });
102
+ }
84
103
  if (value.length > 512) {
85
104
  ctx.addIssue({
86
105
  code: z.ZodIssueCode.custom,
@@ -92,65 +111,147 @@ var dispatchMetadataSchema = z.record(z.string(), z.string()).superRefine((metad
92
111
  });
93
112
  var dispatchOptionsSchema = z.object({
94
113
  idempotencyKey: nonBlankStringSchema.pipe(z.string().max(512)),
95
- credentialSubject: agentPluginCredentialSubjectSchema.optional(),
114
+ credentialSubject: pluginCredentialSubjectSchema.optional(),
96
115
  destination: slackDestinationSchema,
97
116
  input: nonBlankStringSchema.pipe(z.string().max(32e3)),
98
- metadata: dispatchMetadataSchema.optional()
117
+ metadata: dispatchMetadataSchema.optional(),
118
+ source: sourceSchema
99
119
  }).strict();
100
- var AgentPluginToolInputError = class extends Error {
101
- constructor(message, options) {
102
- super(message, options);
103
- this.name = "AgentPluginToolInputError";
120
+
121
+ // src/context.ts
122
+ function createSlackSource(input) {
123
+ return {
124
+ platform: "slack",
125
+ type: slackSourceType(input.channelId),
126
+ teamId: input.teamId,
127
+ channelId: input.channelId,
128
+ ...input.messageTs ? { messageTs: input.messageTs } : {},
129
+ ...input.threadTs ? { threadTs: input.threadTs } : {}
130
+ };
131
+ }
132
+ function slackSourceType(channelId) {
133
+ if (channelId.startsWith("C")) return "pub";
134
+ if (channelId.startsWith("D") || channelId.startsWith("G")) return "priv";
135
+ throw new Error(`Unsupported Slack channel ID prefix: ${channelId}`);
136
+ }
137
+ function createLocalSource(conversationId) {
138
+ return {
139
+ platform: "local",
140
+ type: "priv",
141
+ conversationId
142
+ };
143
+ }
144
+ function isPrivateSource(source) {
145
+ return source.type === "priv";
146
+ }
147
+ function getSourceKey(source) {
148
+ if (source.platform === "local") {
149
+ return source.conversationId;
104
150
  }
105
- };
151
+ const messageKey = source.threadTs ?? source.messageTs;
152
+ if (!messageKey) {
153
+ return void 0;
154
+ }
155
+ return `slack:${source.teamId}:${source.channelId}:${messageKey}`;
156
+ }
106
157
  function isSlackDestination(destination) {
107
158
  return destination?.platform === "slack";
108
159
  }
109
- var agentPluginProviderNameSchema = z.string().regex(/^[a-z][a-z0-9-]*$/);
110
- var agentPluginGrantNameSchema = z.string().regex(/^[a-z][a-z0-9.-]*$/);
111
- var agentPluginGrantAccessSchema = z.union([
112
- z.literal("read"),
113
- z.literal("write")
160
+
161
+ // src/prompt.ts
162
+ import { z as z2 } from "zod";
163
+ var promptMessageSchema = z2.object({
164
+ text: z2.string().trim().min(1).max(8e3)
165
+ }).strict();
166
+
167
+ // src/tasks.ts
168
+ import { z as z3 } from "zod";
169
+ var pluginRunTranscriptEntrySchema = z3.discriminatedUnion("type", [
170
+ z3.object({
171
+ type: z3.literal("message"),
172
+ role: z3.enum(["user", "assistant"]),
173
+ text: z3.string().min(1)
174
+ }).strict(),
175
+ z3.object({
176
+ type: z3.literal("toolResult"),
177
+ toolName: z3.string().min(1),
178
+ isError: z3.boolean(),
179
+ text: z3.string().min(1).optional()
180
+ }).strict()
114
181
  ]);
115
- var agentPluginAuthorizationSchema = z.object({
116
- provider: agentPluginProviderNameSchema,
182
+ var pluginRunContextSchema = z3.object({
183
+ completedAtMs: z3.number().finite(),
184
+ conversationId: z3.string().min(1),
185
+ destination: destinationSchema,
186
+ requester: requesterSchema.optional(),
187
+ runId: z3.string().min(1),
188
+ source: sourceSchema,
189
+ transcript: z3.array(pluginRunTranscriptEntrySchema)
190
+ }).strict();
191
+
192
+ // src/tools.ts
193
+ var PluginToolInputError = class extends Error {
194
+ constructor(message, options) {
195
+ super(message, options);
196
+ this.name = "PluginToolInputError";
197
+ }
198
+ };
199
+
200
+ // src/credentials.ts
201
+ import { z as z4 } from "zod";
202
+ var pluginProviderNameSchema = z4.string().regex(/^[a-z][a-z0-9-]*$/);
203
+ var pluginGrantNameSchema = z4.string().regex(/^[a-z][a-z0-9.-]*$/);
204
+ var pluginGrantAccessSchema = z4.union([
205
+ z4.literal("read"),
206
+ z4.literal("write")
207
+ ]);
208
+ var pluginAuthorizationSchema = z4.object({
209
+ provider: pluginProviderNameSchema,
117
210
  scope: nonBlankStringSchema.optional(),
118
- type: z.literal("oauth")
211
+ type: z4.literal("oauth")
119
212
  }).strict();
120
- var agentPluginProviderAccountSchema = z.object({
213
+ var pluginProviderAccountSchema = z4.object({
121
214
  id: nonBlankStringSchema,
122
215
  label: nonBlankStringSchema.optional(),
123
216
  url: nonBlankStringSchema.optional()
124
217
  }).strict();
125
- var agentPluginGrantSchema = z.object({
126
- access: agentPluginGrantAccessSchema,
127
- name: agentPluginGrantNameSchema,
218
+ var pluginStoredTokensSchema = z4.object({
219
+ account: pluginProviderAccountSchema.optional(),
220
+ accessToken: nonBlankStringSchema,
221
+ expiresAt: z4.number().finite().optional(),
222
+ refreshToken: nonBlankStringSchema,
223
+ refreshTokenExpiresAt: z4.number().finite().optional(),
224
+ scope: nonBlankStringSchema.optional()
225
+ }).strict();
226
+ var pluginGrantSchema = z4.object({
227
+ access: pluginGrantAccessSchema,
228
+ name: pluginGrantNameSchema,
128
229
  reason: nonBlankStringSchema.optional(),
129
- requirements: z.array(nonBlankStringSchema).min(1).optional()
130
- }).strict();
131
- var agentPluginCredentialHeaderTransformSchema = z.object({
132
- domain: z.string().min(1),
133
- headers: z.record(z.string(), z.string()).refine((headers) => Object.keys(headers).length > 0)
134
- }).strict();
135
- var agentPluginCredentialLeaseSchema = z.object({
136
- account: agentPluginProviderAccountSchema.optional(),
137
- authorization: agentPluginAuthorizationSchema.optional(),
138
- expiresAt: z.string().refine((value) => Number.isFinite(Date.parse(value))),
139
- headerTransforms: z.array(agentPluginCredentialHeaderTransformSchema).min(1)
140
- }).strict();
141
- var agentPluginCredentialResultSchema = z.discriminatedUnion("type", [
142
- z.object({
143
- lease: agentPluginCredentialLeaseSchema,
144
- type: z.literal("lease")
230
+ requirements: z4.array(nonBlankStringSchema).min(1).optional()
231
+ }).strict();
232
+ var pluginCredentialHeaderTransformSchema = z4.object({
233
+ domain: z4.string().min(1),
234
+ headers: z4.record(z4.string(), z4.string()).refine((headers) => Object.keys(headers).length > 0)
235
+ }).strict();
236
+ var pluginCredentialLeaseSchema = z4.object({
237
+ account: pluginProviderAccountSchema.optional(),
238
+ authorization: pluginAuthorizationSchema.optional(),
239
+ expiresAt: z4.string().refine((value) => Number.isFinite(Date.parse(value))),
240
+ headerTransforms: z4.array(pluginCredentialHeaderTransformSchema).min(1)
241
+ }).strict();
242
+ var pluginCredentialResultSchema = z4.discriminatedUnion("type", [
243
+ z4.object({
244
+ lease: pluginCredentialLeaseSchema,
245
+ type: z4.literal("lease")
145
246
  }).strict(),
146
- z.object({
147
- authorization: agentPluginAuthorizationSchema.optional(),
247
+ z4.object({
248
+ authorization: pluginAuthorizationSchema.optional(),
148
249
  message: nonBlankStringSchema,
149
- type: z.literal("needed")
250
+ type: z4.literal("needed")
150
251
  }).strict(),
151
- z.object({
252
+ z4.object({
152
253
  message: nonBlankStringSchema,
153
- type: z.literal("unavailable")
254
+ type: z4.literal("unavailable")
154
255
  }).strict()
155
256
  ]);
156
257
  var EgressAuthRequired = class extends Error {
@@ -161,24 +262,27 @@ var EgressAuthRequired = class extends Error {
161
262
  this.authorization = options?.authorization;
162
263
  }
163
264
  };
265
+
266
+ // src/registration.ts
164
267
  var PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
165
268
  function defineJuniorPlugin(plugin) {
166
269
  if ("pluginConfig" in plugin) {
167
270
  throw new Error(
168
- "pluginConfig is no longer supported. Put runtime metadata in manifest and state prefixes on the plugin registration."
271
+ "pluginConfig is no longer supported. Put runtime metadata in manifest or plugin registration fields."
169
272
  );
170
273
  }
274
+ if ("name" in plugin) {
275
+ throw new Error("defineJuniorPlugin() uses manifest.name for identity.");
276
+ }
171
277
  const manifest = plugin.manifest;
172
278
  if (!manifest) {
173
279
  throw new Error(
174
280
  "defineJuniorPlugin() requires a manifest. Use a package name string in defineJuniorPlugins([...]) for plugin.yaml packages."
175
281
  );
176
282
  }
177
- const name = plugin.name ?? manifest.name;
283
+ const name = manifest.name;
178
284
  if (!name) {
179
- throw new Error(
180
- "Junior plugin registrations must include name or manifest.name."
181
- );
285
+ throw new Error("Junior plugin manifest.name is required.");
182
286
  }
183
287
  if (!PLUGIN_NAME_RE.test(name)) {
184
288
  throw new Error(
@@ -195,36 +299,41 @@ function defineJuniorPlugin(plugin) {
195
299
  `Junior plugin "${name}" manifest.description is required.`
196
300
  );
197
301
  }
198
- if (plugin.name && manifest.name && plugin.name !== manifest.name) {
199
- throw new Error(
200
- `Junior plugin registration name "${plugin.name}" must match manifest.name "${manifest.name}".`
201
- );
202
- }
203
302
  return {
204
- ...plugin,
205
- name
303
+ ...plugin
206
304
  };
207
305
  }
208
306
  export {
209
- AgentPluginToolInputError,
210
307
  EgressAuthRequired,
211
- agentPluginAuthorizationSchema,
212
- agentPluginCredentialHeaderTransformSchema,
213
- agentPluginCredentialLeaseSchema,
214
- agentPluginCredentialResultSchema,
215
- agentPluginCredentialSubjectSchema,
216
- agentPluginGrantSchema,
217
- agentPluginProviderAccountSchema,
308
+ PluginToolInputError,
309
+ createLocalSource,
310
+ createSlackSource,
218
311
  defineJuniorPlugin,
219
312
  destinationSchema,
220
313
  dispatchOptionsSchema,
314
+ getSourceKey,
315
+ isPrivateSource,
221
316
  isSlackDestination,
222
317
  localDestinationSchema,
223
318
  localRequesterSchema,
224
319
  localSourceSchema,
320
+ nonBlankStringSchema,
321
+ platformSchema,
322
+ pluginAuthorizationSchema,
323
+ pluginCredentialHeaderTransformSchema,
324
+ pluginCredentialLeaseSchema,
325
+ pluginCredentialResultSchema,
326
+ pluginCredentialSubjectSchema,
327
+ pluginGrantSchema,
328
+ pluginProviderAccountSchema,
329
+ pluginRunContextSchema,
330
+ pluginRunTranscriptEntrySchema,
331
+ pluginStoredTokensSchema,
332
+ promptMessageSchema,
225
333
  requesterSchema,
226
334
  slackDestinationSchema,
227
335
  slackRequesterSchema,
228
336
  slackSourceSchema,
229
- sourceSchema
337
+ sourceSchema,
338
+ sourceTypeSchema
230
339
  };
@@ -0,0 +1,74 @@
1
+ export interface PluginOAuthConfig {
2
+ authorizeEndpoint: string;
3
+ authorizeParams?: Record<string, string>;
4
+ clientIdEnv: string;
5
+ clientSecretEnv: string;
6
+ scope?: string;
7
+ /**
8
+ * Treat a provider token response with `scope: ""` like an omitted scope and
9
+ * fall back to the requested scope string when storing the token.
10
+ */
11
+ treatEmptyScopeAsUnreported?: boolean;
12
+ tokenAuthMethod?: "body" | "basic";
13
+ tokenEndpoint: string;
14
+ tokenExtraHeaders?: Record<string, string>;
15
+ }
16
+ export interface PluginOAuthBearerCredentials {
17
+ apiHeaders?: Record<string, string>;
18
+ authTokenEnv: string;
19
+ authTokenPlaceholder?: string;
20
+ domains: string[];
21
+ type: "oauth-bearer";
22
+ }
23
+ export type PluginCredentials = PluginOAuthBearerCredentials;
24
+ export interface PluginNpmRuntimeDependency {
25
+ package: string;
26
+ type: "npm";
27
+ version: string;
28
+ }
29
+ export interface PluginSystemRuntimeDependency {
30
+ package: string;
31
+ type: "system";
32
+ }
33
+ export interface PluginSystemRuntimeDependencyFromUrl {
34
+ sha256: string;
35
+ type: "system";
36
+ url: string;
37
+ }
38
+ export type PluginRuntimeDependency = PluginNpmRuntimeDependency | PluginSystemRuntimeDependency | PluginSystemRuntimeDependencyFromUrl;
39
+ export interface PluginRuntimePostinstallCommand {
40
+ args?: string[];
41
+ cmd: string;
42
+ sudo?: boolean;
43
+ }
44
+ export interface PluginMcpConfig {
45
+ allowedTools?: string[];
46
+ headers?: Record<string, string>;
47
+ transport: "http";
48
+ url: string;
49
+ }
50
+ export interface PluginEnvVarDeclaration {
51
+ default?: string;
52
+ exposeToCommandEnv?: boolean;
53
+ }
54
+ export interface PluginManifest {
55
+ apiHeaders?: Record<string, string>;
56
+ capabilities?: string[];
57
+ commandEnv?: Record<string, string>;
58
+ configKeys?: string[];
59
+ credentials?: PluginCredentials;
60
+ description: string;
61
+ displayName: string;
62
+ domains?: string[];
63
+ envVars?: Record<string, PluginEnvVarDeclaration>;
64
+ mcp?: PluginMcpConfig;
65
+ name: string;
66
+ oauth?: PluginOAuthConfig;
67
+ runtimeDependencies?: PluginRuntimeDependency[];
68
+ runtimePostinstall?: PluginRuntimePostinstallCommand[];
69
+ target?: {
70
+ commandFlags?: string[];
71
+ configKey: string;
72
+ type: string;
73
+ };
74
+ }
@@ -0,0 +1,91 @@
1
+ import type { PluginContext } from "./context";
2
+ import type { Dispatch, DispatchOptions, DispatchResult } from "./dispatch";
3
+ import type { PluginReadState, PluginState } from "./state";
4
+ export type PluginConversationStatus = "active" | "completed" | "failed" | "hung" | "superseded";
5
+ export interface PluginConversationSummary {
6
+ channelName?: string;
7
+ conversationId: string;
8
+ displayTitle: string;
9
+ lastActivityAt: string;
10
+ lastUpdatedAt: string;
11
+ source?: "api" | "internal" | "local" | "plugin" | "scheduler" | "slack";
12
+ status: PluginConversationStatus;
13
+ }
14
+ export interface PluginConversations {
15
+ listRecent(options?: {
16
+ limit?: number;
17
+ }): Promise<PluginConversationSummary[]>;
18
+ }
19
+ export interface HeartbeatHookContext extends PluginContext {
20
+ agent: {
21
+ dispatch(options: DispatchOptions): Promise<DispatchResult>;
22
+ get(id: string): Promise<Dispatch | undefined>;
23
+ };
24
+ nowMs: number;
25
+ state: PluginState;
26
+ }
27
+ export interface HeartbeatResult {
28
+ dispatchCount?: number;
29
+ }
30
+ export interface StorageMigrationResult {
31
+ existing: number;
32
+ migrated: number;
33
+ missing: number;
34
+ scanned: number;
35
+ skipped?: number;
36
+ }
37
+ export interface StorageMigrationContext extends PluginContext {
38
+ state: PluginState;
39
+ }
40
+ export type PluginOperationalTone = "danger" | "good" | "neutral" | "warning";
41
+ export interface PluginOperationalMetric {
42
+ label: string;
43
+ tone?: PluginOperationalTone;
44
+ value: string;
45
+ }
46
+ export interface PluginOperationalField {
47
+ key: string;
48
+ label: string;
49
+ }
50
+ export interface PluginOperationalRecord {
51
+ id: string;
52
+ tone?: PluginOperationalTone;
53
+ values: Record<string, string>;
54
+ }
55
+ export interface PluginOperationalRecordSet {
56
+ fields?: PluginOperationalField[];
57
+ emptyText?: string;
58
+ records?: PluginOperationalRecord[];
59
+ title: string;
60
+ }
61
+ export interface PluginOperationalReportContent {
62
+ generatedAt?: string;
63
+ metrics?: PluginOperationalMetric[];
64
+ recordSets?: PluginOperationalRecordSet[];
65
+ title?: string;
66
+ }
67
+ export interface PluginOperationalReport extends PluginOperationalReportContent {
68
+ pluginName: string;
69
+ }
70
+ export interface OperationalReportHookContext extends PluginContext {
71
+ conversations: PluginConversations;
72
+ nowMs: number;
73
+ state: PluginReadState;
74
+ }
75
+ export type PluginRouteMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "ALL";
76
+ export type PluginRouteHandler = {
77
+ bivarianceHack(request: Request): Promise<Response> | Response;
78
+ }["bivarianceHack"];
79
+ export interface PluginRoute {
80
+ handler: PluginRouteHandler;
81
+ method?: PluginRouteMethod | PluginRouteMethod[];
82
+ path: string;
83
+ }
84
+ export interface RouteRegistrationHookContext extends PluginContext {
85
+ }
86
+ export interface SlackConversationLink {
87
+ url: string;
88
+ }
89
+ export interface SlackConversationLinkHookContext extends PluginContext {
90
+ conversationId: string;
91
+ }
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+ import type { Destination, Platform, PluginContext, PluginEmbedder, Requester, Source } from "./context";
3
+ import type { PluginState } from "./state";
4
+ export declare const promptMessageSchema: z.ZodObject<{
5
+ text: z.ZodString;
6
+ }, z.core.$strict>;
7
+ /** Small plugin-owned prompt text block rendered by Junior core. */
8
+ export type PromptMessage = z.output<typeof promptMessageSchema>;
9
+ /** Stable platform context for plugin system prompt guidance. */
10
+ export type SystemPromptContext = Pick<PluginContext, "db" | "log" | "plugin"> & {
11
+ platform: Platform;
12
+ };
13
+ /** Runtime facts available while building plugin user prompt context. */
14
+ export type UserPromptContext = Pick<PluginContext, "db" | "log" | "plugin"> & {
15
+ conversationId?: string;
16
+ destination: Destination;
17
+ embedder: PluginEmbedder;
18
+ requester?: Requester;
19
+ source: Source;
20
+ state: PluginState;
21
+ text: string;
22
+ };
@@ -0,0 +1,22 @@
1
+ import type { PluginCliDefinition } from "./cli";
2
+ import type { PluginHooks } from "./hooks";
3
+ import type { PluginManifest } from "./manifest";
4
+ import type { PluginTasks } from "./tasks";
5
+ export interface PluginModelConfig {
6
+ /** Host model family used when no explicit structured model id is configured. */
7
+ structuredModel?: "default" | "fast";
8
+ /** Host model id used for this plugin's structured model calls. */
9
+ structuredModelId?: string;
10
+ }
11
+ export type PluginRegistrationInput = {
12
+ cli?: PluginCliDefinition;
13
+ hooks?: PluginHooks;
14
+ manifest: PluginManifest;
15
+ model?: PluginModelConfig;
16
+ packageName?: string;
17
+ tasks?: PluginTasks;
18
+ };
19
+ export interface PluginRegistration extends PluginRegistrationInput {
20
+ }
21
+ /** Define one Junior plugin registration for app and build-time wiring. */
22
+ export declare function defineJuniorPlugin(plugin: PluginRegistrationInput): PluginRegistration;