@sentry/junior 0.67.3 → 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.
Files changed (66) hide show
  1. package/dist/app.js +1465 -814
  2. package/dist/build/virtual-config.d.ts +2 -2
  3. package/dist/chat/agent-dispatch/heartbeat.d.ts +2 -2
  4. package/dist/chat/agent-dispatch/store.d.ts +4 -1
  5. package/dist/chat/agent-dispatch/types.d.ts +2 -4
  6. package/dist/chat/agent-dispatch/validation.d.ts +3 -2
  7. package/dist/chat/credentials/context.d.ts +49 -24
  8. package/dist/chat/credentials/user-token-store.d.ts +6 -0
  9. package/dist/chat/destination.d.ts +12 -0
  10. package/dist/chat/ingress/message-router.d.ts +1 -1
  11. package/dist/chat/mcp/auth-store.d.ts +2 -0
  12. package/dist/chat/mcp/oauth.d.ts +2 -0
  13. package/dist/chat/oauth-flow.d.ts +7 -0
  14. package/dist/chat/plugins/agent-hooks.d.ts +9 -9
  15. package/dist/chat/plugins/auth/auth-token-placeholder.d.ts +2 -2
  16. package/dist/chat/plugins/auth/oauth-request.d.ts +3 -1
  17. package/dist/chat/plugins/credential-hooks.d.ts +34 -0
  18. package/dist/chat/plugins/logging.d.ts +1 -1
  19. package/dist/chat/plugins/state.d.ts +1 -1
  20. package/dist/chat/plugins/types.d.ts +19 -23
  21. package/dist/chat/respond.d.ts +2 -0
  22. package/dist/chat/runtime/reply-executor.d.ts +3 -1
  23. package/dist/chat/runtime/slack-runtime.d.ts +8 -3
  24. package/dist/chat/sandbox/egress-credentials.d.ts +33 -0
  25. package/dist/chat/sandbox/egress-schemas.d.ts +105 -0
  26. package/dist/chat/sandbox/egress-session.d.ts +17 -17
  27. package/dist/chat/sandbox/sandbox.d.ts +3 -0
  28. package/dist/chat/sandbox/session.d.ts +1 -0
  29. package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -0
  30. package/dist/chat/services/pending-auth.d.ts +2 -0
  31. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -0
  32. package/dist/chat/services/provider-retry.d.ts +13 -4
  33. package/dist/chat/services/timeout-resume.d.ts +2 -0
  34. package/dist/chat/services/turn-session-record.d.ts +6 -0
  35. package/dist/chat/slack/attachment-fetchers.d.ts +11 -0
  36. package/dist/chat/slack/footer.d.ts +2 -7
  37. package/dist/chat/state/conversation.d.ts +1 -0
  38. package/dist/chat/state/turn-session.d.ts +4 -0
  39. package/dist/chat/task-execution/queue.d.ts +2 -0
  40. package/dist/chat/task-execution/store.d.ts +5 -0
  41. package/dist/chat/task-execution/vercel-callback.d.ts +4 -0
  42. package/dist/chat/task-execution/vercel-queue.d.ts +2 -0
  43. package/dist/chat/task-execution/worker.d.ts +4 -2
  44. package/dist/chat/tools/slack/context.d.ts +3 -0
  45. package/dist/chat/tools/types.d.ts +21 -2
  46. package/dist/chunk-76YMBKW7.js +326 -0
  47. package/dist/{chunk-PIVOJIUD.js → chunk-B5HKWWQB.js} +9 -5
  48. package/dist/chunk-BBXYXOJW.js +1858 -0
  49. package/dist/{chunk-V47RLIO2.js → chunk-GT67ZWZQ.js} +4 -4
  50. package/dist/{chunk-75UZ4JLC.js → chunk-IGLNC5H6.js} +21 -9
  51. package/dist/{chunk-EBVQXCD2.js → chunk-JS4HURDT.js} +362 -280
  52. package/dist/{chunk-UQQSW7QB.js → chunk-N3MORKTH.js} +74 -331
  53. package/dist/chunk-R62YWUNO.js +264 -0
  54. package/dist/{chunk-OIIXZOOC.js → chunk-UXG6TU2U.js} +311 -2015
  55. package/dist/cli/check.js +4 -4
  56. package/dist/cli/snapshot-warmup.js +5 -4
  57. package/dist/nitro.d.ts +1 -1
  58. package/dist/nitro.js +21 -19
  59. package/dist/plugins.d.ts +2 -2
  60. package/dist/reporting.d.ts +2 -2
  61. package/dist/reporting.js +13 -11
  62. package/package.json +6 -4
  63. package/dist/chat/plugins/auth/github-app-broker.d.ts +0 -4
  64. package/dist/chat/plugins/github-permissions.d.ts +0 -11
  65. package/dist/chat/queue/thread-message-dispatcher.d.ts +0 -33
  66. package/dist/chunk-KVZL5NZS.js +0 -519
