@sentry/junior 0.54.0 → 0.56.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 (60) hide show
  1. package/README.md +1 -1
  2. package/dist/app.d.ts +9 -2
  3. package/dist/app.js +13024 -10255
  4. package/dist/chat/agent-dispatch/context.d.ts +6 -0
  5. package/dist/chat/agent-dispatch/heartbeat.d.ts +14 -0
  6. package/dist/chat/agent-dispatch/runner.d.ts +9 -0
  7. package/dist/chat/agent-dispatch/signing.d.ts +5 -0
  8. package/dist/chat/agent-dispatch/store.d.ts +29 -0
  9. package/dist/chat/agent-dispatch/types.d.ts +57 -0
  10. package/dist/chat/agent-dispatch/validation.d.ts +3 -0
  11. package/dist/chat/app/services.d.ts +3 -0
  12. package/dist/chat/config.d.ts +2 -0
  13. package/dist/chat/ingress/workspace-membership.d.ts +1 -2
  14. package/dist/chat/logging.d.ts +2 -0
  15. package/dist/chat/pi/client.d.ts +1 -0
  16. package/dist/chat/plugins/agent-hooks.d.ts +32 -0
  17. package/dist/chat/plugins/logging.d.ts +3 -0
  18. package/dist/chat/plugins/state.d.ts +3 -0
  19. package/dist/chat/respond.d.ts +11 -0
  20. package/dist/chat/runtime/reply-executor.d.ts +2 -0
  21. package/dist/chat/runtime/thread-context.d.ts +2 -0
  22. package/dist/chat/sandbox/egress-proxy.d.ts +8 -1
  23. package/dist/chat/sandbox/sandbox.d.ts +2 -0
  24. package/dist/chat/sandbox/session.d.ts +1 -0
  25. package/dist/chat/sandbox/skill-sync.d.ts +1 -2
  26. package/dist/chat/scheduler/cadence.d.ts +24 -0
  27. package/dist/chat/scheduler/plugin.d.ts +2 -0
  28. package/dist/chat/scheduler/prompt.d.ts +7 -0
  29. package/dist/chat/scheduler/store.d.ts +49 -0
  30. package/dist/chat/scheduler/types.d.ts +86 -0
  31. package/dist/chat/services/auth-pause.d.ts +7 -0
  32. package/dist/chat/services/context-budget.d.ts +14 -0
  33. package/dist/chat/services/context-compaction.d.ts +33 -0
  34. package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -1
  35. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
  36. package/dist/chat/slack/assistant-thread/status-scheduler.d.ts +1 -1
  37. package/dist/chat/slack/ids.d.ts +4 -0
  38. package/dist/chat/slack/reply.d.ts +1 -1
  39. package/dist/chat/slack/user.d.ts +1 -0
  40. package/dist/chat/slack/workspace-context.d.ts +4 -0
  41. package/dist/chat/tools/agent-tools.d.ts +2 -1
  42. package/dist/chat/tools/slack/schedule-tools.d.ts +29 -0
  43. package/dist/chat/tools/types.d.ts +6 -0
  44. package/dist/{chunk-7WTXNEPF.js → chunk-AA5TIFN5.js} +119 -15
  45. package/dist/{chunk-QCHPJ4FD.js → chunk-D3G3YOU4.js} +1 -1
  46. package/dist/chunk-SCQPBJAU.js +21 -0
  47. package/dist/{chunk-YITDDLS3.js → chunk-TTUY467K.js} +13 -9
  48. package/dist/cli/check.js +2 -2
  49. package/dist/cli/init.js +5 -1
  50. package/dist/cli/snapshot-warmup.js +2 -2
  51. package/dist/handlers/agent-dispatch.d.ts +3 -0
  52. package/dist/handlers/heartbeat.d.ts +3 -0
  53. package/dist/handlers/sandbox-egress-proxy.d.ts +6 -1
  54. package/dist/vercel.js +3 -12
  55. package/package.json +8 -2
  56. package/dist/chat/credentials/test-broker.d.ts +0 -19
  57. package/dist/chat/sandbox/eval-gh-stub.d.ts +0 -2
  58. package/dist/chat/sandbox/eval-oauth-stub.d.ts +0 -2
  59. package/dist/chat/sandbox/eval-sentry-stub.d.ts +0 -2
  60. package/dist/chat/sandbox/fault-injection.d.ts +0 -2
