@sentry/junior 0.67.1 → 0.67.3

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/app.d.ts CHANGED
@@ -5,6 +5,13 @@ import type { WaitUntilFn } from "@/handlers/types";
5
5
  export { defineJuniorPlugins } from "@/plugins";
6
6
  export type { JuniorPluginInput, JuniorPluginSet, JuniorPluginSetOptions, } from "@/plugins";
7
7
  export interface JuniorAppOptions {
8
+ /** Slack-specific overrides applied after env parsing. */
9
+ slack?: {
10
+ /** Slack emoji shown while Junior is processing. Defaults to `eyes`. */
11
+ processingReactionEmoji?: string;
12
+ /** Slack emoji shown after a turn completes. Defaults to `white_check_mark`. */
13
+ completedReactionEmoji?: string;
14
+ };
8
15
  /** Install-wide provider defaults (`provider.key` format). Channel overrides take precedence. */
9
16
  configDefaults?: Record<string, unknown>;
10
17
  /** Queue consumer wiring for the durable conversation worker. */
package/dist/app.js CHANGED
@@ -47,7 +47,7 @@ import {
47
47
  validateAgentPlugins,
48
48
  verifySlackDirectCredentialSubject,
49
49
  withSlackRetries
50
- } from "./chunk-5UIDU7XR.js";
50
+ } from "./chunk-UQQSW7QB.js";
51
51
  import {
52
52
  discoverSkills,
53
53
  findSkillByName,
@@ -62,7 +62,7 @@ import {
62
62
  isSnapshotMissingError,
63
63
  resolveRuntimeDependencySnapshot,
64
64
  runNonInteractiveCommand
65
- } from "./chunk-YGGH2742.js";
65
+ } from "./chunk-PIVOJIUD.js";
66
66
  import {
67
67
  ACTIVE_LOCK_TTL_MS,
68
68
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
@@ -83,6 +83,7 @@ import {
83
83
  getSlackBotToken,
84
84
  getSlackClientId,
85
85
  getSlackClientSecret,
86
+ getSlackReactionConfig,
86
87
  getSlackSigningSecret,
87
88
  getStateAdapter,
88
89
  normalizeSlackEmojiName,
@@ -93,12 +94,13 @@ import {
93
94
  resolveSlackChannelIdFromThreadId,
94
95
  sandboxSkillDir,
95
96
  sandboxSkillFile,
97
+ setSlackReactionConfig,
96
98
  toGenAiMessageMetadata,
97
99
  toGenAiMessagesTraceAttributes,
98
100
  toGenAiPayloadMetadata,
99
101
  toGenAiPayloadTraceAttributes,
100
102
  toGenAiTextMetadata
101
- } from "./chunk-MT23VNOH.js";
103
+ } from "./chunk-EBVQXCD2.js";
102
104
  import {
103
105
  CredentialUnavailableError,
104
106
  buildActorIdentity,
@@ -15486,7 +15488,7 @@ var noProcessingReaction = {
15486
15488
  stop: async () => void 0
15487
15489
  };
15488
15490
  function isProcessingReactionEmoji(value) {
15489
- return typeof value === "string" && normalizeSlackEmojiName(value) === botConfig.processingReactionEmoji;
15491
+ return typeof value === "string" && normalizeSlackEmojiName(value) === getChatConfig().slack.processingReactionEmoji;
15490
15492
  }
15491
15493
  function shouldKeepProcessingReactionForToolInvocation(input) {
15492
15494
  return input.toolName === "slackMessageAddReaction" && isProcessingReactionEmoji(input.params.emoji);
@@ -15512,7 +15514,7 @@ async function startSlackProcessingReactionForMessage(args) {
15512
15514
  await addReactionToMessage({
15513
15515
  channelId: args.channelId,
15514
15516
  timestamp: args.timestamp,
15515
- emoji: botConfig.processingReactionEmoji
15517
+ emoji: getChatConfig().slack.processingReactionEmoji
15516
15518
  });
15517
15519
  } catch (error) {
15518
15520
  args.logException(
@@ -15537,7 +15539,7 @@ async function startSlackProcessingReactionForMessage(args) {
15537
15539
  await removeReactionFromMessage({
15538
15540
  channelId: args.channelId,
15539
15541
  timestamp: args.timestamp,
15540
- emoji: botConfig.processingReactionEmoji
15542
+ emoji: getChatConfig().slack.processingReactionEmoji
15541
15543
  });
15542
15544
  return true;
15543
15545
  } catch (error) {
@@ -15564,7 +15566,7 @@ async function startSlackProcessingReactionForMessage(args) {
15564
15566
  await addReactionToMessage({
15565
15567
  channelId: args.channelId,
15566
15568
  timestamp: args.timestamp,
15567
- emoji: botConfig.completedReactionEmoji
15569
+ emoji: getChatConfig().slack.completedReactionEmoji
15568
15570
  });
15569
15571
  } catch (error) {
15570
15572
  args.logException(
@@ -22843,9 +22845,13 @@ async function createApp(options) {
22843
22845
  const previousPluginCatalogConfig = setPluginCatalogConfig(pluginConfig);
22844
22846
  const previousAgentPlugins = setAgentPlugins(agentPlugins);
22845
22847
  const previousConfigDefaults = getConfigDefaults();
22848
+ const previousSlackReactionConfig = getSlackReactionConfig();
22846
22849
  let agentPluginRoutes = [];
22847
22850
  try {
22848
22851
  setConfigDefaults(options?.configDefaults);
22852
+ if (options?.slack) {
22853
+ setSlackReactionConfig(options.slack);
22854
+ }
22849
22855
  if (shouldValidatePluginCatalog) {
22850
22856
  getPluginCatalogSignature();
22851
22857
  validatePluginRegistrations(configuredPlugins?.registrations ?? []);
@@ -22855,6 +22861,7 @@ async function createApp(options) {
22855
22861
  setPluginCatalogConfig(previousPluginCatalogConfig);
22856
22862
  setAgentPlugins(previousAgentPlugins);
22857
22863
  setConfigDefaults(previousConfigDefaults);
22864
+ setSlackReactionConfig(previousSlackReactionConfig);
22858
22865
  throw error;
22859
22866
  }
22860
22867
  const waitUntil = options?.waitUntil ?? await defaultWaitUntil();
@@ -7,12 +7,10 @@ export type AdvisorThinkingLevel = (typeof ADVISOR_THINKING_LEVELS)[number];
7
7
  export declare const FUNCTION_TIMEOUT_BUFFER_SECONDS = 20;
8
8
  export interface BotConfig {
9
9
  advisor: AdvisorConfig;
10
- completedReactionEmoji: string;
11
10
  fastModelId: string;
12
11
  loadingMessages: string[];
13
12
  modelId: string;
14
13
  modelContextWindowTokens?: number;
15
- processingReactionEmoji: string;
16
14
  visionModelId?: string;
17
15
  turnTimeoutMs: number;
18
16
  userName: string;
@@ -28,6 +26,8 @@ export interface ChatConfig {
28
26
  botToken?: string;
29
27
  clientId?: string;
30
28
  clientSecret?: string;
29
+ completedReactionEmoji: string;
30
+ processingReactionEmoji: string;
31
31
  signingSecret?: string;
32
32
  slashCommand: string;
33
33
  };
@@ -53,4 +53,12 @@ export interface RuntimeMetadata {
53
53
  }
54
54
  /** Return runtime metadata (version from deploy environment). */
55
55
  export declare function getRuntimeMetadata(): RuntimeMetadata;
56
+ export interface SlackReactionConfig {
57
+ completedReactionEmoji: string;
58
+ processingReactionEmoji: string;
59
+ }
60
+ /** Return the current Slack reaction emoji config. */
61
+ export declare function getSlackReactionConfig(): SlackReactionConfig;
62
+ /** Apply Slack reaction emoji overrides from createApp() options, validating names. */
63
+ export declare function setSlackReactionConfig(overrides: Partial<SlackReactionConfig>): void;
56
64
  export {};
@@ -1,12 +1,13 @@
1
1
  /** Insert blank lines between content blocks so Slack renders them with visual separation. */
2
2
  export declare function ensureBlockSpacing(text: string): string;
3
3
  /**
4
- * Render model-authored markdown into Slack-friendly `mrkdwn`.
4
+ * Normalize model-authored Slack markdown for delivery via `markdown_text`
5
+ * or `{ type: "markdown" }` blocks.
5
6
  *
6
- * Slack reply delivery owns chunking and continuation markers separately.
7
- * This helper only normalizes text into the repository's canonical Slack
8
- * rendering form.
7
+ * Pre-wraps bare URLs as Slack explicit links to prevent Slack's auto-linker
8
+ * from consuming adjacent formatting markers. Slack reply delivery owns
9
+ * chunking and continuation markers separately.
9
10
  */
10
- export declare function renderSlackMrkdwn(text: string): string;
11
+ export declare function normalizeSlackReplyMarkdown(text: string): string;
11
12
  /** Normalize assistant status text before handing it to Slack. */
12
13
  export declare function normalizeSlackStatusText(text: string): string;
@@ -207,10 +207,6 @@ function toGenAiMessagesTraceAttributes(prefix, messages) {
207
207
  };
208
208
  }
209
209
 
210
- // src/chat/state/adapter.ts
211
- import { createMemoryState } from "@chat-adapter/state-memory";
212
- import { createRedisState } from "@chat-adapter/state-redis";
213
-
214
210
  // src/chat/config.ts
215
211
  import { getModel } from "@earendil-works/pi-ai";
216
212
 
@@ -658,16 +654,6 @@ function readBotConfig(env) {
658
654
  ),
659
655
  fastModelId: validateGatewayModelId(env.AI_FAST_MODEL ?? env.AI_MODEL) ?? DEFAULT_FAST_MODEL_ID,
660
656
  loadingMessages: parseLoadingMessages(env.JUNIOR_LOADING_MESSAGES),
661
- processingReactionEmoji: parseReactionEmoji(
662
- "JUNIOR_PROCESSING_REACTION",
663
- env.JUNIOR_PROCESSING_REACTION,
664
- DEFAULT_PROCESSING_REACTION_EMOJI
665
- ),
666
- completedReactionEmoji: parseReactionEmoji(
667
- "JUNIOR_COMPLETED_REACTION",
668
- env.JUNIOR_COMPLETED_REACTION,
669
- DEFAULT_COMPLETED_REACTION_EMOJI
670
- ),
671
657
  visionModelId: validateGatewayModelId(env.AI_VISION_MODEL),
672
658
  turnTimeoutMs: parseAgentTurnTimeoutMs(
673
659
  env.AGENT_TURN_TIMEOUT_MS,
@@ -682,9 +668,11 @@ function readChatConfig(env = process.env) {
682
668
  functionMaxDurationSeconds: resolveFunctionMaxDurationSeconds(env),
683
669
  slack: {
684
670
  botToken: toOptionalTrimmed(env.SLACK_BOT_TOKEN) ?? toOptionalTrimmed(env.SLACK_BOT_USER_TOKEN),
685
- signingSecret: toOptionalTrimmed(env.SLACK_SIGNING_SECRET),
686
671
  clientId: toOptionalTrimmed(env.SLACK_CLIENT_ID),
687
672
  clientSecret: toOptionalTrimmed(env.SLACK_CLIENT_SECRET),
673
+ completedReactionEmoji: DEFAULT_COMPLETED_REACTION_EMOJI,
674
+ processingReactionEmoji: DEFAULT_PROCESSING_REACTION_EMOJI,
675
+ signingSecret: toOptionalTrimmed(env.SLACK_SIGNING_SECRET),
688
676
  slashCommand: parseSlashCommand(env.JUNIOR_SLASH_COMMAND)
689
677
  },
690
678
  state: {
@@ -716,8 +704,32 @@ function getRuntimeMetadata() {
716
704
  version: toOptionalTrimmed(process.env.VERCEL_GIT_COMMIT_SHA)
717
705
  };
718
706
  }
707
+ function getSlackReactionConfig() {
708
+ return {
709
+ completedReactionEmoji: chatConfig.slack.completedReactionEmoji,
710
+ processingReactionEmoji: chatConfig.slack.processingReactionEmoji
711
+ };
712
+ }
713
+ function setSlackReactionConfig(overrides) {
714
+ if (overrides.processingReactionEmoji !== void 0) {
715
+ chatConfig.slack.processingReactionEmoji = parseReactionEmoji(
716
+ "processingReactionEmoji",
717
+ overrides.processingReactionEmoji,
718
+ chatConfig.slack.processingReactionEmoji
719
+ );
720
+ }
721
+ if (overrides.completedReactionEmoji !== void 0) {
722
+ chatConfig.slack.completedReactionEmoji = parseReactionEmoji(
723
+ "completedReactionEmoji",
724
+ overrides.completedReactionEmoji,
725
+ chatConfig.slack.completedReactionEmoji
726
+ );
727
+ }
728
+ }
719
729
 
720
730
  // src/chat/state/adapter.ts
731
+ import { createMemoryState } from "@chat-adapter/state-memory";
732
+ import { createRedisState } from "@chat-adapter/state-redis";
721
733
  var ACTIVE_LOCK_TTL_MS = 9e4;
722
734
  var ACTIVE_LOCK_HEARTBEAT_MS = 3e4;
723
735
  var stateAdapter;
@@ -994,6 +1006,8 @@ export {
994
1006
  getSlackClientId,
995
1007
  getSlackClientSecret,
996
1008
  getRuntimeMetadata,
1009
+ getSlackReactionConfig,
1010
+ setSlackReactionConfig,
997
1011
  ACTIVE_LOCK_TTL_MS,
998
1012
  getConnectedStateContext,
999
1013
  getStateAdapter,
@@ -2,7 +2,7 @@ import {
2
2
  SANDBOX_WORKSPACE_ROOT,
3
3
  getStateAdapter,
4
4
  toOptionalTrimmed
5
- } from "./chunk-MT23VNOH.js";
5
+ } from "./chunk-EBVQXCD2.js";
6
6
  import {
7
7
  getPluginRuntimeDependencies,
8
8
  getPluginRuntimePostinstall,
@@ -8,7 +8,7 @@ import {
8
8
  getStateAdapter,
9
9
  parseSlackThreadId,
10
10
  sandboxSkillDir
11
- } from "./chunk-MT23VNOH.js";
11
+ } from "./chunk-EBVQXCD2.js";
12
12
  import {
13
13
  isActorUserId,
14
14
  isRecord,
@@ -1095,6 +1095,145 @@ function truncateStatusText(text) {
1095
1095
  }
1096
1096
 
1097
1097
  // src/chat/slack/mrkdwn.ts
1098
+ function readInlineCodeSpan(line, start) {
1099
+ if (line[start] !== "`") {
1100
+ return void 0;
1101
+ }
1102
+ let n = 1;
1103
+ while (line[start + n] === "`") {
1104
+ n++;
1105
+ }
1106
+ const marker = "`".repeat(n);
1107
+ let search = start + n;
1108
+ while (search < line.length) {
1109
+ const close = line.indexOf(marker, search);
1110
+ if (close === -1) {
1111
+ return void 0;
1112
+ }
1113
+ const after = close + n;
1114
+ if (line[after] !== "`") {
1115
+ return { text: line.slice(start, after), end: after };
1116
+ }
1117
+ search = after + 1;
1118
+ }
1119
+ return void 0;
1120
+ }
1121
+ function readExistingSlackAngleToken(line, start) {
1122
+ if (line[start] !== "<") {
1123
+ return void 0;
1124
+ }
1125
+ const close = line.indexOf(">", start + 1);
1126
+ if (close === -1) {
1127
+ return void 0;
1128
+ }
1129
+ const body = line.slice(start + 1, close);
1130
+ if (/^(?:https?:\/\/|@|#|!)/.test(body)) {
1131
+ return { text: line.slice(start, close + 1), end: close + 1 };
1132
+ }
1133
+ return void 0;
1134
+ }
1135
+ function readMarkdownLink(line, start) {
1136
+ if (line[start] !== "[") {
1137
+ return void 0;
1138
+ }
1139
+ const labelEnd = line.indexOf("](", start + 1);
1140
+ if (labelEnd === -1) {
1141
+ return void 0;
1142
+ }
1143
+ const destStart = labelEnd + 2;
1144
+ if (!line.startsWith("http://", destStart) && !line.startsWith("https://", destStart)) {
1145
+ return void 0;
1146
+ }
1147
+ const closeParens = line.indexOf(")", destStart);
1148
+ if (closeParens === -1) {
1149
+ return void 0;
1150
+ }
1151
+ return { text: line.slice(start, closeParens + 1), end: closeParens + 1 };
1152
+ }
1153
+ function hasUnmatchedClosingParen(text) {
1154
+ let balance = 0;
1155
+ for (const ch of text) {
1156
+ if (ch === "(") balance++;
1157
+ else if (ch === ")") balance--;
1158
+ }
1159
+ return balance < 0;
1160
+ }
1161
+ function readBareUrl(line, start) {
1162
+ let end = start;
1163
+ while (end < line.length) {
1164
+ const ch = line[end];
1165
+ if (/\s/.test(ch) || ch === "<" || ch === ">" || ch === '"' || ch === "`" || ch === "|" || ch === "*") {
1166
+ break;
1167
+ }
1168
+ end++;
1169
+ }
1170
+ if (end === start) {
1171
+ return void 0;
1172
+ }
1173
+ let raw = line.slice(start, end);
1174
+ let suffix = "";
1175
+ const peel = () => {
1176
+ suffix = raw.slice(-1) + suffix;
1177
+ raw = raw.slice(0, -1);
1178
+ };
1179
+ const shouldPeel = () => raw.endsWith("_") || /[.,!?;:]$/.test(raw) || raw.endsWith(")") && hasUnmatchedClosingParen(raw);
1180
+ while (raw.length > 0 && shouldPeel()) {
1181
+ peel();
1182
+ }
1183
+ if (!/^https?:\/\/.+/.test(raw)) {
1184
+ return void 0;
1185
+ }
1186
+ return { url: raw, suffix, end };
1187
+ }
1188
+ function wrapBareUrlsOnLine(line) {
1189
+ let result = "";
1190
+ let i = 0;
1191
+ while (i < line.length) {
1192
+ const codeSpan = readInlineCodeSpan(line, i);
1193
+ if (codeSpan) {
1194
+ result += codeSpan.text;
1195
+ i = codeSpan.end;
1196
+ continue;
1197
+ }
1198
+ const angleToken = readExistingSlackAngleToken(line, i);
1199
+ if (angleToken) {
1200
+ result += angleToken.text;
1201
+ i = angleToken.end;
1202
+ continue;
1203
+ }
1204
+ const mdLink = readMarkdownLink(line, i);
1205
+ if (mdLink) {
1206
+ result += mdLink.text;
1207
+ i = mdLink.end;
1208
+ continue;
1209
+ }
1210
+ if (line.startsWith("https://", i) || line.startsWith("http://", i)) {
1211
+ const parsed = readBareUrl(line, i);
1212
+ if (parsed) {
1213
+ result += `<${parsed.url}>${parsed.suffix}`;
1214
+ i = parsed.end;
1215
+ continue;
1216
+ }
1217
+ }
1218
+ result += line[i];
1219
+ i++;
1220
+ }
1221
+ return result;
1222
+ }
1223
+ function wrapBareUrls(text) {
1224
+ const lines = text.split("\n");
1225
+ const out = [];
1226
+ let inCodeBlock = false;
1227
+ for (const line of lines) {
1228
+ if (line.trimStart().startsWith("```")) {
1229
+ inCodeBlock = !inCodeBlock;
1230
+ out.push(line);
1231
+ continue;
1232
+ }
1233
+ out.push(inCodeBlock ? line : wrapBareUrlsOnLine(line));
1234
+ }
1235
+ return out.join("\n");
1236
+ }
1098
1237
  function ensureBlockSpacing(text) {
1099
1238
  const codeBlockPattern = /^```/;
1100
1239
  const listItemPattern = /^[-*•]\s|^\d+\.\s/;
@@ -1127,8 +1266,9 @@ function ensureBlockSpacing(text) {
1127
1266
  }
1128
1267
  return result.join("\n");
1129
1268
  }
1130
- function renderSlackMrkdwn(text) {
1269
+ function normalizeSlackReplyMarkdown(text) {
1131
1270
  let normalized = text.replace(/\r\n?/g, "\n").replace(/[ \t]+$/gm, "");
1271
+ normalized = wrapBareUrls(normalized);
1132
1272
  normalized = ensureBlockSpacing(normalized);
1133
1273
  return normalized.replace(/\n{3,}/g, "\n\n").trim();
1134
1274
  }
@@ -1302,7 +1442,7 @@ function takeSlackInlinePrefix(text, options) {
1302
1442
  };
1303
1443
  }
1304
1444
  function splitSlackReplyText(text, options) {
1305
- const normalized = renderSlackMrkdwn(text);
1445
+ const normalized = normalizeSlackReplyMarkdown(text);
1306
1446
  if (!normalized) {
1307
1447
  return [];
1308
1448
  }
@@ -1333,7 +1473,7 @@ function getSlackContinuationBudget() {
1333
1473
  return reserveInlineBudgetForSuffix(CONTINUED_MARKER);
1334
1474
  }
1335
1475
  function buildSlackOutputMessage(text, files) {
1336
- const normalized = renderSlackMrkdwn(text);
1476
+ const normalized = normalizeSlackReplyMarkdown(text);
1337
1477
  const fileCount = files?.length ?? 0;
1338
1478
  if (!normalized) {
1339
1479
  if (fileCount > 0) {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  resolveRuntimeDependencySnapshot
3
- } from "../chunk-YGGH2742.js";
3
+ } from "../chunk-PIVOJIUD.js";
4
4
  import {
5
5
  disconnectStateAdapter
6
- } from "../chunk-MT23VNOH.js";
6
+ } from "../chunk-EBVQXCD2.js";
7
7
  import {
8
8
  getPluginProviders,
9
9
  getPluginRuntimeDependencies,
package/dist/reporting.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  listAgentTurnSessionSummaries,
10
10
  listAgentTurnSessionSummariesForConversation,
11
11
  resolveSlackConversationContextFromThreadId
12
- } from "./chunk-5UIDU7XR.js";
12
+ } from "./chunk-UQQSW7QB.js";
13
13
  import {
14
14
  discoverSkills
15
15
  } from "./chunk-V47RLIO2.js";
@@ -17,7 +17,7 @@ import {
17
17
  canExposeConversationPayload,
18
18
  parseSlackThreadId,
19
19
  resolveConversationPrivacy
20
- } from "./chunk-MT23VNOH.js";
20
+ } from "./chunk-EBVQXCD2.js";
21
21
  import {
22
22
  getPluginPackageContent,
23
23
  getPluginProviders,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior",
3
- "version": "0.67.1",
3
+ "version": "0.67.3",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -65,7 +65,7 @@
65
65
  "node-html-markdown": "^2.0.0",
66
66
  "yaml": "^2.9.0",
67
67
  "zod": "^4.4.3",
68
- "@sentry/junior-plugin-api": "0.67.1"
68
+ "@sentry/junior-plugin-api": "0.67.3"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.9.1",
@@ -77,7 +77,7 @@
77
77
  "typescript": "^6.0.3",
78
78
  "vercel": "^54.4.0",
79
79
  "vitest": "^4.1.7",
80
- "@sentry/junior-scheduler": "0.67.1"
80
+ "@sentry/junior-scheduler": "0.67.3"
81
81
  },
82
82
  "scripts": {
83
83
  "build": "tsup && tsc -p tsconfig.build.json --emitDeclarationOnly",