@@ -1,30 +1,39 @@
1
1
  import {
2
2
  SANDBOX_DATA_ROOT,
3
3
  SANDBOX_WORKSPACE_ROOT,
4
- botConfig,
5
- getChatConfig,
6
4
  getConnectedStateContext,
7
- getSlackBotToken,
8
5
  getStateAdapter,
9
- parseSlackThreadId,
10
6
  sandboxSkillDir
11
- } from "./chunk-EBVQXCD2.js";
7
+ } from "./chunk-R62YWUNO.js";
12
8
  import {
13
9
  isActorUserId,
10
+ parseActorUserId
11
+ } from "./chunk-UXG6TU2U.js";
12
+ import {
13
+ isConversationChannel,
14
+ isConversationScopedChannel,
15
+ isDmChannel,
16
+ normalizeSlackConversationId,
17
+ parseDestination
18
+ } from "./chunk-76YMBKW7.js";
19
+ import {
20
+ TURN_CONTEXT_TAG,
21
+ botConfig,
22
+ getChatConfig,
23
+ parseSlackThreadId
24
+ } from "./chunk-JS4HURDT.js";
25
+ import {
14
26
  isRecord,
27
+ listReferenceFiles,
15
28
  logException,
16
29
  logInfo,
17
30
  logWarn,
18
- parseActorUserId
19
- } from "./chunk-OIIXZOOC.js";
31
+ soulPathCandidates,
32
+ worldPathCandidates
33
+ } from "./chunk-BBXYXOJW.js";
20
34
  import {
21
35
  sentry_exports
22
36
  } from "./chunk-Z3YD6NHK.js";
23
- import {
24
- listReferenceFiles,
25
- soulPathCandidates,
26
- worldPathCandidates
27
- } from "./chunk-KVZL5NZS.js";
28
37
 
29
38
  // src/chat/plugins/logging.ts