@@ -0,0 +1,4 @@
1
+ /** Return true when a value is a Slack workspace/team id. */
2
+ export declare function isSlackTeamId(value: string): boolean;
3
+ /** Return true when a value is a Slack conversation id. */
4
+ export declare function isSlackConversationId(value: string): boolean;
@@ -28,6 +28,6 @@ export declare function postSlackApiReplyPosts(args: {
28
28
  messageTs?: string;
29
29
  stage: PlannedSlackReplyStage;
30
30
  }) => Promise<void> | void;
31
- threadTs: string;
31
+ threadTs?: string;
32
32
  posts: PlannedSlackReplyPost[];
33
33
  }): Promise<string | undefined>;
@@ -1,6 +1,7 @@
1
1
  interface SlackUserLookupResult {
2
2
  userName?: string;
3
3
  fullName?: string;
4
+ email?: string;
4
5
  }
5
6
  /** Fetch Slack user profile info with in-memory TTL cache to avoid repeated API calls. */
6
7
  export declare function lookupSlackUser(userId?: string): Promise<SlackUserLookupResult | null>;
@@ -0,0 +1,4 @@
1
+ /** Run a callback with the Slack workspace team ID for the inbound webhook. */
2
+ export declare function runWithWorkspaceTeamId<T>(teamId: string | undefined, fn: () => T): T;
3
+ /** Return the Slack workspace team ID for the current inbound webhook. */
4
+ export declare function getWorkspaceTeamId(): string | undefined;
@@ -5,5 +5,6 @@ import type { AssistantStatusSpec } from "@/chat/slack/assistant-thread/status";
5
5
  import type { SandboxExecutor } from "@/chat/sandbox/sandbox";
6
6
  import type { SkillSandbox } from "@/chat/sandbox/skill-sandbox";
7
7
  import type { ToolDefinition } from "@/chat/tools/definition";
8
+ import type { AgentPluginHookRunner } from "@/chat/plugins/agent-hooks";
8
9
  /** Wrap tool definitions into Pi Agent tool objects with logging, validation, and sandbox execution. */
