@sentry/junior-plugin-api 0.261.0 → 0.263.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 +62 -1
- package/dist/index.js +127 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -505,6 +505,29 @@ export declare const dispatchOptionsSchema: z.ZodObject<{
|
|
|
505
505
|
detail: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodString>>;
|
|
506
506
|
}, z.core.$strict>>;
|
|
507
507
|
}, z.core.$strict>;
|
|
508
|
+
/** A loaded value and how long to cache it. */
|
|
509
|
+
export interface CacheEntry<T> {
|
|
510
|
+
/** Omit to return the value without caching it, such as for an incomplete response. */
|
|
511
|
+
ttlMs?: number;
|
|
512
|
+
/** Must survive JSON serialization. */
|
|
513
|
+
value: T;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Short-lived copies of values that are slow or costly to load, such as
|
|
517
|
+
* provider API reads. Junior can drop an entry at any time. A lost entry only
|
|
518
|
+
* costs a reload, so never keep data here that Junior must not lose. Use
|
|
519
|
+
* `PluginState` for that.
|
|
520
|
+
*/
|
|
521
|
+
export interface PluginCache {
|
|
522
|
+
/**
|
|
523
|
+
* Return the cached value for `key`, or call `load` and cache its result.
|
|
524
|
+
* Concurrent callers share one load. A load that throws is not cached.
|
|
525
|
+
* `refresh` ignores the cached value and replaces it.
|
|
526
|
+
*/
|
|
527
|
+
getOrLoad<T>(key: string, load: () => Promise<CacheEntry<T>>, options?: {
|
|
528
|
+
refresh?: boolean;
|
|
529
|
+
}): Promise<T>;
|
|
530
|
+
}
|
|
508
531
|
/** Runtime platform name without source or destination coordinates. */
|
|
509
532
|
export type Platform = z.output<typeof platformSchema>;
|
|
510
533
|
export type Actor = z.output<typeof actorSchema>;
|
|
@@ -586,6 +609,8 @@ export interface PluginEmbedder {
|
|
|
586
609
|
}>;
|
|
587
610
|
}
|
|
588
611
|
export interface PluginContext {
|
|
612
|
+
/** Short-lived cache scoped to this plugin. */
|
|
613
|
+
cache: PluginCache;
|
|
589
614
|
/** Shared Drizzle database connection for plugin runtime code. */
|
|
590
615
|
db: unknown;
|
|
591
616
|
log: PluginLogger;
|
|
@@ -1805,8 +1830,23 @@ export interface PluginEnv {
|
|
|
1805
1830
|
get(key: string): string | undefined;
|
|
1806
1831
|
set(key: string, value: string): void;
|
|
1807
1832
|
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Decide what happens to one tool call in `beforeToolExecute`.
|
|
1835
|
+
*
|
|
1836
|
+
* `redirect` and `deny` both stop the tool before it runs. Neither ends the
|
|
1837
|
+
* turn: the agent gets the message as the tool result.
|
|
1838
|
+
*/
|
|
1808
1839
|
export interface PluginDecision {
|
|
1809
|
-
|
|
1840
|
+
/**
|
|
1841
|
+
* Block the call as a policy refusal. The agent is told not to retry or
|
|
1842
|
+
* reach the same result another way, and to explain the block.
|
|
1843
|
+
*/
|
|
1844
|
+
deny(reason: string): void;
|
|
1845
|
+
/**
|
|
1846
|
+
* Block the call because a different path is correct, such as another
|
|
1847
|
+
* tool. The message tells the agent what to do instead.
|
|
1848
|
+
*/
|
|
1849
|
+
redirect(message: string): void;
|
|
1810
1850
|
replaceInput(input: Record<string, unknown>): void;
|
|
1811
1851
|
}
|
|
1812
1852
|
/** Thrown when a plugin tool rejects invalid model or user input. */
|
|
@@ -2180,6 +2220,13 @@ export interface PluginEventToolContext {
|
|
|
2180
2220
|
}): Promise<WatchResult>;
|
|
2181
2221
|
}
|
|
2182
2222
|
export interface PluginWorkspaceToolContext {
|
|
2223
|
+
/**
|
|
2224
|
+
* Workspace that the current Sandbox started from. Returns undefined for
|
|
2225
|
+
* the default Sandbox. `name` is missing when the recipe no longer exists.
|
|
2226
|
+
*/
|
|
2227
|
+
active(): Promise<{
|
|
2228
|
+
name?: string;
|
|
2229
|
+
} | undefined>;
|
|
2183
2230
|
/** Find named Workspaces that include one provider repository. */
|
|
2184
2231
|
findByRepository(input: {
|
|
2185
2232
|
provider: string;
|
|
@@ -2235,6 +2282,20 @@ export declare function enforceEgressPolicy(input: {
|
|
|
2235
2282
|
allowed: boolean;
|
|
2236
2283
|
denialMessage: string;
|
|
2237
2284
|
}): void;
|
|
2285
|
+
/**
|
|
2286
|
+
* Split bash command text into simple commands.
|
|
2287
|
+
*
|
|
2288
|
+
* Plugins use this in `beforeToolExecute` to check `bash` tool input. It is a
|
|
2289
|
+
* small parser, not a full shell. It reads quotes, backslashes, control
|
|
2290
|
+
* operators, comments, redirections, and heredocs. It does not expand
|
|
2291
|
+
* variables, aliases, or globs. It does not look inside `sh -c` or `eval`
|
|
2292
|
+
* strings. Use it for best-effort steering only, not as a security boundary.
|
|
2293
|
+
*
|
|
2294
|
+
* Each result is the argv of one simple command. Leading `NAME=value`
|
|
2295
|
+
* assignments, redirections, and heredoc bodies are removed. Text inside
|
|
2296
|
+
* `$(...)`, backticks, and subshells becomes separate commands.
|
|
2297
|
+
*/
|
|
2298
|
+
export declare function parseShellCommands(text: string): string[][];
|
|
2238
2299
|
/** Input for a pure Markdown rewrite before destination delivery formatting. */
|
|
2239
2300
|
export interface FormatMarkdownHookContext {
|
|
2240
2301
|
text: string;
|
package/dist/index.js
CHANGED
|
@@ -1124,6 +1124,132 @@ var EgressPolicyDenied = class extends Error {
|
|
|
1124
1124
|
function enforceEgressPolicy(input) {
|
|
1125
1125
|
if (!input.allowed) throw new EgressPolicyDenied(input.denialMessage);
|
|
1126
1126
|
}
|
|
1127
|
+
// src/shell-command.ts
|
|
1128
|
+
/**
|
|
1129
|
+
* Split bash command text into simple commands.
|
|
1130
|
+
*
|
|
1131
|
+
* Plugins use this in `beforeToolExecute` to check `bash` tool input. It is a
|
|
1132
|
+
* small parser, not a full shell. It reads quotes, backslashes, control
|
|
1133
|
+
* operators, comments, redirections, and heredocs. It does not expand
|
|
1134
|
+
* variables, aliases, or globs. It does not look inside `sh -c` or `eval`
|
|
1135
|
+
* strings. Use it for best-effort steering only, not as a security boundary.
|
|
1136
|
+
*
|
|
1137
|
+
* Each result is the argv of one simple command. Leading `NAME=value`
|
|
1138
|
+
* assignments, redirections, and heredoc bodies are removed. Text inside
|
|
1139
|
+
* `$(...)`, backticks, and subshells becomes separate commands.
|
|
1140
|
+
*/
|
|
1141
|
+
function parseShellCommands(text) {
|
|
1142
|
+
const commands = [];
|
|
1143
|
+
const heredocs = [];
|
|
1144
|
+
let words = [];
|
|
1145
|
+
let word = "";
|
|
1146
|
+
let inWord = false;
|
|
1147
|
+
let skipNextWord = false;
|
|
1148
|
+
const endWord = () => {
|
|
1149
|
+
if (inWord) {
|
|
1150
|
+
if (!skipNextWord) words.push(word);
|
|
1151
|
+
skipNextWord = false;
|
|
1152
|
+
}
|
|
1153
|
+
word = "";
|
|
1154
|
+
inWord = false;
|
|
1155
|
+
};
|
|
1156
|
+
const endCommand = () => {
|
|
1157
|
+
endWord();
|
|
1158
|
+
skipNextWord = false;
|
|
1159
|
+
let start = 0;
|
|
1160
|
+
while (start < words.length && ASSIGNMENT_RE.test(words[start])) start += 1;
|
|
1161
|
+
if (start < words.length) commands.push(words.slice(start));
|
|
1162
|
+
words = [];
|
|
1163
|
+
};
|
|
1164
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
1165
|
+
const char = text[index];
|
|
1166
|
+
if (char === "'") {
|
|
1167
|
+
const end = text.indexOf("'", index + 1);
|
|
1168
|
+
const close = end === -1 ? text.length : end;
|
|
1169
|
+
word += text.slice(index + 1, close);
|
|
1170
|
+
inWord = true;
|
|
1171
|
+
index = close;
|
|
1172
|
+
} else if (char === "\"") {
|
|
1173
|
+
inWord = true;
|
|
1174
|
+
for (index += 1; index < text.length && text[index] !== "\""; index += 1) {
|
|
1175
|
+
if (text[index] === "\\" && DOUBLE_QUOTE_ESCAPES.has(text[index + 1])) index += 1;
|
|
1176
|
+
word += text[index];
|
|
1177
|
+
}
|
|
1178
|
+
} else if (char === "\\") {
|
|
1179
|
+
index += 1;
|
|
1180
|
+
if (index < text.length && text[index] !== "\n") {
|
|
1181
|
+
word += text[index];
|
|
1182
|
+
inWord = true;
|
|
1183
|
+
}
|
|
1184
|
+
} else if (char === "#" && !inWord) {
|
|
1185
|
+
const end = text.indexOf("\n", index);
|
|
1186
|
+
index = (end === -1 ? text.length : end) - 1;
|
|
1187
|
+
} else if (char === "\n") {
|
|
1188
|
+
endCommand();
|
|
1189
|
+
for (const heredoc of heredocs.splice(0)) index = skipHeredocBody(text, index, heredoc);
|
|
1190
|
+
} else if (char === "<" || char === ">") {
|
|
1191
|
+
if (/^\d+$/.test(word)) {
|
|
1192
|
+
word = "";
|
|
1193
|
+
inWord = false;
|
|
1194
|
+
}
|
|
1195
|
+
endWord();
|
|
1196
|
+
if (text.startsWith("<<<", index)) {
|
|
1197
|
+
index += 2;
|
|
1198
|
+
skipNextWord = true;
|
|
1199
|
+
} else if (text.startsWith("<<", index)) {
|
|
1200
|
+
index += 2;
|
|
1201
|
+
const stripTabs = text[index] === "-";
|
|
1202
|
+
if (stripTabs) index += 1;
|
|
1203
|
+
while (text[index] === " " || text[index] === " ") index += 1;
|
|
1204
|
+
let delimiter = "";
|
|
1205
|
+
while (index < text.length && !/[\s;&|()<>]/.test(text[index])) {
|
|
1206
|
+
if (!/['"\\]/.test(text[index])) delimiter += text[index];
|
|
1207
|
+
index += 1;
|
|
1208
|
+
}
|
|
1209
|
+
index -= 1;
|
|
1210
|
+
heredocs.push({
|
|
1211
|
+
delimiter,
|
|
1212
|
+
stripTabs
|
|
1213
|
+
});
|
|
1214
|
+
} else {
|
|
1215
|
+
while (/[<>&|]/.test(text[index + 1] ?? "")) index += 1;
|
|
1216
|
+
skipNextWord = true;
|
|
1217
|
+
}
|
|
1218
|
+
} else if (/[;&|()`]/.test(char)) {
|
|
1219
|
+
if (char === "(" && word.endsWith("$")) {
|
|
1220
|
+
word = word.slice(0, -1);
|
|
1221
|
+
inWord = word.length > 0;
|
|
1222
|
+
}
|
|
1223
|
+
endCommand();
|
|
1224
|
+
} else if (/\s/.test(char)) endWord();
|
|
1225
|
+
else {
|
|
1226
|
+
word += char;
|
|
1227
|
+
inWord = true;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
endCommand();
|
|
1231
|
+
return commands;
|
|
1232
|
+
}
|
|
1233
|
+
const ASSIGNMENT_RE = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
1234
|
+
const DOUBLE_QUOTE_ESCAPES = /* @__PURE__ */ new Set([
|
|
1235
|
+
"\"",
|
|
1236
|
+
"\\",
|
|
1237
|
+
"$",
|
|
1238
|
+
"`"
|
|
1239
|
+
]);
|
|
1240
|
+
/** Return the index of the newline that ends the heredoc delimiter line. */
|
|
1241
|
+
function skipHeredocBody(text, newlineIndex, heredoc) {
|
|
1242
|
+
let index = newlineIndex;
|
|
1243
|
+
while (index < text.length) {
|
|
1244
|
+
const start = index + 1;
|
|
1245
|
+
const found = text.indexOf("\n", start);
|
|
1246
|
+
const end = found === -1 ? text.length : found;
|
|
1247
|
+
const line = text.slice(start, end);
|
|
1248
|
+
index = end;
|
|
1249
|
+
if ((heredoc.stripTabs ? line.replace(/^\t+/, "") : line) === heredoc.delimiter) break;
|
|
1250
|
+
}
|
|
1251
|
+
return index;
|
|
1252
|
+
}
|
|
1127
1253
|
// src/registration.ts
|
|
1128
1254
|
const PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
1129
1255
|
const USER_PAGE_ID_RE = /^[a-z][a-z0-9-]*$/;
|
|
@@ -1242,4 +1368,4 @@ const pluginUserPageInputSchema = z.object({
|
|
|
1242
1368
|
limit: z.number().int().min(1).max(50),
|
|
1243
1369
|
query: pluginUserPageQuerySchema
|
|
1244
1370
|
}).strict();
|
|
1245
|
-
export { EVENT_DATA_MAX_JSON_BYTES, EVENT_DATA_MAX_KEYS, EVENT_GUIDANCE_MAX_LENGTH, EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, REQUIRED_TOOL_ANNOTATION_KEYS, actorSchema, actorUserIdSchema, agentInvocationSourceSchema, codeChangeInputSchema, codeChangeStateSchema, conversationAnnotationInputSchema, conversationEventIconSchema, conversationEventPresentationSchema, conversationSidebarAnnotationSchema, conversationSidebarIconSchema, createEventSource, createLocalSource, createSlackSource, createWebSource, defineConversationEvent, defineJuniorPlugin, definePluginTool, definePromptContext, destinationSchema, destinationVisibilitySchema, dispatchOptionsSchema, enforceEgressPolicy, eventAutomationSourceSchema, eventDataSchema, eventIdentifierSchema, eventInputSchema, eventMatchFieldSchema, eventMatchFieldsSchema, eventMatchSchema, eventMatches, eventPersonSchema, eventSchema, eventSourceSchema, eventTypeSchema, getSourceKey, identitySchema, isPrivateSource, isSlackDestination, localActorSchema, localDestinationSchema, localSourceSchema, locationSchema, missingToolAnnotationKeys, nonBlankStringSchema, normalizeEventIdentifier, objectAnnotationSchema, objectFactFields, objectFactsSchema, objectIconPath, objectIconPaths, objectPresentation, objectTypeSchema, ownedObjectAnnotationSchema, platformSchema, pluginApiRouteRequestContextSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialLeaseSchema, pluginCredentialResultSchema, pluginCredentialSubjectSchema, pluginDispatchSourceSchema, pluginEventTypeSchema, pluginEventsSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginRunContextSchema, pluginRunTranscriptEntrySchema, pluginRunTranscriptProvenanceSchema, pluginStoredTokensSchema, pluginToolContentSchema, pluginToolContinuationSchema, pluginToolOutputSchema, pluginUserPageContentSchema, pluginUserPageCursorSchema, pluginUserPageFilterSchema, pluginUserPageInputSchema, pluginUserPageLinkSchema, pluginUserPageLinksSchema, pluginUserPageQuerySchema, promptContextSchema, promptMessageSchema, replyAttributionSchema, resourceLinkAnnotationSchema, resourceTypeSchema, scheduledAutomationSourceSchema, slackActorSchema, slackDestinationSchema, slackLocationSchema, slackSourceSchema, sourceSchema, sourceVisibilitySchema, stableEventMatchKey, subscribableResourceSchema, systemActorSchema, taskOutcomeSchema, toolApprovalModeSchema, userSchema, watchResultSchema, webActorSchema, webSourceSchema, zodTool };
|
|
1371
|
+
export { EVENT_DATA_MAX_JSON_BYTES, EVENT_DATA_MAX_KEYS, EVENT_GUIDANCE_MAX_LENGTH, EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, REQUIRED_TOOL_ANNOTATION_KEYS, actorSchema, actorUserIdSchema, agentInvocationSourceSchema, codeChangeInputSchema, codeChangeStateSchema, conversationAnnotationInputSchema, conversationEventIconSchema, conversationEventPresentationSchema, conversationSidebarAnnotationSchema, conversationSidebarIconSchema, createEventSource, createLocalSource, createSlackSource, createWebSource, defineConversationEvent, defineJuniorPlugin, definePluginTool, definePromptContext, destinationSchema, destinationVisibilitySchema, dispatchOptionsSchema, enforceEgressPolicy, eventAutomationSourceSchema, eventDataSchema, eventIdentifierSchema, eventInputSchema, eventMatchFieldSchema, eventMatchFieldsSchema, eventMatchSchema, eventMatches, eventPersonSchema, eventSchema, eventSourceSchema, eventTypeSchema, getSourceKey, identitySchema, isPrivateSource, isSlackDestination, localActorSchema, localDestinationSchema, localSourceSchema, locationSchema, missingToolAnnotationKeys, nonBlankStringSchema, normalizeEventIdentifier, objectAnnotationSchema, objectFactFields, objectFactsSchema, objectIconPath, objectIconPaths, objectPresentation, objectTypeSchema, ownedObjectAnnotationSchema, parseShellCommands, platformSchema, pluginApiRouteRequestContextSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialLeaseSchema, pluginCredentialResultSchema, pluginCredentialSubjectSchema, pluginDispatchSourceSchema, pluginEventTypeSchema, pluginEventsSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginRunContextSchema, pluginRunTranscriptEntrySchema, pluginRunTranscriptProvenanceSchema, pluginStoredTokensSchema, pluginToolContentSchema, pluginToolContinuationSchema, pluginToolOutputSchema, pluginUserPageContentSchema, pluginUserPageCursorSchema, pluginUserPageFilterSchema, pluginUserPageInputSchema, pluginUserPageLinkSchema, pluginUserPageLinksSchema, pluginUserPageQuerySchema, promptContextSchema, promptMessageSchema, replyAttributionSchema, resourceLinkAnnotationSchema, resourceTypeSchema, scheduledAutomationSourceSchema, slackActorSchema, slackDestinationSchema, slackLocationSchema, slackSourceSchema, sourceSchema, sourceVisibilitySchema, stableEventMatchKey, subscribableResourceSchema, systemActorSchema, taskOutcomeSchema, toolApprovalModeSchema, userSchema, watchResultSchema, webActorSchema, webSourceSchema, zodTool };
|