30
39
  function createAgentPluginLogger(plugin) {
@@ -152,277 +161,6 @@ function createPluginState(plugin, options) {
152
161
 
153
162
  // src/chat/credentials/subject.ts
154
163
  import { createHmac, timingSafeEqual } from "crypto";
155
-
156
- // src/chat/slack/client.ts
157
- import { WebClient } from "@slack/web-api";
158
- var SlackActionError = class extends Error {
159
- code;
160
- apiError;
161
- needed;
162
- provided;
163
- statusCode;
164
- requestId;
165
- errorData;
166
- retryAfterSeconds;
167
- detail;
168
- detailLine;
169
- detailRule;
170
- constructor(message, code, options = {}) {
171
- super(message);
172
- this.name = "SlackActionError";
173
- this.code = code;
174
- this.apiError = options.apiError;
175
- this.needed = options.needed;
176
- this.provided = options.provided;
177
- this.statusCode = options.statusCode;
178
- this.requestId = options.requestId;
179
- this.errorData = options.errorData;
180
- this.retryAfterSeconds = options.retryAfterSeconds;
181
- this.detail = options.detail;
182
- this.detailLine = options.detailLine;
183
- this.detailRule = options.detailRule;
184
- }
185
- };
186
- function serializeSlackErrorData(data) {
187
- if (!data || typeof data !== "object") {
188
- return void 0;
189
- }
190
- const filtered = Object.fromEntries(
191
- Object.entries(data).filter(
192
- ([key2]) => key2 !== "error"
193
- )
194
- );
195
- if (Object.keys(filtered).length === 0) {
196
- return void 0;
197
- }
198
- try {
199
- const serialized = JSON.stringify(filtered);
200
- return serialized.length <= 600 ? serialized : `${serialized.slice(0, 597)}...`;
201
- } catch {
202
- return void 0;
203
- }
204
- }
205
- function getHeaderString(headers, name) {
206
- if (!headers || typeof headers !== "object") {
207
- return void 0;
208
- }
209
- const key2 = name.toLowerCase();
210
- const entries = headers;
211
- for (const [entryKey, value] of Object.entries(entries)) {
212
- if (entryKey.toLowerCase() !== key2) continue;
213
- if (typeof value === "string") return value;
214
- if (Array.isArray(value)) {
215
- const first = value.find((entry) => typeof entry === "string");
216
- return typeof first === "string" ? first : void 0;
217
- }
218
- }
219
- return void 0;
220
- }
221
- function parseSlackCanvasDetail(detail) {
222
- if (typeof detail !== "string") {
223
- return {};
224
- }
225
- const trimmed = detail.trim();
226
- if (!trimmed) {
227
- return {};
228
- }
229
- const parsed = {
230
- detail: trimmed
231
- };
232
- const lineMatch = trimmed.match(/line\s+(\d+):/i);
233
- if (lineMatch) {
234
- const line = Number.parseInt(lineMatch[1] ?? "", 10);
235
- if (Number.isFinite(line)) {
236
- parsed.detailLine = line;
237
- }
238
- }
239
- if (/unsupported heading depth/i.test(trimmed)) {
240
- parsed.detailRule = "unsupported_heading_depth";
241
- }
242
- return parsed;
243
- }
244
- var client = null;
245
- function normalizeSlackConversationId(channelId) {
246
- if (!channelId) return void 0;
247
- const trimmed = channelId.trim();
248
- if (!trimmed) return void 0;
249
- if (!trimmed.startsWith("slack:")) {
250
- return trimmed;
251
- }
252
- const parts = trimmed.split(":");
253
- return parts[1]?.trim() || void 0;
254
- }
255
- function getClient() {
256
- if (client) return client;
257
- const token = getSlackBotToken();
258
- if (!token) {
259
- throw new SlackActionError(
260
- "SLACK_BOT_TOKEN (or SLACK_BOT_USER_TOKEN) is required for Slack canvas/list actions in this service",
261
- "missing_token"
262
- );
263
- }
264
- client = new WebClient(token);
265
- return client;
266
- }
267
- function mapSlackError(error) {
268
- if (error instanceof SlackActionError) {
269
- return error;
270
- }
271
- const candidate = error;
272
- const apiError = candidate.data?.error;
273
- const message = candidate.message ?? "Slack action failed";
274
- const baseOptions = {
275
- apiError,
276
- statusCode: candidate.statusCode,
277
- requestId: getHeaderString(candidate.headers, "x-slack-req-id"),
278
- errorData: serializeSlackErrorData(candidate.data),
279
- ...parseSlackCanvasDetail(candidate.data?.detail)
280
- };
281
- if (apiError === "missing_scope") {
282
- return new SlackActionError(message, "missing_scope", {
283
- ...baseOptions,
284
- needed: candidate.data?.needed,
285
- provided: candidate.data?.provided
286
- });
287
- }
288
- if (apiError === "not_in_channel") {
289
- return new SlackActionError(message, "not_in_channel", baseOptions);
290
- }
291
- if (apiError === "already_reacted") {
292
- return new SlackActionError(message, "already_reacted", baseOptions);
293
- }
294
- if (apiError === "no_reaction") {
295
- return new SlackActionError(message, "no_reaction", baseOptions);
296
- }
297
- if (apiError === "invalid_arguments") {
298
- return new SlackActionError(message, "invalid_arguments", baseOptions);
299
- }
300
- if (apiError === "invalid_cursor") {
301
- return new SlackActionError(message, "invalid_arguments", baseOptions);
302
- }
303
- if (apiError === "invalid_name") {
304
- return new SlackActionError(message, "invalid_arguments", baseOptions);
305
- }
306
- if (apiError === "not_found" || apiError === "channel_not_found" || apiError === "message_not_found") {
307
- return new SlackActionError(message, "not_found", baseOptions);
308
- }
309
- if (apiError === "feature_not_enabled" || apiError === "not_allowed_token_type") {
310
- return new SlackActionError(message, "feature_unavailable", baseOptions);
311
- }
312
- if (apiError === "canvas_creation_failed") {
313
- return new SlackActionError(message, "canvas_creation_failed", baseOptions);
314
- }
315
- if (apiError === "canvas_editing_failed") {
316
- return new SlackActionError(message, "canvas_editing_failed", baseOptions);
317
- }
318
- if (candidate.code === "slack_webapi_rate_limited_error" || candidate.statusCode === 429) {
319
- return new SlackActionError(message, "rate_limited", {
320
- ...baseOptions,
321
- retryAfterSeconds: candidate.retryAfter
322
- });
323
- }
324
- return new SlackActionError(message, "internal_error", baseOptions);
325
- }
326
- function sleep(ms) {
327
- return new Promise((resolve) => setTimeout(resolve, ms));
328
- }
329
- async function withSlackRetries(task, maxAttempts = 3, context = {}) {
330
- let attempt = 0;
331
- while (attempt < maxAttempts) {
332
- attempt += 1;
333
- try {
334
- return await task();
335
- } catch (error) {
336
- const mapped = mapSlackError(error);
337
- const isRetryable = mapped.code === "rate_limited";
338
- const baseLogAttributes = {
339
- "app.slack.action": context.action ?? "unknown",
340
- "app.slack.error_code": mapped.code,
341
- ...mapped.apiError ? { "app.slack.api_error": mapped.apiError } : {},
342
- ...mapped.detail ? { "app.slack.detail": mapped.detail } : {},
343
- ...mapped.detailLine !== void 0 ? { "app.slack.detail_line": mapped.detailLine } : {},
344
- ...mapped.detailRule ? { "app.slack.detail_rule": mapped.detailRule } : {},
345
- ...mapped.requestId ? { "app.slack.request_id": mapped.requestId } : {},
346
- ...mapped.statusCode !== void 0 ? { "http.response.status_code": mapped.statusCode } : {},
347
- ...context.attributes ?? {}
348
- };
349
- if (!isRetryable || attempt >= maxAttempts) {
350
- logWarn(
351
- "slack_action_failed",
352
- {},
353
- {
354
- ...baseLogAttributes,
355
- ...mapped.errorData ? { "app.slack.error_data": mapped.errorData } : {}
356
- },
357
- "Slack action failed"
358
- );
359
- throw mapped;
360
- }
361
- logWarn(
362
- "slack_action_retrying",
363
- {},
364
- {
365
- ...baseLogAttributes,
366
- "app.slack.retry_attempt": attempt
367
- },
368
- "Retrying Slack action after transient failure"
369
- );
370
- const retryAfterMs = mapped.code === "rate_limited" && mapped.retryAfterSeconds && mapped.retryAfterSeconds > 0 ? mapped.retryAfterSeconds * 1e3 : void 0;
371
- const backoffMs = Math.min(2e3, 250 * 2 ** (attempt - 1));
372
- await sleep(retryAfterMs ?? backoffMs);
373
- }
374
- }
375
- throw new SlackActionError(
376
- "Slack action exhausted retries",
377
- "internal_error"
378
- );
379
- }
380
- function getSlackClient() {
381
- return getClient();
382
- }
383
- function isDmChannel(channelId) {
384
- const normalized = normalizeSlackConversationId(channelId);
385
- return Boolean(normalized && normalized.startsWith("D"));
386
- }
387
- function isConversationScopedChannel(channelId) {
388
- const normalized = normalizeSlackConversationId(channelId);
389
- if (!normalized) return false;
390
- return normalized.startsWith("C") || normalized.startsWith("G") || normalized.startsWith("D");
391
- }
392
- function isConversationChannel(channelId) {
393
- const normalized = normalizeSlackConversationId(channelId);
394
- if (!normalized) return false;
395
- return normalized.startsWith("C") || normalized.startsWith("G");
396
- }
397
- async function getFilePermalink(fileId) {
398
- const client2 = getClient();
399
- const response = await withSlackRetries(
400
- () => client2.files.info({
401
- file: fileId
402
- })
403
- );
404
- return response.file?.permalink;
405
- }
406
- async function downloadPrivateSlackFile(url) {
407
- const token = getSlackBotToken();
408
- if (!token) {
409
- throw new SlackActionError(
410
- "SLACK_BOT_TOKEN (or SLACK_BOT_USER_TOKEN) is required for Slack file downloads in this service",
411
- "missing_token"
412
- );
413
- }
414
- const response = await fetch(url, {
415
- headers: {
416
- Authorization: `Bearer ${token}`
417
- }
418
- });
419
- if (!response.ok) {
420
- throw new Error(`Slack file download failed: ${response.status}`);
421
- }
422
- return Buffer.from(await response.arrayBuffer());
423
- }
424
-
425
- // src/chat/credentials/subject.ts
426
164
  var CREDENTIAL_SUBJECT_HMAC_CONTEXT = "junior.credential_subject.v1";
427
165
  var CREDENTIAL_SUBJECT_SIGNATURE_VERSION = "v1";
428
166
  function getCredentialSubjectSecret() {
@@ -514,6 +252,15 @@ function verifySlackDirectCredentialSubject(input) {
514
252
  return timingSafeMatch(expected, binding.signature);
515
253
  }
516
254
 
255
+ // src/chat/tools/channel-capabilities.ts
256
+ function resolveChannelCapabilities(channelId) {
257
+ return {
258
+ canCreateCanvas: isConversationScopedChannel(channelId),
259
+ canPostToChannel: isConversationChannel(channelId),
260
+ canAddReactions: isConversationScopedChannel(channelId)
261
+ };
262
+ }
263
+
517
264
  // src/chat/plugins/agent-hooks.ts
518
265
  var AgentPluginHookDeniedError = class extends Error {
519
266
  constructor(message) {
@@ -540,6 +287,9 @@ var AGENT_PLUGIN_ROUTE_METHODS = /* @__PURE__ */ new Set([
540
287
  "OPTIONS",
541
288
  "ALL"
542
289
  ]);
290
+ function isRecord2(value) {
291
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
292
+ }
543
293
  function validateLegacyStatePrefixes(plugin) {
544
294
  const prefixes = plugin.legacyStatePrefixes;
545
295
  if (prefixes === void 0) {
@@ -547,7 +297,7 @@ function validateLegacyStatePrefixes(plugin) {
547
297
  }
548
298
  if (!Array.isArray(prefixes)) {
549
299
  throw new Error(
550
- `Trusted plugin "${plugin.name}" legacyStatePrefixes must be an array`
300
+ `Plugin "${plugin.name}" legacyStatePrefixes must be an array`
551
301
  );
552
302
  }
553
303
  const allowedPrefix = `junior:${plugin.name}`;
@@ -555,12 +305,12 @@ function validateLegacyStatePrefixes(plugin) {
555
305
  const prefix = typeof rawPrefix === "string" ? rawPrefix.trim() : "";
556
306
  if (!prefix) {
557
307
  throw new Error(
558
- `Trusted plugin "${plugin.name}" legacy state prefixes must be non-empty strings`
308
+ `Plugin "${plugin.name}" legacy state prefixes must be non-empty strings`
559
309
  );
560
310
  }
561
311
  if (prefix !== allowedPrefix && !prefix.startsWith(`${allowedPrefix}:`)) {
562
312
  throw new Error(
563
- `Trusted plugin "${plugin.name}" legacy state prefix "${prefix}" must stay under "${allowedPrefix}"`
313
+ `Plugin "${plugin.name}" legacy state prefix "${prefix}" must stay under "${allowedPrefix}"`
564
314
  );
565
315
  }
566
316
  }
@@ -570,11 +320,11 @@ function validateAgentPlugins(plugins) {
570
320
  for (const plugin of plugins) {
571
321
  if (!AGENT_PLUGIN_NAME_RE.test(plugin.name)) {
572
322
  throw new Error(
573
- `Trusted plugin name "${plugin.name}" must be a lowercase plugin identifier`
323
+ `Plugin name "${plugin.name}" must be a lowercase plugin identifier`
574
324
  );
575
325
  }
576
326
  if (seen.has(plugin.name)) {
577
- throw new Error(`Duplicate trusted plugin name "${plugin.name}"`);
327
+ throw new Error(`Duplicate plugin name "${plugin.name}"`);
578
328
  }
579
329
  seen.add(plugin.name);
580
330
  validateLegacyStatePrefixes(plugin);
@@ -599,18 +349,22 @@ function getAgentPluginTools(context) {
599
349
  continue;
600
350
  }
601
351
  const log = createAgentPluginLogger(plugin.name);
352
+ const destination = context.destination;
602
353
  const credentialSubject = createSlackDirectCredentialSubject({
603
354
  channelId: context.channelId,
604
355
  teamId: context.teamId,
605
356
  userId: context.requester?.userId
606
357
  });
358
+ const pluginCapabilities = resolveChannelCapabilities(context.channelId);
607
359
  const pluginTools = hook({
608
360
  plugin: { name: plugin.name },
609
361
  log,
610
362
  requester: context.requester,
611
- channelCapabilities: context.channelCapabilities,
363
+ channelCapabilities: pluginCapabilities,
612
364
  channelId: context.channelId,
365
+ conversationId: context.conversationId,
613
366
  ...credentialSubject ? { credentialSubject } : {},
367
+ ...destination ? { destination } : {},
614
368
  teamId: context.teamId,
615
369
  messageTs: context.messageTs,
616
370
  threadTs: context.threadTs,
@@ -622,12 +376,12 @@ function getAgentPluginTools(context) {
622
376
  for (const [name, tool] of Object.entries(pluginTools)) {
623
377
  if (!AGENT_PLUGIN_TOOL_NAME_RE.test(name)) {
624
378
  throw new Error(
625
- `Trusted plugin tool "${name}" from plugin "${plugin.name}" must be a camelCase identifier`
379
+ `Plugin tool "${name}" from plugin "${plugin.name}" must be a camelCase identifier`
626
380
  );
627
381
  }
628
382
  if (tools[name]) {
629
383
  throw new Error(
630
- `Duplicate trusted plugin tool "${name}" from plugin "${plugin.name}"`
384
+ `Duplicate plugin tool "${name}" from plugin "${plugin.name}"`
631
385
  );
632
386
  }
633
387
  tools[name] = tool;
@@ -639,19 +393,19 @@ function routeMethods(route, pluginName) {
639
393
  const methods = Array.isArray(route.method) ? route.method : [route.method ?? "ALL"];
640
394
  if (methods.length === 0) {
641
395
  throw new Error(
642
- `Trusted plugin route "${route.path}" from plugin "${pluginName}" must declare at least one method`
396
+ `Plugin route "${route.path}" from plugin "${pluginName}" must declare at least one method`
643
397
  );
644
398
  }
645
399
  for (const method of methods) {
646
400
  if (!AGENT_PLUGIN_ROUTE_METHODS.has(method)) {
647
401
  throw new Error(
648
- `Trusted plugin route "${route.path}" from plugin "${pluginName}" has invalid method "${String(method)}"`
402
+ `Plugin route "${route.path}" from plugin "${pluginName}" has invalid method "${String(method)}"`
649
403
  );
650
404
  }
651
405
  }
652
406
  if (methods.includes("ALL") && methods.length > 1) {
653
407
  throw new Error(
654
- `Trusted plugin route "${route.path}" from plugin "${pluginName}" must not combine ALL with explicit methods`
408
+ `Plugin route "${route.path}" from plugin "${pluginName}" must not combine ALL with explicit methods`
655
409
  );
656
410
  }
657
411
  return methods;
@@ -672,38 +426,36 @@ function getAgentPluginRoutes() {
672
426
  });
673
427
  if (!Array.isArray(pluginRoutes)) {
674
428
  throw new Error(
675
- `Trusted plugin routes hook from plugin "${plugin.name}" must return an array`
429
+ `Plugin routes hook from plugin "${plugin.name}" must return an array`
676
430
  );
677
431
  }
678
432
  for (const route of pluginRoutes) {
679
433
  if (!isRecord2(route)) {
680
434
  throw new Error(
681
- `Trusted plugin route from plugin "${plugin.name}" must be an object`
435
+ `Plugin route from plugin "${plugin.name}" must be an object`
682
436
  );
683
437
  }
684
438
  if (typeof route.path !== "string" || !route.path.startsWith("/")) {
685
439
  throw new Error(
686
- `Trusted plugin route "${route.path}" from plugin "${plugin.name}" must start with /`
440
+ `Plugin route "${route.path}" from plugin "${plugin.name}" must start with /`
687
441
  );
688
442
  }
689
443
  if (typeof route.handler !== "function") {
690
444
  throw new Error(
691
- `Trusted plugin route "${route.path}" from plugin "${plugin.name}" must provide a handler`
445
+ `Plugin route "${route.path}" from plugin "${plugin.name}" must provide a handler`
692
446
  );
693
447
  }
694
448
  const methods = routeMethods(route, plugin.name);
695
449
  const pathMethods = methodsByPath.get(route.path) ?? /* @__PURE__ */ new Set();
696
450
  if (pathMethods.has("ALL") || methods.includes("ALL") && pathMethods.size > 0) {
697
451
  throw new Error(
698
- `Trusted plugin route "${route.path}" conflicts with an ALL route for the same path`
452
+ `Plugin route "${route.path}" conflicts with an ALL route for the same path`
699
453
  );
700
454
  }
701
455
  for (const method of methods) {
702
456
  const key2 = `${method}:${route.path}`;
703
457
  if (seen.has(key2)) {
704
- throw new Error(
705
- `Duplicate trusted plugin route "${method} ${route.path}"`
706
- );
458
+ throw new Error(`Duplicate plugin route "${method} ${route.path}"`);
707
459
  }
708
460
  seen.add(key2);
709
461
  pathMethods.add(method);
@@ -727,13 +479,13 @@ function trustedSlackConversationUrl(pluginName, link) {
727
479
  parsed = new URL(url);
728
480
  } catch (error) {
729
481
  throw new Error(
730
- `Trusted plugin "${pluginName}" slackConversationLink must return an absolute http(s) URL`,
482
+ `Plugin "${pluginName}" slackConversationLink must return an absolute http(s) URL`,
731
483
  { cause: error }
732
484
  );
733
485
  }
734
486
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
735
487
  throw new Error(
736
- `Trusted plugin "${pluginName}" slackConversationLink must return an absolute http(s) URL`
488
+ `Plugin "${pluginName}" slackConversationLink must return an absolute http(s) URL`
737
489
  );
738
490
  }
739
491
  return parsed.toString();
@@ -923,7 +675,7 @@ async function getAgentPluginOperationalReports(nowMs = Date.now()) {
923
675
  })
924
676
  );
925
677
  } catch (error) {
926
- log.error("Trusted plugin operational report failed", {
678
+ log.error("Plugin operational report failed", {
927
679
  error: error instanceof Error ? error.message : String(error)
928
680
  });
929
681
  reports.push(failedOperationalReport({ nowMs, pluginName: plugin.name }));
@@ -931,9 +683,6 @@ async function getAgentPluginOperationalReports(nowMs = Date.now()) {
931
683
  }
932
684
  return reports;
933
685
  }
934
- function isRecord2(value) {
935
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
936
- }
937
686
  function normalizeEnv(value) {
938
687
  if (!isRecord2(value)) {
939
688
  return {};
@@ -1072,9 +821,6 @@ function GET() {
1072
821
  import fs from "fs";
1073
822
  import path from "path";
1074
823
 
1075
- // src/chat/turn-context-tag.ts
1076
- var TURN_CONTEXT_TAG = "runtime-turn-context";
1077
-
1078
824
  // src/chat/interruption-marker.ts
1079
825
  var INTERRUPTED_MARKER = "\n\n[Response interrupted before completion]";
1080
826
  function getInterruptionMarker() {
@@ -2202,20 +1948,20 @@ function commitEntries(existingMessages, nextMessages, sessionId, entries) {
2202
1948
  return [resetEntry(nextMessages, nextSessionId(entries))];
2203
1949
  }
2204
1950
  function redisStore(redisStateAdapter) {
2205
- const client2 = redisStateAdapter.getClient();
1951
+ const client = redisStateAdapter.getClient();
2206
1952
  return {
2207
1953
  async append({ entries, scope, ttlMs }) {
2208
1954
  const listKey = key(scope);
2209
1955
  if (entries.length > 0) {
2210
- await client2.rPush(
1956
+ await client.rPush(
2211
1957
  listKey,
2212
1958
  entries.map((entry) => JSON.stringify(entry))
2213
1959
  );
2214
1960
  }
2215
- await client2.pExpire(listKey, Math.max(1, ttlMs));
1961
+ await client.pExpire(listKey, Math.max(1, ttlMs));
2216
1962
  },
2217
1963
  async read(scope) {
2218
- const values = await client2.lRange(key(scope), 0, -1);
1964
+ const values = await client.lRange(key(scope), 0, -1);
2219
1965
  return values.map(decode);
2220
1966
  }
2221
1967
  };
@@ -2441,7 +2187,8 @@ function parseAgentTurnSessionFields(parsed) {
2441
2187
  const requester = parseAgentTurnRequester(parsed.requester);
2442
2188
  const startedAtMs = toFiniteNonNegativeNumber(parsed.startedAtMs);
2443
2189
  const surface = parseAgentTurnSurface(parsed.surface);
2444
- if (typeof conversationId !== "string" || typeof sessionId !== "string" || sliceId === void 0 || version === void 0 || updatedAtMs === void 0) {
2190
+ const destination = parsed.destination === void 0 ? void 0 : parseDestination(parsed.destination);
2191
+ if (typeof conversationId !== "string" || typeof sessionId !== "string" || sliceId === void 0 || version === void 0 || updatedAtMs === void 0 || parsed.destination !== void 0 && !destination) {
2445
2192
  return void 0;
2446
2193
  }
2447
2194
  return {
@@ -2458,6 +2205,7 @@ function parseAgentTurnSessionFields(parsed) {
2458
2205
  cumulativeDurationMs,
2459
2206
  ...logSessionId ? { logSessionId } : {},
2460
2207
  ...cumulativeUsage ? { cumulativeUsage } : {},
2208
+ ...destination ? { destination } : {},
2461
2209
  ...requester ? { requester } : {},
2462
2210
  ...Array.isArray(parsed.loadedSkillNames) ? {
2463
2211
  loadedSkillNames: parsed.loadedSkillNames.filter(
@@ -2547,6 +2295,7 @@ function materializeAgentTurnSessionRecord(stored, piMessages) {
2547
2295
  updatedAtMs: stored.updatedAtMs,
2548
2296
  piMessages,
2549
2297
  cumulativeDurationMs: stored.cumulativeDurationMs,
2298
+ ...stored.destination ? { destination: stored.destination } : {},
2550
2299
  ...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
2551
2300
  ...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
2552
2301
  ...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
@@ -2610,6 +2359,7 @@ function buildStoredRecord(args) {
2610
2359
  ...args.logSessionId ? { logSessionId: args.logSessionId } : {},
2611
2360
  cumulativeDurationMs: args.cumulativeDurationMs,
2612
2361
  ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
2362
+ ...args.destination ? { destination: args.destination } : {},
2613
2363
  ...args.requester ? { requester: args.requester } : {},
2614
2364
  ...Array.isArray(args.loadedSkillNames) ? {
2615
2365
  loadedSkillNames: args.loadedSkillNames.filter(
@@ -2665,6 +2415,7 @@ async function updateAgentTurnSessionState(args) {
2665
2415
  ...parsed.logSessionId ? { logSessionId: parsed.logSessionId } : {},
2666
2416
  cumulativeDurationMs: args.existing.cumulativeDurationMs,
2667
2417
  ...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
2418
+ ...args.existing.destination ? { destination: args.existing.destination } : {},
2668
2419
  ...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
2669
2420
  ...args.existing.requester ? { requester: args.existing.requester } : {},
2670
2421
  ...args.existing.resumeReason ? { resumeReason: args.existing.resumeReason } : {},
@@ -2705,6 +2456,7 @@ async function upsertAgentTurnSessionRecord(args) {
2705
2456
  previousVersion: existingRecord?.version,
2706
2457
  cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existingRecord?.cumulativeDurationMs ?? 0,
2707
2458
  ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
2459
+ ...args.destination ?? existingRecord?.destination ? { destination: args.destination ?? existingRecord?.destination } : {},
2708
2460
  ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
2709
2461
  ...args.requester ?? existingRecord?.requester ? { requester: args.requester ?? existingRecord?.requester } : {},
2710
2462
  ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
@@ -2738,6 +2490,7 @@ async function recordAgentTurnSessionSummary(args) {
2738
2490
  updatedAtMs: nowMs,
2739
2491
  cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existing?.cumulativeDurationMs ?? 0,
2740
2492
  ...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
2493
+ ...args.destination ?? existing?.destination ? { destination: args.destination ?? existing?.destination } : {},
2741
2494
  ...args.requester ?? existing?.requester ? { requester: args.requester ?? existing?.requester } : {},
2742
2495
  ...Array.isArray(args.loadedSkillNames) ? {
2743
2496
  loadedSkillNames: args.loadedSkillNames.filter(
@@ -2828,8 +2581,8 @@ function buildSentryWebBaseUrl(dsn) {
2828
2581
  return `${dsn.protocol}://${dsn.host}${port}${path2}`;
2829
2582
  }
2830
2583
  function buildSentryConversationUrl(conversationId) {
2831
- const client2 = sentry_exports.getClient();
2832
- const dsn = client2?.getDsn();
2584
+ const client = sentry_exports.getClient();
2585
+ const dsn = client?.getDsn();
2833
2586
  if (!dsn?.host || !dsn.projectId) {
2834
2587
  return void 0;
2835
2588
  }
@@ -2847,8 +2600,8 @@ function buildSentryConversationUrl(conversationId) {
2847
2600
  return `${buildSentryWebBaseUrl(dsn)}/organizations/${orgSlug}/${path2}`;
2848
2601
  }
2849
2602
  function buildSentryTraceUrl(traceId) {
2850
- const client2 = sentry_exports.getClient();
2851
- const dsn = client2?.getDsn();
2603
+ const client = sentry_exports.getClient();
2604
+ const dsn = client?.getDsn();
2852
2605
  if (!dsn?.host || !dsn.projectId) {
2853
2606
  return void 0;
2854
2607
  }
@@ -2937,18 +2690,9 @@ function formatSlackConversationRedactedLabel(context) {
2937
2690
  export {
2938
2691
  createAgentPluginLogger,
2939
2692
  createPluginState,
2940
- SlackActionError,
2941
- getHeaderString,
2942
- normalizeSlackConversationId,
2943
- withSlackRetries,
2944
- getSlackClient,
2945
- isDmChannel,
2946
- isConversationScopedChannel,
2947
- isConversationChannel,
2948
- getFilePermalink,
2949
- downloadPrivateSlackFile,
2950
2693
  bindSlackDirectCredentialSubject,
2951
2694
  verifySlackDirectCredentialSubject,
2695
+ resolveChannelCapabilities,
2952
2696
  validateAgentPlugins,
2953
2697
  setAgentPlugins,
2954
2698
  getAgentPlugins,
@@ -2958,7 +2702,6 @@ export {
2958
2702
  getAgentPluginOperationalReports,
2959
2703
  createAgentPluginHookRunner,
2960
2704
  GET,
2961
- TURN_CONTEXT_TAG,
2962
2705
  getInterruptionMarker,
2963
2706
  truncateStatusText,
2964
2707
  normalizeSlackStatusText,