9
- export declare function createAgentTools(tools: Record<string, ToolDefinition<any>>, sandbox: SkillSandbox, spanContext: LogContext, onStatus?: (status: AssistantStatusSpec) => void | Promise<void>, sandboxExecutor?: SandboxExecutor, pluginAuthOrchestration?: PluginAuthOrchestration, onToolCall?: (toolName: string, params: Record<string, unknown>) => void): AgentTool[];
10
+ export declare function createAgentTools(tools: Record<string, ToolDefinition<any>>, sandbox: SkillSandbox, spanContext: LogContext, onStatus?: (status: AssistantStatusSpec) => void | Promise<void>, sandboxExecutor?: SandboxExecutor, pluginAuthOrchestration?: PluginAuthOrchestration, onToolCall?: (toolName: string, params: Record<string, unknown>) => void, agentHooks?: AgentPluginHookRunner): AgentTool[];
@@ -0,0 +1,29 @@
1
+ import type { ToolRuntimeContext } from "@/chat/tools/types";
2
+ /** Create a tool that stores a scheduled task for the active Slack context. */
3
+ export declare function createSlackScheduleCreateTaskTool(context: ToolRuntimeContext): import("@/chat/tools/definition").ToolDefinition<import("@sinclair/typebox").TObject<{
4
+ task: import("@sinclair/typebox").TString;
5
+ schedule: import("@sinclair/typebox").TString;
6
+ timezone: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
7
+ next_run_at: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
8
+ recurrence: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"daily">, import("@sinclair/typebox").TLiteral<"weekly">, import("@sinclair/typebox").TLiteral<"monthly">, import("@sinclair/typebox").TLiteral<"yearly">]>>;
9
+ }>>;
10
+ /** Create a tool that lists scheduled tasks for the active Slack destination. */
11
+ export declare function createSlackScheduleListTasksTool(context: ToolRuntimeContext): import("@/chat/tools/definition").ToolDefinition<import("@sinclair/typebox").TObject<{}>>;
12
+ /** Create a tool that edits a scheduled task in the active Slack destination. */
13
+ export declare function createSlackScheduleUpdateTaskTool(context: ToolRuntimeContext): import("@/chat/tools/definition").ToolDefinition<import("@sinclair/typebox").TObject<{
14
+ task_id: import("@sinclair/typebox").TString;
15
+ task: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
16
+ schedule: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
17
+ timezone: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
18
+ next_run_at: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
19
+ recurrence: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"daily">, import("@sinclair/typebox").TLiteral<"weekly">, import("@sinclair/typebox").TLiteral<"monthly">, import("@sinclair/typebox").TLiteral<"yearly">]>, import("@sinclair/typebox").TNull]>>;
20
+ status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"active">, import("@sinclair/typebox").TLiteral<"paused">, import("@sinclair/typebox").TLiteral<"blocked">]>>;
21
+ }>>;
22
+ /** Create a tool that removes a scheduled task from the active Slack destination. */
23
+ export declare function createSlackScheduleDeleteTaskTool(context: ToolRuntimeContext): import("@/chat/tools/definition").ToolDefinition<import("@sinclair/typebox").TObject<{
24
+ task_id: import("@sinclair/typebox").TString;
25
+ }>>;
26
+ /** Create a tool that marks an existing scheduled task due immediately. */
27
+ export declare function createSlackScheduleRunTaskNowTool(context: ToolRuntimeContext): import("@/chat/tools/definition").ToolDefinition<import("@sinclair/typebox").TObject<{
28
+ task_id: import("@sinclair/typebox").TString;
29
+ }>>;
@@ -37,6 +37,12 @@ export interface ToolRuntimeContext {
37
37
  advisor?: AdvisorToolRuntimeContext;
38
38
  channelId?: string;
39
39
  channelCapabilities: ChannelCapabilities;
40
+ requester?: {
41
+ userId?: string;
42
+ userName?: string;
43
+ fullName?: string;
44
+ };
45
+ teamId?: string;
40
46
  messageTs?: string;
41
47
  threadTs?: string;
42
48
  userText?: string;
@@ -7,7 +7,7 @@ import {
7
7
  serializeGenAiAttribute,
8
8
  setSpanAttributes,
9
9
  withSpan
10
- } from "./chunk-YITDDLS3.js";
10
+ } from "./chunk-TTUY467K.js";
11
11
 
12
12
  // src/chat/state/adapter.ts
13
13
  import { createMemoryState } from "@chat-adapter/state-memory";
@@ -54,6 +54,35 @@ function getPiGatewayApiKeyOverride() {
54
54
  function extractText(message) {
55
55
  return (message.content ?? []).filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text ?? "").join("").trim();
56
56
  }
