@sentry/junior-plugin-api 0.68.0 → 0.69.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.d.ts +215 -34
- package/dist/index.js +123 -2
- package/package.json +4 -1
- package/src/index.ts +316 -38
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Runtime-owned provider-neutral address for routing future work or side effects. */
|
|
3
|
+
export declare const destinationSchema: z.ZodObject<{
|
|
4
|
+
platform: z.ZodLiteral<"slack">;
|
|
5
|
+
teamId: z.ZodString;
|
|
6
|
+
channelId: z.ZodString;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
/** Stable user credential subject shape accepted from plugins. */
|
|
9
|
+
export declare const agentPluginCredentialSubjectSchema: z.ZodObject<{
|
|
10
|
+
type: z.ZodLiteral<"user">;
|
|
11
|
+
userId: z.ZodString;
|
|
12
|
+
allowedWhen: z.ZodLiteral<"private-direct-conversation">;
|
|
13
|
+
}, z.core.$strict>;
|
|
14
|
+
/** Runtime-provided requester identity visible to plugin hooks. */
|
|
15
|
+
export declare const agentPluginRequesterSchema: z.ZodObject<{
|
|
16
|
+
userId: z.ZodOptional<z.ZodString>;
|
|
17
|
+
userName: z.ZodOptional<z.ZodString>;
|
|
18
|
+
fullName: z.ZodOptional<z.ZodString>;
|
|
19
|
+
email: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, z.core.$strict>;
|
|
21
|
+
/** Plugin dispatch request accepted by Junior core. */
|
|
22
|
+
export declare const dispatchOptionsSchema: z.ZodObject<{
|
|
23
|
+
idempotencyKey: z.ZodPipe<z.ZodString, z.ZodString>;
|
|
24
|
+
credentialSubject: z.ZodOptional<z.ZodObject<{
|
|
25
|
+
type: z.ZodLiteral<"user">;
|
|
26
|
+
userId: z.ZodString;
|
|
27
|
+
allowedWhen: z.ZodLiteral<"private-direct-conversation">;
|
|
28
|
+
}, z.core.$strict>>;
|
|
29
|
+
destination: z.ZodObject<{
|
|
30
|
+
platform: z.ZodLiteral<"slack">;
|
|
31
|
+
teamId: z.ZodString;
|
|
32
|
+
channelId: z.ZodString;
|
|
33
|
+
}, z.core.$strict>;
|
|
34
|
+
input: z.ZodPipe<z.ZodString, z.ZodString>;
|
|
35
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
36
|
+
}, z.core.$strict>;
|
|
37
|
+
export type AgentPluginRequester = z.output<typeof agentPluginRequesterSchema>;
|
|
7
38
|
export interface AgentPluginMetadata {
|
|
8
39
|
name: string;
|
|
9
40
|
}
|
|
@@ -20,7 +51,7 @@ export interface AgentPluginLogger {
|
|
|
20
51
|
info(message: string, metadata?: Record<string, unknown>): void;
|
|
21
52
|
warn(message: string, metadata?: Record<string, unknown>): void;
|
|
22
53
|
}
|
|
23
|
-
/** Thrown when a
|
|
54
|
+
/** Thrown when a plugin tool rejects invalid model or user input. */
|
|
24
55
|
export declare class AgentPluginToolInputError extends Error {
|
|
25
56
|
constructor(message: string, options?: {
|
|
26
57
|
cause?: unknown;
|
|
@@ -90,13 +121,36 @@ export interface AgentPluginToolDefinition<TInput = unknown> {
|
|
|
90
121
|
execute?: AgentPluginToolExecute<TInput>;
|
|
91
122
|
}
|
|
92
123
|
export interface ToolRegistrationHookContext extends AgentPluginContext {
|
|
124
|
+
/**
|
|
125
|
+
* Capabilities of `channelId` — the raw conversation channel exposed to
|
|
126
|
+
* this plugin. Recomputed from `channelId`, not from `destination`.
|
|
127
|
+
*/
|
|
93
128
|
channelCapabilities?: {
|
|
94
129
|
canAddReactions: boolean;
|
|
95
130
|
canCreateCanvas: boolean;
|
|
96
131
|
canPostToChannel: boolean;
|
|
97
132
|
};
|
|
133
|
+
/**
|
|
134
|
+
* The raw Slack channel ID for this conversation — the DM or channel where
|
|
135
|
+
* this turn is happening, without any assistant-context-source override.
|
|
136
|
+
* Use this as the stable binding key for state scoped to a Slack conversation.
|
|
137
|
+
* `channelCapabilities` describes this channel.
|
|
138
|
+
*/
|
|
98
139
|
channelId?: string;
|
|
140
|
+
/**
|
|
141
|
+
* Opaque Junior conversation/session identity for this turn.
|
|
142
|
+
* Interactive Slack turns use `slack:{channelId}:{threadTs}`.
|
|
143
|
+
* Scheduled/API turns use an internal id such as `agent-dispatch:{id}`.
|
|
144
|
+
* Do not parse as Slack unless the value starts with `slack:`.
|
|
145
|
+
*/
|
|
146
|
+
conversationId?: string;
|
|
99
147
|
credentialSubject?: AgentPluginCredentialSubject;
|
|
148
|
+
/**
|
|
149
|
+
* Runtime-owned destination suitable for future autonomous dispatch. For
|
|
150
|
+
* Slack, this is the raw conversation channel, not a thread timestamp or
|
|
151
|
+
* assistant-context source channel.
|
|
152
|
+
*/
|
|
153
|
+
destination?: Destination;
|
|
100
154
|
messageTs?: string;
|
|
101
155
|
requester?: AgentPluginRequester;
|
|
102
156
|
state: AgentPluginState;
|
|
@@ -104,22 +158,9 @@ export interface ToolRegistrationHookContext extends AgentPluginContext {
|
|
|
104
158
|
threadTs?: string;
|
|
105
159
|
userText?: string;
|
|
106
160
|
}
|
|
107
|
-
export
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
allowedWhen: "private-direct-conversation";
|
|
111
|
-
}
|
|
112
|
-
export interface DispatchOptions {
|
|
113
|
-
credentialSubject?: AgentPluginCredentialSubject;
|
|
114
|
-
destination: {
|
|
115
|
-
platform: "slack";
|
|
116
|
-
teamId: string;
|
|
117
|
-
channelId: string;
|
|
118
|
-
};
|
|
119
|
-
idempotencyKey: string;
|
|
120
|
-
input: string;
|
|
121
|
-
metadata?: Record<string, string>;
|
|
122
|
-
}
|
|
161
|
+
export type AgentPluginCredentialSubject = z.output<typeof agentPluginCredentialSubjectSchema>;
|
|
162
|
+
export type Destination = z.output<typeof destinationSchema>;
|
|
163
|
+
export type DispatchOptions = z.output<typeof dispatchOptionsSchema>;
|
|
123
164
|
export interface DispatchResult {
|
|
124
165
|
id: string;
|
|
125
166
|
status: "created" | "already_exists";
|
|
@@ -202,9 +243,143 @@ export interface SlackConversationLink {
|
|
|
202
243
|
export interface SlackConversationLinkHookContext extends AgentPluginContext {
|
|
203
244
|
conversationId: string;
|
|
204
245
|
}
|
|
246
|
+
declare const agentPluginGrantAccessSchema: z.ZodUnion<readonly [z.ZodLiteral<"read">, z.ZodLiteral<"write">]>;
|
|
247
|
+
/** Runtime schema for provider authorization a plugin may request. */
|
|
248
|
+
export declare const agentPluginAuthorizationSchema: z.ZodObject<{
|
|
249
|
+
provider: z.ZodString;
|
|
250
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
251
|
+
type: z.ZodLiteral<"oauth">;
|
|
252
|
+
}, z.core.$strict>;
|
|
253
|
+
/** Runtime schema for a provider account attached to stored OAuth tokens. */
|
|
254
|
+
export declare const agentPluginProviderAccountSchema: z.ZodObject<{
|
|
255
|
+
id: z.ZodString;
|
|
256
|
+
label: z.ZodOptional<z.ZodString>;
|
|
257
|
+
url: z.ZodOptional<z.ZodString>;
|
|
258
|
+
}, z.core.$strict>;
|
|
259
|
+
/** Runtime schema for a plugin-defined outbound credential grant. */
|
|
260
|
+
export declare const agentPluginGrantSchema: z.ZodObject<{
|
|
261
|
+
access: z.ZodUnion<readonly [z.ZodLiteral<"read">, z.ZodLiteral<"write">]>;
|
|
262
|
+
name: z.ZodString;
|
|
263
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
264
|
+
requirements: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
265
|
+
}, z.core.$strict>;
|
|
266
|
+
/** Runtime schema for plugin-issued header mutations. */
|
|
267
|
+
export declare const agentPluginCredentialHeaderTransformSchema: z.ZodObject<{
|
|
268
|
+
domain: z.ZodString;
|
|
269
|
+
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
270
|
+
}, z.core.$strict>;
|
|
271
|
+
/** Runtime schema for a short-lived plugin-issued credential lease. */
|
|
272
|
+
export declare const agentPluginCredentialLeaseSchema: z.ZodObject<{
|
|
273
|
+
account: z.ZodOptional<z.ZodObject<{
|
|
274
|
+
id: z.ZodString;
|
|
275
|
+
label: z.ZodOptional<z.ZodString>;
|
|
276
|
+
url: z.ZodOptional<z.ZodString>;
|
|
277
|
+
}, z.core.$strict>>;
|
|
278
|
+
authorization: z.ZodOptional<z.ZodObject<{
|
|
279
|
+
provider: z.ZodString;
|
|
280
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
281
|
+
type: z.ZodLiteral<"oauth">;
|
|
282
|
+
}, z.core.$strict>>;
|
|
283
|
+
expiresAt: z.ZodString;
|
|
284
|
+
headerTransforms: z.ZodArray<z.ZodObject<{
|
|
285
|
+
domain: z.ZodString;
|
|
286
|
+
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
287
|
+
}, z.core.$strict>>;
|
|
288
|
+
}, z.core.$strict>;
|
|
289
|
+
/** Runtime schema for the result returned by a plugin credential hook. */
|
|
290
|
+
export declare const agentPluginCredentialResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
291
|
+
lease: z.ZodObject<{
|
|
292
|
+
account: z.ZodOptional<z.ZodObject<{
|
|
293
|
+
id: z.ZodString;
|
|
294
|
+
label: z.ZodOptional<z.ZodString>;
|
|
295
|
+
url: z.ZodOptional<z.ZodString>;
|
|
296
|
+
}, z.core.$strict>>;
|
|
297
|
+
authorization: z.ZodOptional<z.ZodObject<{
|
|
298
|
+
provider: z.ZodString;
|
|
299
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
300
|
+
type: z.ZodLiteral<"oauth">;
|
|
301
|
+
}, z.core.$strict>>;
|
|
302
|
+
expiresAt: z.ZodString;
|
|
303
|
+
headerTransforms: z.ZodArray<z.ZodObject<{
|
|
304
|
+
domain: z.ZodString;
|
|
305
|
+
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
306
|
+
}, z.core.$strict>>;
|
|
307
|
+
}, z.core.$strict>;
|
|
308
|
+
type: z.ZodLiteral<"lease">;
|
|
309
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
310
|
+
authorization: z.ZodOptional<z.ZodObject<{
|
|
311
|
+
provider: z.ZodString;
|
|
312
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
313
|
+
type: z.ZodLiteral<"oauth">;
|
|
314
|
+
}, z.core.$strict>>;
|
|
315
|
+
message: z.ZodString;
|
|
316
|
+
type: z.ZodLiteral<"needed">;
|
|
317
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
318
|
+
message: z.ZodString;
|
|
319
|
+
type: z.ZodLiteral<"unavailable">;
|
|
320
|
+
}, z.core.$strict>], "type">;
|
|
321
|
+
export type AgentPluginGrantAccess = z.output<typeof agentPluginGrantAccessSchema>;
|
|
322
|
+
/** Provider authorization Junior can start when a plugin-owned grant is missing. */
|
|
323
|
+
export type AgentPluginAuthorization = z.output<typeof agentPluginAuthorizationSchema>;
|
|
324
|
+
/** Provider account identity resolved by a plugin OAuth hook. */
|
|
325
|
+
export type AgentPluginProviderAccount = z.output<typeof agentPluginProviderAccountSchema>;
|
|
326
|
+
/** Plugin-defined grant required before Junior can forward one outbound request. */
|
|
327
|
+
export type AgentPluginGrant = z.output<typeof agentPluginGrantSchema>;
|
|
328
|
+
/** Request details available while selecting the grant for sandbox egress. */
|
|
329
|
+
export interface AgentPluginEgressRequest {
|
|
330
|
+
method: string;
|
|
331
|
+
url: string;
|
|
332
|
+
}
|
|
333
|
+
export interface EgressHookContext extends AgentPluginContext {
|
|
334
|
+
request: AgentPluginEgressRequest;
|
|
335
|
+
}
|
|
336
|
+
/** Header mutations a plugin-issued credential lease may apply to owned domains. */
|
|
337
|
+
export type AgentPluginCredentialHeaderTransform = z.output<typeof agentPluginCredentialHeaderTransformSchema>;
|
|
338
|
+
/** Short-lived credential headers issued by a plugin for a selected grant. */
|
|
339
|
+
export type AgentPluginCredentialLease = z.output<typeof agentPluginCredentialLeaseSchema>;
|
|
340
|
+
export type AgentPluginCredentialResult = z.output<typeof agentPluginCredentialResultSchema>;
|
|
341
|
+
export type AgentPluginCredentialActor = {
|
|
342
|
+
type: "system";
|
|
343
|
+
id: string;
|
|
344
|
+
} | {
|
|
345
|
+
type: "user";
|
|
346
|
+
userId: string;
|
|
347
|
+
};
|
|
348
|
+
export interface AgentPluginResolvedCredentialUser {
|
|
349
|
+
type: "user";
|
|
350
|
+
userId: string;
|
|
351
|
+
}
|
|
352
|
+
export interface AgentPluginStoredTokens {
|
|
353
|
+
account?: AgentPluginProviderAccount;
|
|
354
|
+
accessToken: string;
|
|
355
|
+
expiresAt?: number;
|
|
356
|
+
refreshToken: string;
|
|
357
|
+
scope?: string;
|
|
358
|
+
}
|
|
359
|
+
export interface AgentPluginUserTokenSlot {
|
|
360
|
+
get(): Promise<AgentPluginStoredTokens | undefined>;
|
|
361
|
+
set(tokens: AgentPluginStoredTokens): Promise<void>;
|
|
362
|
+
userId: string;
|
|
363
|
+
}
|
|
364
|
+
export interface AgentPluginTokenStore {
|
|
365
|
+
credentialSubject?: AgentPluginUserTokenSlot;
|
|
366
|
+
currentUser?: AgentPluginUserTokenSlot;
|
|
367
|
+
}
|
|
368
|
+
export interface ResolveOAuthAccountHookContext extends AgentPluginContext {
|
|
369
|
+
tokens: AgentPluginStoredTokens;
|
|
370
|
+
}
|
|
371
|
+
export interface IssueCredentialHookContext extends AgentPluginContext {
|
|
372
|
+
actor: AgentPluginCredentialActor;
|
|
373
|
+
credentialSubject?: AgentPluginResolvedCredentialUser;
|
|
374
|
+
grant: AgentPluginGrant;
|
|
375
|
+
tokens: AgentPluginTokenStore;
|
|
376
|
+
}
|
|
205
377
|
export interface AgentPluginHooks {
|
|
206
378
|
sandboxPrepare?(ctx: SandboxPrepareHookContext): Promise<void> | void;
|
|
207
379
|
beforeToolExecute?(ctx: BeforeToolExecuteHookContext): Promise<void> | void;
|
|
380
|
+
grantForEgress?(ctx: EgressHookContext): Promise<AgentPluginGrant | undefined> | AgentPluginGrant | undefined;
|
|
381
|
+
issueCredential?(ctx: IssueCredentialHookContext): Promise<AgentPluginCredentialResult> | AgentPluginCredentialResult;
|
|
382
|
+
resolveOAuthAccount?(ctx: ResolveOAuthAccountHookContext): Promise<AgentPluginProviderAccount | undefined> | AgentPluginProviderAccount | undefined;
|
|
208
383
|
routes?(ctx: RouteRegistrationHookContext): AgentPluginRoute[];
|
|
209
384
|
tools?(ctx: ToolRegistrationHookContext): Record<string, AgentPluginToolDefinition>;
|
|
210
385
|
heartbeat?(ctx: HeartbeatHookContext): Promise<HeartbeatResult | void> | HeartbeatResult | void;
|
|
@@ -217,6 +392,21 @@ export interface JuniorPluginOAuthConfig {
|
|
|
217
392
|
clientIdEnv: string;
|
|
218
393
|
clientSecretEnv: string;
|
|
219
394
|
scope?: string;
|
|
395
|
+
/**
|
|
396
|
+
* Treat a provider token response with `scope: ""` like an omitted scope and
|
|
397
|
+
* fall back to the requested scope string when storing the token.
|
|
398
|
+
*
|
|
399
|
+
* Enable this only for providers whose token responses cannot report OAuth
|
|
400
|
+
* scopes even though Junior needs a local requested-scope string for
|
|
401
|
+
* reauthorization checks. The built-in GitHub App plugin enables this because
|
|
402
|
+
* GitHub App user-to-server tokens always return an empty scope value — their
|
|
403
|
+
* effective access is enforced by GitHub App permissions, installation
|
|
404
|
+
* repository access, and the requesting user's own access, not OAuth scopes.
|
|
405
|
+
*
|
|
406
|
+
* Do not enable this for standard OAuth providers where an explicit empty
|
|
407
|
+
* `scope` means the provider granted no scopes.
|
|
408
|
+
*/
|
|
409
|
+
treatEmptyScopeAsUnreported?: boolean;
|
|
220
410
|
tokenAuthMethod?: "body" | "basic";
|
|
221
411
|
tokenEndpoint: string;
|
|
222
412
|
tokenExtraHeaders?: Record<string, string>;
|
|
@@ -228,17 +418,7 @@ export interface JuniorPluginOAuthBearerCredentials {
|
|
|
228
418
|
domains: string[];
|
|
229
419
|
type: "oauth-bearer";
|
|
230
420
|
}
|
|
231
|
-
export
|
|
232
|
-
apiHeaders?: Record<string, string>;
|
|
233
|
-
appIdEnv: string;
|
|
234
|
-
authTokenEnv: string;
|
|
235
|
-
authTokenPlaceholder?: string;
|
|
236
|
-
domains: string[];
|
|
237
|
-
installationIdEnv: string;
|
|
238
|
-
privateKeyEnv: string;
|
|
239
|
-
type: "github-app";
|
|
240
|
-
}
|
|
241
|
-
export type JuniorPluginCredentials = JuniorPluginOAuthBearerCredentials | JuniorPluginGitHubAppCredentials;
|
|
421
|
+
export type JuniorPluginCredentials = JuniorPluginOAuthBearerCredentials;
|
|
242
422
|
export interface JuniorPluginNpmRuntimeDependency {
|
|
243
423
|
package: string;
|
|
244
424
|
type: "npm";
|
|
@@ -301,3 +481,4 @@ export interface JuniorPluginRegistration extends JuniorPluginRegistrationInput
|
|
|
301
481
|
}
|
|
302
482
|
/** Define one Junior plugin registration for app and build-time wiring. */
|
|
303
483
|
export declare function defineJuniorPlugin(plugin: JuniorPluginRegistrationInput): JuniorPluginRegistration;
|
|
484
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,126 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var slackTeamIdSchema = z.string().regex(/^T[A-Z0-9]+$/);
|
|
4
|
+
var slackConversationIdSchema = z.string().regex(/^(C|G|D)[A-Z0-9]+$/);
|
|
5
|
+
var exactActorUserIdSchema = z.string().min(1).refine(
|
|
6
|
+
(value) => value === value.trim() && value.toLowerCase() !== "unknown"
|
|
7
|
+
);
|
|
8
|
+
var nonBlankStringSchema = z.string().refine((value) => value.trim().length > 0);
|
|
9
|
+
var destinationSchema = z.object({
|
|
10
|
+
platform: z.literal("slack"),
|
|
11
|
+
teamId: slackTeamIdSchema,
|
|
12
|
+
channelId: slackConversationIdSchema
|
|
13
|
+
}).strict();
|
|
14
|
+
var agentPluginCredentialSubjectSchema = z.object({
|
|
15
|
+
type: z.literal("user"),
|
|
16
|
+
userId: exactActorUserIdSchema,
|
|
17
|
+
allowedWhen: z.literal("private-direct-conversation")
|
|
18
|
+
}).strict();
|
|
19
|
+
var agentPluginRequesterSchema = z.object({
|
|
20
|
+
userId: exactActorUserIdSchema.optional(),
|
|
21
|
+
userName: nonBlankStringSchema.optional(),
|
|
22
|
+
fullName: nonBlankStringSchema.optional(),
|
|
23
|
+
email: nonBlankStringSchema.optional()
|
|
24
|
+
}).strict();
|
|
25
|
+
var dispatchMetadataSchema = z.record(z.string(), z.string()).superRefine((metadata, ctx) => {
|
|
26
|
+
const entries = Object.entries(metadata);
|
|
27
|
+
if (entries.length > 20) {
|
|
28
|
+
ctx.addIssue({
|
|
29
|
+
code: z.ZodIssueCode.custom,
|
|
30
|
+
message: "Dispatch metadata has too many keys"
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
for (const [key, value] of entries) {
|
|
35
|
+
if (!key.trim()) {
|
|
36
|
+
ctx.addIssue({
|
|
37
|
+
code: z.ZodIssueCode.custom,
|
|
38
|
+
message: "Dispatch metadata values must be strings",
|
|
39
|
+
path: [key]
|
|
40
|
+
});
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (key.length > 128) {
|
|
44
|
+
ctx.addIssue({
|
|
45
|
+
code: z.ZodIssueCode.custom,
|
|
46
|
+
message: "Dispatch metadata key exceeds the maximum length",
|
|
47
|
+
path: [key]
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (value.length > 512) {
|
|
51
|
+
ctx.addIssue({
|
|
52
|
+
code: z.ZodIssueCode.custom,
|
|
53
|
+
message: "Dispatch metadata value exceeds the maximum length",
|
|
54
|
+
path: [key]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
var dispatchOptionsSchema = z.object({
|
|
60
|
+
idempotencyKey: nonBlankStringSchema.pipe(z.string().max(512)),
|
|
61
|
+
credentialSubject: agentPluginCredentialSubjectSchema.optional(),
|
|
62
|
+
destination: destinationSchema,
|
|
63
|
+
input: nonBlankStringSchema.pipe(z.string().max(32e3)),
|
|
64
|
+
metadata: dispatchMetadataSchema.optional()
|
|
65
|
+
}).strict();
|
|
2
66
|
var AgentPluginToolInputError = class extends Error {
|
|
3
67
|
constructor(message, options) {
|
|
4
68
|
super(message, options);
|
|
5
69
|
this.name = "AgentPluginToolInputError";
|
|
6
70
|
}
|
|
7
71
|
};
|
|
72
|
+
var agentPluginProviderNameSchema = z.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
73
|
+
var agentPluginGrantNameSchema = z.string().regex(/^[a-z][a-z0-9.-]*$/);
|
|
74
|
+
var agentPluginGrantAccessSchema = z.union([
|
|
75
|
+
z.literal("read"),
|
|
76
|
+
z.literal("write")
|
|
77
|
+
]);
|
|
78
|
+
var agentPluginAuthorizationSchema = z.object({
|
|
79
|
+
provider: agentPluginProviderNameSchema,
|
|
80
|
+
scope: nonBlankStringSchema.optional(),
|
|
81
|
+
type: z.literal("oauth")
|
|
82
|
+
}).strict();
|
|
83
|
+
var agentPluginProviderAccountSchema = z.object({
|
|
84
|
+
id: nonBlankStringSchema,
|
|
85
|
+
label: nonBlankStringSchema.optional(),
|
|
86
|
+
url: nonBlankStringSchema.optional()
|
|
87
|
+
}).strict();
|
|
88
|
+
var agentPluginGrantSchema = z.object({
|
|
89
|
+
access: agentPluginGrantAccessSchema,
|
|
90
|
+
name: agentPluginGrantNameSchema,
|
|
91
|
+
reason: nonBlankStringSchema.optional(),
|
|
92
|
+
requirements: z.array(nonBlankStringSchema).min(1).optional()
|
|
93
|
+
}).strict();
|
|
94
|
+
var agentPluginCredentialHeaderTransformSchema = z.object({
|
|
95
|
+
domain: z.string().min(1),
|
|
96
|
+
headers: z.record(z.string(), z.string()).refine((headers) => Object.keys(headers).length > 0)
|
|
97
|
+
}).strict();
|
|
98
|
+
var agentPluginCredentialLeaseSchema = z.object({
|
|
99
|
+
account: agentPluginProviderAccountSchema.optional(),
|
|
100
|
+
authorization: agentPluginAuthorizationSchema.optional(),
|
|
101
|
+
expiresAt: z.string().refine((value) => Number.isFinite(Date.parse(value))),
|
|
102
|
+
headerTransforms: z.array(agentPluginCredentialHeaderTransformSchema).min(1)
|
|
103
|
+
}).strict();
|
|
104
|
+
var agentPluginCredentialResultSchema = z.discriminatedUnion("type", [
|
|
105
|
+
z.object({
|
|
106
|
+
lease: agentPluginCredentialLeaseSchema,
|
|
107
|
+
type: z.literal("lease")
|
|
108
|
+
}).strict(),
|
|
109
|
+
z.object({
|
|
110
|
+
authorization: agentPluginAuthorizationSchema.optional(),
|
|
111
|
+
message: nonBlankStringSchema,
|
|
112
|
+
type: z.literal("needed")
|
|
113
|
+
}).strict(),
|
|
114
|
+
z.object({
|
|
115
|
+
message: nonBlankStringSchema,
|
|
116
|
+
type: z.literal("unavailable")
|
|
117
|
+
}).strict()
|
|
118
|
+
]);
|
|
8
119
|
var PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
9
120
|
function defineJuniorPlugin(plugin) {
|
|
10
121
|
if ("pluginConfig" in plugin) {
|
|
11
122
|
throw new Error(
|
|
12
|
-
"pluginConfig is no longer supported. Put runtime metadata in manifest and
|
|
123
|
+
"pluginConfig is no longer supported. Put runtime metadata in manifest and state prefixes on the plugin registration."
|
|
13
124
|
);
|
|
14
125
|
}
|
|
15
126
|
const manifest = plugin.manifest;
|
|
@@ -46,5 +157,15 @@ function defineJuniorPlugin(plugin) {
|
|
|
46
157
|
}
|
|
47
158
|
export {
|
|
48
159
|
AgentPluginToolInputError,
|
|
49
|
-
|
|
160
|
+
agentPluginAuthorizationSchema,
|
|
161
|
+
agentPluginCredentialHeaderTransformSchema,
|
|
162
|
+
agentPluginCredentialLeaseSchema,
|
|
163
|
+
agentPluginCredentialResultSchema,
|
|
164
|
+
agentPluginCredentialSubjectSchema,
|
|
165
|
+
agentPluginGrantSchema,
|
|
166
|
+
agentPluginProviderAccountSchema,
|
|
167
|
+
agentPluginRequesterSchema,
|
|
168
|
+
defineJuniorPlugin,
|
|
169
|
+
destinationSchema,
|
|
170
|
+
dispatchOptionsSchema
|
|
50
171
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-plugin-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.69.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
"dist",
|
|
22
22
|
"src"
|
|
23
23
|
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"zod": "^4.4.3"
|
|
26
|
+
},
|
|
24
27
|
"devDependencies": {
|
|
25
28
|
"oxlint": "^1.66.0",
|
|
26
29
|
"tsup": "^8.5.1",
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const slackTeamIdSchema = z.string().regex(/^T[A-Z0-9]+$/);
|
|
4
|
+
const slackConversationIdSchema = z.string().regex(/^(C|G|D)[A-Z0-9]+$/);
|
|
5
|
+
const exactActorUserIdSchema = z
|
|
6
|
+
.string()
|
|
7
|
+
.min(1)
|
|
8
|
+
.refine(
|
|
9
|
+
(value) => value === value.trim() && value.toLowerCase() !== "unknown",
|
|
10
|
+
);
|
|
11
|
+
const nonBlankStringSchema = z
|
|
12
|
+
.string()
|
|
13
|
+
.refine((value) => value.trim().length > 0);
|
|
14
|
+
|
|
15
|
+
/** Runtime-owned provider-neutral address for routing future work or side effects. */
|
|
16
|
+
export const destinationSchema = z
|
|
17
|
+
.object({
|
|
18
|
+
platform: z.literal("slack"),
|
|
19
|
+
teamId: slackTeamIdSchema,
|
|
20
|
+
channelId: slackConversationIdSchema,
|
|
21
|
+
})
|
|
22
|
+
.strict();
|
|
23
|
+
|
|
24
|
+
/** Stable user credential subject shape accepted from plugins. */
|
|
25
|
+
export const agentPluginCredentialSubjectSchema = z
|
|
26
|
+
.object({
|
|
27
|
+
type: z.literal("user"),
|
|
28
|
+
userId: exactActorUserIdSchema,
|
|
29
|
+
allowedWhen: z.literal("private-direct-conversation"),
|
|
30
|
+
})
|
|
31
|
+
.strict();
|
|
32
|
+
|
|
33
|
+
/** Runtime-provided requester identity visible to plugin hooks. */
|
|
34
|
+
export const agentPluginRequesterSchema = z
|
|
35
|
+
.object({
|
|
36
|
+
userId: exactActorUserIdSchema.optional(),
|
|
37
|
+
userName: nonBlankStringSchema.optional(),
|
|
38
|
+
fullName: nonBlankStringSchema.optional(),
|
|
39
|
+
email: nonBlankStringSchema.optional(),
|
|
40
|
+
})
|
|
41
|
+
.strict();
|
|
42
|
+
|
|
43
|
+
const dispatchMetadataSchema = z
|
|
44
|
+
.record(z.string(), z.string())
|
|
45
|
+
.superRefine((metadata, ctx) => {
|
|
46
|
+
const entries = Object.entries(metadata);
|
|
47
|
+
if (entries.length > 20) {
|
|
48
|
+
ctx.addIssue({
|
|
49
|
+
code: z.ZodIssueCode.custom,
|
|
50
|
+
message: "Dispatch metadata has too many keys",
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (const [key, value] of entries) {
|
|
55
|
+
if (!key.trim()) {
|
|
56
|
+
ctx.addIssue({
|
|
57
|
+
code: z.ZodIssueCode.custom,
|
|
58
|
+
message: "Dispatch metadata values must be strings",
|
|
59
|
+
path: [key],
|
|
60
|
+
});
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (key.length > 128) {
|
|
64
|
+
ctx.addIssue({
|
|
65
|
+
code: z.ZodIssueCode.custom,
|
|
66
|
+
message: "Dispatch metadata key exceeds the maximum length",
|
|
67
|
+
path: [key],
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (value.length > 512) {
|
|
71
|
+
ctx.addIssue({
|
|
72
|
+
code: z.ZodIssueCode.custom,
|
|
73
|
+
message: "Dispatch metadata value exceeds the maximum length",
|
|
74
|
+
path: [key],
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/** Plugin dispatch request accepted by Junior core. */
|
|
81
|
+
export const dispatchOptionsSchema = z
|
|
82
|
+
.object({
|
|
83
|
+
idempotencyKey: nonBlankStringSchema.pipe(z.string().max(512)),
|
|
84
|
+
credentialSubject: agentPluginCredentialSubjectSchema.optional(),
|
|
85
|
+
destination: destinationSchema,
|
|
86
|
+
input: nonBlankStringSchema.pipe(z.string().max(32_000)),
|
|
87
|
+
metadata: dispatchMetadataSchema.optional(),
|
|
88
|
+
})
|
|
89
|
+
.strict();
|
|
90
|
+
|
|
91
|
+
export type AgentPluginRequester = z.output<typeof agentPluginRequesterSchema>;
|
|
7
92
|
|
|
8
93
|
export interface AgentPluginMetadata {
|
|
9
94
|
name: string;
|
|
@@ -25,7 +110,7 @@ export interface AgentPluginLogger {
|
|
|
25
110
|
warn(message: string, metadata?: Record<string, unknown>): void;
|
|
26
111
|
}
|
|
27
112
|
|
|
28
|
-
/** Thrown when a
|
|
113
|
+
/** Thrown when a plugin tool rejects invalid model or user input. */
|
|
29
114
|
export class AgentPluginToolInputError extends Error {
|
|
30
115
|
constructor(message: string, options?: { cause?: unknown }) {
|
|
31
116
|
super(message, options);
|
|
@@ -104,13 +189,36 @@ export interface AgentPluginToolDefinition<TInput = unknown> {
|
|
|
104
189
|
}
|
|
105
190
|
|
|
106
191
|
export interface ToolRegistrationHookContext extends AgentPluginContext {
|
|
192
|
+
/**
|
|
193
|
+
* Capabilities of `channelId` — the raw conversation channel exposed to
|
|
194
|
+
* this plugin. Recomputed from `channelId`, not from `destination`.
|
|
195
|
+
*/
|
|
107
196
|
channelCapabilities?: {
|
|
108
197
|
canAddReactions: boolean;
|
|
109
198
|
canCreateCanvas: boolean;
|
|
110
199
|
canPostToChannel: boolean;
|
|
111
200
|
};
|
|
201
|
+
/**
|
|
202
|
+
* The raw Slack channel ID for this conversation — the DM or channel where
|
|
203
|
+
* this turn is happening, without any assistant-context-source override.
|
|
204
|
+
* Use this as the stable binding key for state scoped to a Slack conversation.
|
|
205
|
+
* `channelCapabilities` describes this channel.
|
|
206
|
+
*/
|
|
112
207
|
channelId?: string;
|
|
208
|
+
/**
|
|
209
|
+
* Opaque Junior conversation/session identity for this turn.
|
|
210
|
+
* Interactive Slack turns use `slack:{channelId}:{threadTs}`.
|
|
211
|
+
* Scheduled/API turns use an internal id such as `agent-dispatch:{id}`.
|
|
212
|
+
* Do not parse as Slack unless the value starts with `slack:`.
|
|
213
|
+
*/
|
|
214
|
+
conversationId?: string;
|
|
113
215
|
credentialSubject?: AgentPluginCredentialSubject;
|
|
216
|
+
/**
|
|
217
|
+
* Runtime-owned destination suitable for future autonomous dispatch. For
|
|
218
|
+
* Slack, this is the raw conversation channel, not a thread timestamp or
|
|
219
|
+
* assistant-context source channel.
|
|
220
|
+
*/
|
|
221
|
+
destination?: Destination;
|
|
114
222
|
messageTs?: string;
|
|
115
223
|
requester?: AgentPluginRequester;
|
|
116
224
|
state: AgentPluginState;
|
|
@@ -119,23 +227,13 @@ export interface ToolRegistrationHookContext extends AgentPluginContext {
|
|
|
119
227
|
userText?: string;
|
|
120
228
|
}
|
|
121
229
|
|
|
122
|
-
export
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
allowedWhen: "private-direct-conversation";
|
|
126
|
-
}
|
|
230
|
+
export type AgentPluginCredentialSubject = z.output<
|
|
231
|
+
typeof agentPluginCredentialSubjectSchema
|
|
232
|
+
>;
|
|
127
233
|
|
|
128
|
-
export
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
platform: "slack";
|
|
132
|
-
teamId: string;
|
|
133
|
-
channelId: string;
|
|
134
|
-
};
|
|
135
|
-
idempotencyKey: string;
|
|
136
|
-
input: string;
|
|
137
|
-
metadata?: Record<string, string>;
|
|
138
|
-
}
|
|
234
|
+
export type Destination = z.output<typeof destinationSchema>;
|
|
235
|
+
|
|
236
|
+
export type DispatchOptions = z.output<typeof dispatchOptionsSchema>;
|
|
139
237
|
|
|
140
238
|
export interface DispatchResult {
|
|
141
239
|
id: string;
|
|
@@ -256,9 +354,187 @@ export interface SlackConversationLinkHookContext extends AgentPluginContext {
|
|
|
256
354
|
conversationId: string;
|
|
257
355
|
}
|
|
258
356
|
|
|
357
|
+
const agentPluginProviderNameSchema = z.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
358
|
+
const agentPluginGrantNameSchema = z.string().regex(/^[a-z][a-z0-9.-]*$/);
|
|
359
|
+
const agentPluginGrantAccessSchema = z.union([
|
|
360
|
+
z.literal("read"),
|
|
361
|
+
z.literal("write"),
|
|
362
|
+
]);
|
|
363
|
+
|
|
364
|
+
/** Runtime schema for provider authorization a plugin may request. */
|
|
365
|
+
export const agentPluginAuthorizationSchema = z
|
|
366
|
+
.object({
|
|
367
|
+
provider: agentPluginProviderNameSchema,
|
|
368
|
+
scope: nonBlankStringSchema.optional(),
|
|
369
|
+
type: z.literal("oauth"),
|
|
370
|
+
})
|
|
371
|
+
.strict();
|
|
372
|
+
|
|
373
|
+
/** Runtime schema for a provider account attached to stored OAuth tokens. */
|
|
374
|
+
export const agentPluginProviderAccountSchema = z
|
|
375
|
+
.object({
|
|
376
|
+
id: nonBlankStringSchema,
|
|
377
|
+
label: nonBlankStringSchema.optional(),
|
|
378
|
+
url: nonBlankStringSchema.optional(),
|
|
379
|
+
})
|
|
380
|
+
.strict();
|
|
381
|
+
|
|
382
|
+
/** Runtime schema for a plugin-defined outbound credential grant. */
|
|
383
|
+
export const agentPluginGrantSchema = z
|
|
384
|
+
.object({
|
|
385
|
+
access: agentPluginGrantAccessSchema,
|
|
386
|
+
name: agentPluginGrantNameSchema,
|
|
387
|
+
reason: nonBlankStringSchema.optional(),
|
|
388
|
+
requirements: z.array(nonBlankStringSchema).min(1).optional(),
|
|
389
|
+
})
|
|
390
|
+
.strict();
|
|
391
|
+
|
|
392
|
+
/** Runtime schema for plugin-issued header mutations. */
|
|
393
|
+
export const agentPluginCredentialHeaderTransformSchema = z
|
|
394
|
+
.object({
|
|
395
|
+
domain: z.string().min(1),
|
|
396
|
+
headers: z
|
|
397
|
+
.record(z.string(), z.string())
|
|
398
|
+
.refine((headers) => Object.keys(headers).length > 0),
|
|
399
|
+
})
|
|
400
|
+
.strict();
|
|
401
|
+
|
|
402
|
+
/** Runtime schema for a short-lived plugin-issued credential lease. */
|
|
403
|
+
export const agentPluginCredentialLeaseSchema = z
|
|
404
|
+
.object({
|
|
405
|
+
account: agentPluginProviderAccountSchema.optional(),
|
|
406
|
+
authorization: agentPluginAuthorizationSchema.optional(),
|
|
407
|
+
expiresAt: z.string().refine((value) => Number.isFinite(Date.parse(value))),
|
|
408
|
+
headerTransforms: z
|
|
409
|
+
.array(agentPluginCredentialHeaderTransformSchema)
|
|
410
|
+
.min(1),
|
|
411
|
+
})
|
|
412
|
+
.strict();
|
|
413
|
+
|
|
414
|
+
/** Runtime schema for the result returned by a plugin credential hook. */
|
|
415
|
+
export const agentPluginCredentialResultSchema = z.discriminatedUnion("type", [
|
|
416
|
+
z
|
|
417
|
+
.object({
|
|
418
|
+
lease: agentPluginCredentialLeaseSchema,
|
|
419
|
+
type: z.literal("lease"),
|
|
420
|
+
})
|
|
421
|
+
.strict(),
|
|
422
|
+
z
|
|
423
|
+
.object({
|
|
424
|
+
authorization: agentPluginAuthorizationSchema.optional(),
|
|
425
|
+
message: nonBlankStringSchema,
|
|
426
|
+
type: z.literal("needed"),
|
|
427
|
+
})
|
|
428
|
+
.strict(),
|
|
429
|
+
z
|
|
430
|
+
.object({
|
|
431
|
+
message: nonBlankStringSchema,
|
|
432
|
+
type: z.literal("unavailable"),
|
|
433
|
+
})
|
|
434
|
+
.strict(),
|
|
435
|
+
]);
|
|
436
|
+
|
|
437
|
+
export type AgentPluginGrantAccess = z.output<
|
|
438
|
+
typeof agentPluginGrantAccessSchema
|
|
439
|
+
>;
|
|
440
|
+
|
|
441
|
+
/** Provider authorization Junior can start when a plugin-owned grant is missing. */
|
|
442
|
+
export type AgentPluginAuthorization = z.output<
|
|
443
|
+
typeof agentPluginAuthorizationSchema
|
|
444
|
+
>;
|
|
445
|
+
|
|
446
|
+
/** Provider account identity resolved by a plugin OAuth hook. */
|
|
447
|
+
export type AgentPluginProviderAccount = z.output<
|
|
448
|
+
typeof agentPluginProviderAccountSchema
|
|
449
|
+
>;
|
|
450
|
+
|
|
451
|
+
/** Plugin-defined grant required before Junior can forward one outbound request. */
|
|
452
|
+
export type AgentPluginGrant = z.output<typeof agentPluginGrantSchema>;
|
|
453
|
+
|
|
454
|
+
/** Request details available while selecting the grant for sandbox egress. */
|
|
455
|
+
export interface AgentPluginEgressRequest {
|
|
456
|
+
method: string;
|
|
457
|
+
url: string;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export interface EgressHookContext extends AgentPluginContext {
|
|
461
|
+
request: AgentPluginEgressRequest;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** Header mutations a plugin-issued credential lease may apply to owned domains. */
|
|
465
|
+
export type AgentPluginCredentialHeaderTransform = z.output<
|
|
466
|
+
typeof agentPluginCredentialHeaderTransformSchema
|
|
467
|
+
>;
|
|
468
|
+
|
|
469
|
+
/** Short-lived credential headers issued by a plugin for a selected grant. */
|
|
470
|
+
export type AgentPluginCredentialLease = z.output<
|
|
471
|
+
typeof agentPluginCredentialLeaseSchema
|
|
472
|
+
>;
|
|
473
|
+
|
|
474
|
+
export type AgentPluginCredentialResult = z.output<
|
|
475
|
+
typeof agentPluginCredentialResultSchema
|
|
476
|
+
>;
|
|
477
|
+
|
|
478
|
+
export type AgentPluginCredentialActor =
|
|
479
|
+
| {
|
|
480
|
+
type: "system";
|
|
481
|
+
id: string;
|
|
482
|
+
}
|
|
483
|
+
| {
|
|
484
|
+
type: "user";
|
|
485
|
+
userId: string;
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
export interface AgentPluginResolvedCredentialUser {
|
|
489
|
+
type: "user";
|
|
490
|
+
userId: string;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export interface AgentPluginStoredTokens {
|
|
494
|
+
account?: AgentPluginProviderAccount;
|
|
495
|
+
accessToken: string;
|
|
496
|
+
expiresAt?: number;
|
|
497
|
+
refreshToken: string;
|
|
498
|
+
scope?: string;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
export interface AgentPluginUserTokenSlot {
|
|
502
|
+
get(): Promise<AgentPluginStoredTokens | undefined>;
|
|
503
|
+
set(tokens: AgentPluginStoredTokens): Promise<void>;
|
|
504
|
+
userId: string;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export interface AgentPluginTokenStore {
|
|
508
|
+
credentialSubject?: AgentPluginUserTokenSlot;
|
|
509
|
+
currentUser?: AgentPluginUserTokenSlot;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
export interface ResolveOAuthAccountHookContext extends AgentPluginContext {
|
|
513
|
+
tokens: AgentPluginStoredTokens;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export interface IssueCredentialHookContext extends AgentPluginContext {
|
|
517
|
+
actor: AgentPluginCredentialActor;
|
|
518
|
+
credentialSubject?: AgentPluginResolvedCredentialUser;
|
|
519
|
+
grant: AgentPluginGrant;
|
|
520
|
+
tokens: AgentPluginTokenStore;
|
|
521
|
+
}
|
|
522
|
+
|
|
259
523
|
export interface AgentPluginHooks {
|
|
260
524
|
sandboxPrepare?(ctx: SandboxPrepareHookContext): Promise<void> | void;
|
|
261
525
|
beforeToolExecute?(ctx: BeforeToolExecuteHookContext): Promise<void> | void;
|
|
526
|
+
grantForEgress?(
|
|
527
|
+
ctx: EgressHookContext,
|
|
528
|
+
): Promise<AgentPluginGrant | undefined> | AgentPluginGrant | undefined;
|
|
529
|
+
issueCredential?(
|
|
530
|
+
ctx: IssueCredentialHookContext,
|
|
531
|
+
): Promise<AgentPluginCredentialResult> | AgentPluginCredentialResult;
|
|
532
|
+
resolveOAuthAccount?(
|
|
533
|
+
ctx: ResolveOAuthAccountHookContext,
|
|
534
|
+
):
|
|
535
|
+
| Promise<AgentPluginProviderAccount | undefined>
|
|
536
|
+
| AgentPluginProviderAccount
|
|
537
|
+
| undefined;
|
|
262
538
|
routes?(ctx: RouteRegistrationHookContext): AgentPluginRoute[];
|
|
263
539
|
tools?(
|
|
264
540
|
ctx: ToolRegistrationHookContext,
|
|
@@ -283,6 +559,21 @@ export interface JuniorPluginOAuthConfig {
|
|
|
283
559
|
clientIdEnv: string;
|
|
284
560
|
clientSecretEnv: string;
|
|
285
561
|
scope?: string;
|
|
562
|
+
/**
|
|
563
|
+
* Treat a provider token response with `scope: ""` like an omitted scope and
|
|
564
|
+
* fall back to the requested scope string when storing the token.
|
|
565
|
+
*
|
|
566
|
+
* Enable this only for providers whose token responses cannot report OAuth
|
|
567
|
+
* scopes even though Junior needs a local requested-scope string for
|
|
568
|
+
* reauthorization checks. The built-in GitHub App plugin enables this because
|
|
569
|
+
* GitHub App user-to-server tokens always return an empty scope value — their
|
|
570
|
+
* effective access is enforced by GitHub App permissions, installation
|
|
571
|
+
* repository access, and the requesting user's own access, not OAuth scopes.
|
|
572
|
+
*
|
|
573
|
+
* Do not enable this for standard OAuth providers where an explicit empty
|
|
574
|
+
* `scope` means the provider granted no scopes.
|
|
575
|
+
*/
|
|
576
|
+
treatEmptyScopeAsUnreported?: boolean;
|
|
286
577
|
tokenAuthMethod?: "body" | "basic";
|
|
287
578
|
tokenEndpoint: string;
|
|
288
579
|
tokenExtraHeaders?: Record<string, string>;
|
|
@@ -296,20 +587,7 @@ export interface JuniorPluginOAuthBearerCredentials {
|
|
|
296
587
|
type: "oauth-bearer";
|
|
297
588
|
}
|
|
298
589
|
|
|
299
|
-
export
|
|
300
|
-
apiHeaders?: Record<string, string>;
|
|
301
|
-
appIdEnv: string;
|
|
302
|
-
authTokenEnv: string;
|
|
303
|
-
authTokenPlaceholder?: string;
|
|
304
|
-
domains: string[];
|
|
305
|
-
installationIdEnv: string;
|
|
306
|
-
privateKeyEnv: string;
|
|
307
|
-
type: "github-app";
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export type JuniorPluginCredentials =
|
|
311
|
-
| JuniorPluginOAuthBearerCredentials
|
|
312
|
-
| JuniorPluginGitHubAppCredentials;
|
|
590
|
+
export type JuniorPluginCredentials = JuniorPluginOAuthBearerCredentials;
|
|
313
591
|
|
|
314
592
|
export interface JuniorPluginNpmRuntimeDependency {
|
|
315
593
|
package: string;
|
|
@@ -392,7 +670,7 @@ export function defineJuniorPlugin(
|
|
|
392
670
|
): JuniorPluginRegistration {
|
|
393
671
|
if ("pluginConfig" in plugin) {
|
|
394
672
|
throw new Error(
|
|
395
|
-
"pluginConfig is no longer supported. Put runtime metadata in manifest and
|
|
673
|
+
"pluginConfig is no longer supported. Put runtime metadata in manifest and state prefixes on the plugin registration.",
|
|
396
674
|
);
|
|
397
675
|
}
|
|
398
676
|
const manifest = plugin.manifest;
|