57
+ function contentMetadata(content) {
58
+ if (typeof content === "string") {
59
+ return [{ type: "text", chars: content.length }];
60
+ }
61
+ if (!Array.isArray(content)) {
62
+ return { type: typeof content };
63
+ }
64
+ return content.map((part) => {
65
+ if (!part || typeof part !== "object") {
66
+ return { type: typeof part };
67
+ }
68
+ const record = part;
69
+ const type = typeof record.type === "string" ? record.type : "unknown";
70
+ return {
71
+ type,
72
+ ...typeof record.text === "string" ? { chars: record.text.length } : {},
73
+ ...typeof record.mimeType === "string" ? { mimeType: record.mimeType } : {},
74
+ ...typeof record.mediaType === "string" ? { mediaType: record.mediaType } : {},
75
+ ...typeof record.data === "string" ? { dataChars: record.data.length } : {}
76
+ };
77
+ });
78
+ }
79
+ function toMessageMetadata(message) {
80
+ const record = message;
81
+ return {
82
+ role: record.role,
83
+ content: contentMetadata(record.content)
84
+ };
85
+ }
57
86
  function parseJsonCandidate(text) {
58
87
  const trimmed = text.trim();
59
88
  if (!trimmed) return void 0;
@@ -126,8 +155,13 @@ function resolveGatewayModel(modelId) {
126
155
  async function completeText(params) {
127
156
  const model = resolveGatewayModel(params.modelId);
128
157
  const apiKey = getPiGatewayApiKeyOverride();
129
- const requestMessagesAttribute = serializeGenAiAttribute(params.messages);
130
- const systemInstructionsAttribute = params.system ? serializeGenAiAttribute([{ type: "text", content: params.system }]) : void 0;
158
+ const messageAttributeMode = params.messageAttributeMode ?? "content";
159
+ const requestMessagesAttribute = serializeGenAiAttribute(
160
+ messageAttributeMode === "metadata" ? params.messages.map(toMessageMetadata) : params.messages
161
+ );
162
+ const systemInstructionsAttribute = params.system ? serializeGenAiAttribute(
163
+ messageAttributeMode === "metadata" ? [{ type: "text", chars: params.system.length }] : [{ type: "text", content: params.system }]
164
+ ) : void 0;
131
165
  const baseAttributes = {
132
166
  "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
133
167
  "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
@@ -161,12 +195,19 @@ async function completeText(params) {
161
195
  }
162
196
  );
163
197
  const outputText = extractText(message);
164
- const outputMessagesAttribute = serializeGenAiAttribute([
165
- {
166
- role: "assistant",
167
- content: outputText ? [{ type: "text", text: outputText }] : []
168
- }
169
- ]);
198
+ const outputMessagesAttribute = serializeGenAiAttribute(
199
+ messageAttributeMode === "metadata" ? [
200
+ {
201
+ role: "assistant",
202
+ content: outputText ? [{ type: "text", chars: outputText.length }] : []
203
+ }
204
+ ] : [
205
+ {
206
+ role: "assistant",
207
+ content: outputText ? [{ type: "text", text: outputText }] : []
208
+ }
209
+ ]
210
+ );
170
211
  const usageAttributes = extractGenAiUsageAttributes(message);
171
212
  const endAttributes = {
172
213
  ...baseAttributes,
@@ -336,6 +377,17 @@ function parseAdvisorThinkingLevel(rawValue) {
336
377
  `AI_ADVISOR_THINKING_LEVEL must be one of: minimal, low, medium, high, xhigh`
337
378
  );
338
379
  }
380
+ function parseOptionalPositiveInteger(envName, rawValue) {
381
+ const trimmed = toOptionalTrimmed(rawValue);
382
+ if (trimmed === void 0) {
383
+ return void 0;
384
+ }
385
+ const value = Number.parseInt(trimmed, 10);
386
+ if (!Number.isSafeInteger(value) || value <= 0 || String(value) !== trimmed) {
387
+ throw new Error(`${envName} must be a positive integer`);
388
+ }
389
+ return value;
390
+ }
339
391
  var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "openai/gpt-5.4").id;
340
392
  var DEFAULT_FAST_MODEL_ID = getModel(
341
393
  "vercel-ai-gateway",
@@ -363,6 +415,10 @@ function readBotConfig(env) {
363
415
  return {
364
416
  userName: env.JUNIOR_BOT_NAME ?? "junior",
365
417
  modelId: validateGatewayModelId(env.AI_MODEL) ?? DEFAULT_MODEL_ID,
418
+ modelContextWindowTokens: parseOptionalPositiveInteger(
419
+ "AI_MODEL_CONTEXT_WINDOW_TOKENS",
420
+ env.AI_MODEL_CONTEXT_WINDOW_TOKENS
421
+ ),
366
422
  fastModelId: validateGatewayModelId(env.AI_FAST_MODEL ?? env.AI_MODEL) ?? DEFAULT_FAST_MODEL_ID,
367
423
  loadingMessages: parseLoadingMessages(env.JUNIOR_LOADING_MESSAGES),
368
424
  visionModelId: validateGatewayModelId(env.AI_VISION_MODEL),
@@ -385,6 +441,7 @@ function readChatConfig(env = process.env) {
385
441
  },
386
442
  state: {
387
443
  adapter: env.JUNIOR_STATE_ADAPTER?.trim().toLowerCase() === "memory" ? "memory" : "redis",
444
+ keyPrefix: toOptionalTrimmed(env.JUNIOR_STATE_KEY_PREFIX),
388
445
  redisUrl: toOptionalTrimmed(env.REDIS_URL)
389
446
  }
390
447
  };
@@ -417,6 +474,48 @@ var ACTIVE_LOCK_TTL_MS = 9e4;
417
474
  var ACTIVE_LOCK_HEARTBEAT_MS = 3e4;
418
475
  var stateAdapter;
419
476
  var redisStateAdapter;
477
+ function createPrefixedStateAdapter(base, prefix) {
478
+ const prefixed = (value) => `${prefix}:${value}`;
479
+ const unprefixed = (value) => value.startsWith(`${prefix}:`) ? value.slice(prefix.length + 1) : value;
480
+ const prefixLock = (lock) => ({
481
+ ...lock,
482
+ threadId: prefixed(lock.threadId)
483
+ });
484
+ const unprefixLock = (lock) => ({
485
+ ...lock,
486
+ threadId: unprefixed(lock.threadId)
487
+ });
488
+ return {
489
+ appendToList: (key, value, options) => base.appendToList(prefixed(key), value, options),
490
+ connect: () => base.connect(),
491
+ disconnect: () => base.disconnect(),
492
+ subscribe: (threadId) => base.subscribe(prefixed(threadId)),
493
+ unsubscribe: (threadId) => base.unsubscribe(prefixed(threadId)),
494
+ isSubscribed: (threadId) => base.isSubscribed(prefixed(threadId)),
495
+ acquireLock: async (threadId, ttlMs) => {
496
+ const lock = await base.acquireLock(prefixed(threadId), ttlMs);
497
+ return lock ? unprefixLock(lock) : null;
498
+ },
499
+ releaseLock: (lock) => base.releaseLock(prefixLock(lock)),
500
+ extendLock: async (lock, ttlMs) => {
501
+ const prefixedLock = prefixLock(lock);
502
+ const extended = await base.extendLock(prefixedLock, ttlMs);
503
+ if (extended) {
504
+ lock.expiresAt = prefixedLock.expiresAt;
505
+ }
506
+ return extended;
507
+ },
508
+ forceReleaseLock: (threadId) => base.forceReleaseLock(prefixed(threadId)),
509
+ enqueue: (threadId, entry, maxSize) => base.enqueue(prefixed(threadId), entry, maxSize),
510
+ dequeue: (threadId) => base.dequeue(prefixed(threadId)),
511
+ queueDepth: (threadId) => base.queueDepth(prefixed(threadId)),
512
+ get: (key) => base.get(prefixed(key)),
513
+ getList: (key) => base.getList(prefixed(key)),
514
+ set: (key, value, ttlMs) => base.set(prefixed(key), value, ttlMs),
515
+ setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(prefixed(key), value, ttlMs),
516
+ delete: (key) => base.delete(prefixed(key))
517
+ };
518
+ }
420
519
  function createQueuedStateAdapter(base, options) {
421
520
  const heartbeats = /* @__PURE__ */ new Map();
422
521
  const effectiveLockTtlMs = (ttlMs) => Math.max(ttlMs, ACTIVE_LOCK_TTL_MS);
@@ -541,14 +640,18 @@ function createQueuedStateAdapter(base, options) {
541
640
  delete: (key) => base.delete(key)
542
641
  };
543
642
  }
643
+ function withOptionalPrefix(base, prefix) {
644
+ return prefix ? createPrefixedStateAdapter(base, prefix) : base;
645
+ }
544
646
  function createStateAdapter() {
545
647
  const config = getChatConfig();
546
648
  const activeLockMaxAgeMs = config.bot.turnTimeoutMs + ACTIVE_LOCK_TTL_MS;
547
649
  if (config.state.adapter === "memory") {
548
650
  redisStateAdapter = void 0;
549
- return createQueuedStateAdapter(createMemoryState(), {
550
- activeLockMaxAgeMs
551
- });
651
+ return createQueuedStateAdapter(
652
+ withOptionalPrefix(createMemoryState(), config.state.keyPrefix),
653
+ { activeLockMaxAgeMs }
654
+ );
552
655
  }
553
656
  if (!config.state.redisUrl) {
554
657
  throw new Error("REDIS_URL is required for durable Slack thread state");
@@ -557,9 +660,10 @@ function createStateAdapter() {
557
660
  url: config.state.redisUrl
558
661
  });
559
662
  redisStateAdapter = redisState;
560
- return createQueuedStateAdapter(redisState, {
561
- activeLockMaxAgeMs
562
- });
663
+ return createQueuedStateAdapter(
664
+ withOptionalPrefix(redisState, config.state.keyPrefix),
665
+ { activeLockMaxAgeMs }
666
+ );
563
667
  }
564
668
  function getStateAdapter() {
565
669
  if (!stateAdapter) {
@@ -2,7 +2,7 @@ import {
2
2
  getPluginForSkillPath,
3
3
  getPluginSkillRoots,
4
4
  logWarn
5
- } from "./chunk-YITDDLS3.js";
5
+ } from "./chunk-TTUY467K.js";
6
6
  import {
7
7
  skillRoots
8
8
  } from "./chunk-5LUISFEY.js";
@@ -0,0 +1,21 @@
1
+ // src/vercel.ts
2
+ function juniorVercelConfig(options = {}) {
3
+ const buildCommand = options.buildCommand === void 0 ? "pnpm build" : options.buildCommand;
4
+ const config = {
5
+ framework: "nitro",
6
+ crons: [
7
+ {
8
+ path: "/api/internal/heartbeat",
9
+ schedule: "* * * * *"
10
+ }
11
+ ]
12
+ };
13
+ if (buildCommand !== null) {
14
+ config.buildCommand = buildCommand;
15
+ }
16
+ return config;
17
+ }
18
+
19
+ export {
20
+ juniorVercelConfig
21
+ };
@@ -297,6 +297,8 @@ function contextToAttributes(context) {
297
297
  "enduser.id": context.slackUserId,
298
298
  "enduser.pseudo.id": context.slackUserName,
299
299
  "app.run.id": context.runId,
300
+ "app.actor.type": context.actorType,
301
+ "app.actor.id": context.actorId,
300
302
  "gen_ai.agent.name": context.assistantUserName,
301
303
  "gen_ai.request.model": context.modelId,
302
304
  "app.skill.name": context.skillName,
@@ -592,6 +594,10 @@ function pushPrettyConsoleToken(tokens, token) {
592
594
  function numericConsoleToken(label, value) {
593
595
  return typeof value === "number" ? `${label}=${value}` : void 0;
594
596
  }
597
+ function stringConsoleToken(label, value) {
598
+ const normalized = toOptionalString(value);
599
+ return normalized ? `${label}=${normalized}` : void 0;
600
+ }
595
601
  function booleanConsoleToken(label, value) {
596
602
  return typeof value === "boolean" ? `${label}=${value ? "yes" : "no"}` : void 0;
597
603
  }
@@ -606,7 +612,7 @@ function getPrettyConsoleSummaryTokens(level, eventName, attributes) {
606
612
  );
607
613
  pushPrettyConsoleToken(
608
614
  tokens,
609
- toOptionalString(attributes["app.plugin.name"]) ?? void 0
615
+ eventName.startsWith("trusted_plugin_heartbeat") ? stringConsoleToken("plugin", attributes["app.plugin.name"]) : toOptionalString(attributes["app.plugin.name"]) ?? void 0
610
616
  );
611
617
  pushPrettyConsoleToken(
612
618
  tokens,
@@ -624,6 +630,10 @@ function getPrettyConsoleSummaryTokens(level, eventName, attributes) {
624
630
  tokens,
625
631
  numericConsoleToken("plugins", attributes["app.plugin.count"])
626
632
  );
633
+ pushPrettyConsoleToken(
634
+ tokens,
635
+ numericConsoleToken("dispatches", attributes["app.dispatch.count"])
636
+ );
627
637
  pushPrettyConsoleToken(
628
638
  tokens,
629
639
  numericConsoleToken("skills", attributes["app.skill.count"])
@@ -2473,10 +2483,7 @@ function createGitHubAppBroker(manifest, credentials) {
2473
2483
  const normalizedApiDomain = apiDomain.toLowerCase();
2474
2484
  return normalizedDomain === "github.com" || normalizedApiDomain.startsWith("api.") && normalizedDomain === normalizedApiDomain.slice("api.".length);
2475
2485
  }
2476
- const permissions = capabilitiesToPermissions(
2477
- manifest.capabilities,
2478
- provider
2479
- );
2486
+ const permissions = manifest.capabilities?.length ? capabilitiesToPermissions(manifest.capabilities, provider) : void 0;
2480
2487
  function createLease(params) {
2481
2488
  return {
2482
2489
  id: randomUUID2(),
@@ -2516,9 +2523,7 @@ function createGitHubAppBroker(manifest, credentials) {
2516
2523
  return {
2517
2524
  async issue(input) {
2518
2525
  const installationId = resolveInstallationId();
2519
- const tokenRequestBody = {
2520
- permissions
2521
- };
2526
+ const tokenRequestBody = permissions ? { permissions } : {};
2522
2527
  const appId = resolveAppId(appIdEnv);
2523
2528
  const appJwt = createAppJwt(appId, privateKeyEnv);
2524
2529
  const accessTokenResponse = await githubRequest(apiBase, `/app/installations/${installationId}/access_tokens`, {
@@ -3204,7 +3209,6 @@ export {
3204
3209
  serializeGenAiAttribute,
3205
3210
  extractGenAiUsageSummary,
3206
3211
  extractGenAiUsageAttributes,
3207
- mergeHeaderTransforms,
3208
3212
  resolvePluginCommandEnv,
3209
3213
  resolveAuthTokenPlaceholder,
3210
3214
  parsePluginManifest,
package/dist/cli/check.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  parseSkillFile
3
- } from "../chunk-QCHPJ4FD.js";
3
+ } from "../chunk-D3G3YOU4.js";
4
4
  import {
5
5
  parsePluginManifest
6
- } from "../chunk-YITDDLS3.js";
6
+ } from "../chunk-TTUY467K.js";
7
7
  import "../chunk-Z3YD6NHK.js";
8
8
  import "../chunk-5LUISFEY.js";
9
9
  import "../chunk-2KG3PWR4.js";
package/dist/cli/init.js CHANGED
@@ -1,3 +1,6 @@
1
+ import {
2
+ juniorVercelConfig
3
+ } from "../chunk-SCQPBJAU.js";
1
4
  import "../chunk-2KG3PWR4.js";
2
5
 
3
6
  // src/cli/init.ts
@@ -51,7 +54,7 @@ export default defineConfig({
51
54
  function writeVercelJson(targetDir) {
52
55
  fs.writeFileSync(
53
56
  path.join(targetDir, "vercel.json"),
54
- `${JSON.stringify({ framework: "nitro", buildCommand: "pnpm build" }, null, 2)}
57
+ `${JSON.stringify(juniorVercelConfig(), null, 2)}
55
58
  `
56
59
  );
57
60
  }
@@ -178,6 +181,7 @@ AI_FAST_MODEL=
178
181
  AI_VISION_MODEL=
179
182
  AI_WEB_SEARCH_MODEL=
180
183
  REDIS_URL=
184
+ CRON_SECRET=
181
185
  SENTRY_DSN=
182
186
  SENTRY_ORG_SLUG=
183
187
  `
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  disconnectStateAdapter,
3
3
  resolveRuntimeDependencySnapshot
4
- } from "../chunk-7WTXNEPF.js";
4
+ } from "../chunk-AA5TIFN5.js";
5
5
  import {
6
6
  getPluginProviders,
7
7
  getPluginRuntimeDependencies,
8
8
  getPluginRuntimePostinstall
9
- } from "../chunk-YITDDLS3.js";
9
+ } from "../chunk-TTUY467K.js";
10
10
  import "../chunk-Z3YD6NHK.js";
11
11
  import "../chunk-5LUISFEY.js";
12
12
  import "../chunk-2KG3PWR4.js";
@@ -0,0 +1,3 @@
1
+ import type { WaitUntilFn } from "@/handlers/types";
2
+ /** Handle the authenticated internal agent-dispatch callback. */
3
+ export declare function POST(request: Request, waitUntil: WaitUntilFn): Promise<Response>;
@@ -0,0 +1,3 @@
1
+ import type { WaitUntilFn } from "@/handlers/types";
2
+ /** Handle the authenticated internal heartbeat. */
3
+ export declare function GET(request: Request, waitUntil: WaitUntilFn): Promise<Response>;
@@ -1,4 +1,9 @@
1
+ import { type SandboxEgressHttpInterceptor } from "@/chat/sandbox/egress-proxy";
2
+ interface SandboxEgressProxyOptions {
3
+ interceptHttp?: SandboxEgressHttpInterceptor;
4
+ }
1
5
  /** Handles Vercel Sandbox firewall egress proxy requests. */
2
- export declare function ALL(request: Request): Promise<Response>;
6
+ export declare function ALL(request: Request, options?: SandboxEgressProxyOptions): Promise<Response>;
3
7
  /** Return whether a request should be routed through sandbox egress proxying. */
4
8
  export declare function isSandboxEgressRequest(request: Request): boolean;
9
+ export {};
package/dist/vercel.js CHANGED
@@ -1,16 +1,7 @@
1
+ import {
2
+ juniorVercelConfig
3
+ } from "./chunk-SCQPBJAU.js";
1
4
  import "./chunk-2KG3PWR4.js";
2
-
3
- // src/vercel.ts
4
- function juniorVercelConfig(options = {}) {
5
- const buildCommand = options.buildCommand === void 0 ? "pnpm build" : options.buildCommand;
6
- const config = {
7
- framework: "nitro"
8
- };
9
- if (buildCommand !== null) {
10
- config.buildCommand = buildCommand;
11
- }
12
- return config;
13
- }
14
5
  export {
15
6
  juniorVercelConfig
16
7
  };
package/package.json CHANGED
@@ -1,11 +1,16 @@
1
1
  {
2
2
  "name": "@sentry/junior",
3
- "version": "0.54.0",
3
+ "version": "0.56.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "type": "module",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/getsentry/junior.git",
12
+ "directory": "packages/junior"
13
+ },
9
14
  "bin": {
10
15
  "junior": "bin/junior.mjs"
11
16
  },
@@ -40,7 +45,8 @@
40
45
  "just-bash": "3.0.1",
41
46
  "node-html-markdown": "^2.0.0",
42
47
  "yaml": "^2.9.0",
43
- "zod": "^4.4.3"
48
+ "zod": "^4.4.3",
49
+ "@sentry/junior-plugin-api": "0.56.0"
44
50
  },
45
51
  "peerDependencies": {
46
52
  "@sentry/node": ">=10.0.0"
@@ -1,19 +0,0 @@
1
- import type { CredentialBroker, CredentialHeaderTransform, CredentialLease } from "@/chat/credentials/broker";
2
- interface TestBrokerConfig {
3
- provider: string;
4
- domains?: string[];
5
- apiHeaders?: Record<string, string>;
6
- headerTransforms?: () => CredentialHeaderTransform[];
7
- env?: Record<string, string>;
8
- envKey?: string;
9
- placeholder?: string;
10
- }
11
- /** Issue deterministic placeholder credential leases for eval runs. */
12
- export declare class TestCredentialBroker implements CredentialBroker {
13
- private readonly config;
14
- constructor(config: TestBrokerConfig);
15
- issue(input: {
16
- reason: string;
17
- }): Promise<CredentialLease>;
18
- }
19
- export {};
@@ -1,2 +0,0 @@
1
- /** Build the eval-only GitHub CLI shim copied into sandbox test environments. */
2
- export declare function buildEvalGitHubCliStub(): string;
@@ -1,2 +0,0 @@
1
- /** Build the eval-only generic OAuth CLI shim copied into sandbox eval environments. */
2
- export declare function buildEvalOauthCliStub(): string;
@@ -1,2 +0,0 @@
1
- /** Build the eval-only Sentry CLI shim copied into sandbox test environments. */
2
- export declare function buildEvalSentryCliStub(): string;
@@ -1,2 +0,0 @@
1
- /** Consume one eval-only sandbox bash stream interruption fault. */
2
- export declare function consumeSandboxBashStreamInterruptFault(): Error | undefined;