@sentry/junior 0.203.0 → 0.205.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 (174) hide show
  1. package/dist/agent-D4nu8MQV.js +17521 -0
  2. package/dist/agent-hooks-DXHpTJ4m.js +4042 -0
  3. package/dist/agent-runner-C04colea.js +678 -0
  4. package/dist/api/schema.d.ts +2736 -2639
  5. package/dist/api/schema.js +4 -169
  6. package/dist/api.d.ts +23 -17
  7. package/dist/api.js +3881 -5326
  8. package/dist/app-Cb776lL8.d.ts +247 -0
  9. package/dist/app.d.ts +4 -520
  10. package/dist/app.js +9524 -11875
  11. package/dist/auth-pause-state-C2P3guS1.js +168 -0
  12. package/dist/catalog-runtime-CXw3asJD.js +7 -0
  13. package/dist/checkpoint-CrViJ8Ps.js +2450 -0
  14. package/dist/cli/chat.d.ts +20 -0
  15. package/dist/cli/chat.js +229 -336
  16. package/dist/cli/check.d.ts +8 -0
  17. package/dist/cli/check.js +513 -806
  18. package/dist/cli/env.d.ts +13 -0
  19. package/dist/cli/env.js +63 -12
  20. package/dist/cli/init.d.ts +3 -0
  21. package/dist/cli/init.js +90 -159
  22. package/dist/cli/main.d.ts +6 -0
  23. package/dist/cli/main.js +43 -64
  24. package/dist/cli/plugins.d.ts +13 -0
  25. package/dist/cli/plugins.js +148 -227
  26. package/dist/cli/run.d.ts +16 -0
  27. package/dist/cli/run.js +52 -8
  28. package/dist/cli/snapshot-create.d.ts +4 -0
  29. package/dist/cli/snapshot-create.js +71 -125
  30. package/dist/cli/upgrade.d.ts +15 -0
  31. package/dist/cli/upgrade.js +232 -335
  32. package/dist/config-BOtJQ7Pc.js +941 -0
  33. package/dist/context-B45_WqVX.js +298 -0
  34. package/dist/conversation-privacy-BZRA6Pes.js +182 -0
  35. package/dist/conversation-work-C6y3T5Hx.js +51 -0
  36. package/dist/credential-sync-Bep34IB_.js +2661 -0
  37. package/dist/db-BeyXKJOI.d.ts +5 -0
  38. package/dist/destinations-BeBiJeEM.js +29 -0
  39. package/dist/execution-stats-B6lgWxCK.js +373 -0
  40. package/dist/executor-BlUhFL7_.js +721 -0
  41. package/dist/experimental-CIXf7Uye.js +46 -0
  42. package/dist/history-ClE4toxe.d.ts +32 -0
  43. package/dist/history-CqTuSAdI.js +441 -0
  44. package/dist/instrumentation.d.ts +3 -3
  45. package/dist/instrumentation.js +130 -176
  46. package/dist/job-queue-DLMqIK74.js +63 -0
  47. package/dist/logging-BMJzdDlP.js +1210 -0
  48. package/dist/model-profile-CZmVoGdX.js +49 -0
  49. package/dist/nitro.d.ts +31 -36
  50. package/dist/nitro.js +275 -456
  51. package/dist/oauth-callback-server-WwG5_Zgm.js +130 -0
  52. package/dist/oauth-relay-CdCnu80W.js +62 -0
  53. package/dist/package-discovery-7a9YqLhE.js +455 -0
  54. package/dist/pending-auth-CUbXq06G.js +185 -0
  55. package/dist/plugin-module-BKGOXca2.js +81 -0
  56. package/dist/plugins-BI9A1vKA.d.ts +95 -0
  57. package/dist/plugins-egKWjgue.js +99 -0
  58. package/dist/private-trace-result-BLvBjy_e.js +16 -0
  59. package/dist/profile-T0tXE4zu.js +861 -0
  60. package/dist/registry-BA0__8ai.js +1419 -0
  61. package/dist/reporting-schema-DosTN__Q.js +105 -0
  62. package/dist/resolve-bvD1ORdv.js +546 -0
  63. package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
  64. package/dist/runner-BXYxfIUL.js +392 -0
  65. package/dist/sandbox-egress-signals-ngEPjSEW.js +46 -0
  66. package/dist/schema-Rn8-XEaN.js +1140 -0
  67. package/dist/sentry-CD3SdJl-.js +26 -0
  68. package/dist/skills-DJOlYdBs.js +316 -0
  69. package/dist/spawn-h0R1bTEo.js +29 -0
  70. package/dist/stats-3YZn-Swi.js +2648 -0
  71. package/dist/store-C5qxF2ac.d.ts +208 -0
  72. package/dist/task-queue-CoXwd2eq.js +136 -0
  73. package/dist/task-runner-B2_mJZj0.js +639 -0
  74. package/dist/thread-state-CqZ1m-es.js +431 -0
  75. package/dist/turn-execution-fI6PZ0iI.js +47 -0
  76. package/dist/turn-lifecycle-CcnwrOcp.js +54 -0
  77. package/dist/usage-B5SfMb3H.js +296 -0
  78. package/dist/usage-schema-CKaDkH_j.js +20 -0
  79. package/dist/validation-DfWcvhuS.js +40 -0
  80. package/dist/vercel-queue-DIkVcfK4.js +167 -0
  81. package/dist/vercel.d.ts +6 -6
  82. package/dist/vercel.js +14 -6
  83. package/dist/version-CnXZ614E.d.ts +5 -0
  84. package/dist/version-oD-oPrbO.js +8 -0
  85. package/dist/version.d.ts +2 -4
  86. package/dist/version.js +2 -6
  87. package/dist/web-authorization-Crbzlmzo.js +76 -0
  88. package/dist/web-input-BOuq3oKK.js +494 -0
  89. package/dist/work-B91LQKHr.js +509 -0
  90. package/dist/worker-BcRRTe6k.js +625 -0
  91. package/package.json +9 -9
  92. package/dist/agent-hooks-GB2VPTNA.js +0 -51
  93. package/dist/catalog-runtime-UBLIWD3O.js +0 -14
  94. package/dist/chunk-2LYHWMR4.js +0 -46
  95. package/dist/chunk-352OWAZH.js +0 -320
  96. package/dist/chunk-3Y47VMHV.js +0 -6
  97. package/dist/chunk-3YJSKOWF.js +0 -164
  98. package/dist/chunk-4KSSKTQ5.js +0 -229
  99. package/dist/chunk-4UO6FK4G.js +0 -64
  100. package/dist/chunk-5AHX53NQ.js +0 -717
  101. package/dist/chunk-5J3E5FWA.js +0 -700
  102. package/dist/chunk-5PDAG6O3.js +0 -206
  103. package/dist/chunk-6Y5B5PEX.js +0 -80
  104. package/dist/chunk-7GWQ5S5R.js +0 -2086
  105. package/dist/chunk-7H2VZTWN.js +0 -103
  106. package/dist/chunk-7NL7T6VU.js +0 -406
  107. package/dist/chunk-A5L27LE4.js +0 -387
  108. package/dist/chunk-ADIAWL34.js +0 -81
  109. package/dist/chunk-ASTEMBKJ.js +0 -519
  110. package/dist/chunk-CEMMLV5L.js +0 -98
  111. package/dist/chunk-CM5HNV2W.js +0 -131
  112. package/dist/chunk-CRTRBBRI.js +0 -105
  113. package/dist/chunk-DA2KGZZI.js +0 -13
  114. package/dist/chunk-DIB4GX3G.js +0 -8
  115. package/dist/chunk-DKIJ2RP5.js +0 -68
  116. package/dist/chunk-DWPN6SCH.js +0 -172
  117. package/dist/chunk-EDKUFGPL.js +0 -64
  118. package/dist/chunk-ENY6SKIU.js +0 -1228
  119. package/dist/chunk-F4MGCZOX.js +0 -2943
  120. package/dist/chunk-FA6POGLH.js +0 -70
  121. package/dist/chunk-FSUR7GTG.js +0 -20475
  122. package/dist/chunk-GKEOHJL5.js +0 -1856
  123. package/dist/chunk-GMCB6W5Y.js +0 -333
  124. package/dist/chunk-IE2VPG7O.js +0 -1135
  125. package/dist/chunk-IZ5B5IHQ.js +0 -3656
  126. package/dist/chunk-JAL3CH4G.js +0 -27
  127. package/dist/chunk-KIIEUXD3.js +0 -1764
  128. package/dist/chunk-KXU4NIL7.js +0 -692
  129. package/dist/chunk-MTM5IFCY.js +0 -1190
  130. package/dist/chunk-N7TMSOZH.js +0 -235
  131. package/dist/chunk-NCEBK6PH.js +0 -36
  132. package/dist/chunk-NHJU2ZAL.js +0 -56
  133. package/dist/chunk-P6KTRNVC.js +0 -321
  134. package/dist/chunk-PDO5BLNM.js +0 -22
  135. package/dist/chunk-PDRNLLFT.js +0 -3295
  136. package/dist/chunk-PEQXYSSE.js +0 -45
  137. package/dist/chunk-PKEX2AQX.js +0 -198
  138. package/dist/chunk-PSJCGIGO.js +0 -1163
  139. package/dist/chunk-PZUSUL55.js +0 -506
  140. package/dist/chunk-R45M4TUS.js +0 -37
  141. package/dist/chunk-RC745GGZ.js +0 -122
  142. package/dist/chunk-SP3QKZXJ.js +0 -820
  143. package/dist/chunk-TXKUKMVO.js +0 -417
  144. package/dist/chunk-UE4GPWSD.js +0 -931
  145. package/dist/chunk-UIE3R5XU.js +0 -17
  146. package/dist/chunk-UXPG6ZIN.js +0 -84
  147. package/dist/chunk-VFUK3X5B.js +0 -50
  148. package/dist/chunk-VNMJWREK.js +0 -787
  149. package/dist/chunk-VZ7CSOX2.js +0 -706
  150. package/dist/chunk-WCNQJKFT.js +0 -10
  151. package/dist/chunk-WDZR3QQM.js +0 -135
  152. package/dist/chunk-WLYVJCHV.js +0 -1433
  153. package/dist/chunk-WS7NAFTM.js +0 -1520
  154. package/dist/chunk-X6GDDWQH.js +0 -60
  155. package/dist/chunk-XPDEYNQI.js +0 -102
  156. package/dist/chunk-XRW44VGM.js +0 -58
  157. package/dist/chunk-Y2CM7HXH.js +0 -111
  158. package/dist/chunk-Y7X25LFY.js +0 -15
  159. package/dist/conversation-work-VIOQ5ZF3.js +0 -54
  160. package/dist/db-NGDJV7YH.js +0 -26
  161. package/dist/discovery-DWVDM7UK.js +0 -44
  162. package/dist/experimental-P5FZM4CU.js +0 -12
  163. package/dist/oauth-callback-server-YFY7YEGK.js +0 -243
  164. package/dist/oauth-relay-5XPVRPYB.js +0 -8
  165. package/dist/plugins-YTYJMMJF.js +0 -14
  166. package/dist/runner-ORTNSB2Q.js +0 -522
  167. package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
  168. package/dist/sentry-MB3NL3IR.js +0 -42
  169. package/dist/skills-H376WQOH.js +0 -27
  170. package/dist/spawn-T43WHLOS.js +0 -42
  171. package/dist/task-runner-LBZWF32V.js +0 -36
  172. package/dist/validation-REJLRKI6.js +0 -17
  173. package/dist/work-3KJ3RE76.js +0 -51
  174. package/dist/worker-QFEBU72E.js +0 -24
@@ -1,931 +0,0 @@
1
- import {
2
- isExperimentalFeatureEnabled
3
- } from "./chunk-2LYHWMR4.js";
4
- import {
5
- SlackActionError,
6
- applyPluginFormatMarkdown,
7
- getSlackClient,
8
- isDmChannel,
9
- normalizeSlackConversationId,
10
- withSlackRetries
11
- } from "./chunk-IZ5B5IHQ.js";
12
- import {
13
- parseDestination
14
- } from "./chunk-GKEOHJL5.js";
15
- import {
16
- getStateAdapter
17
- } from "./chunk-P6KTRNVC.js";
18
- import {
19
- normalizeSlackEmojiName
20
- } from "./chunk-ENY6SKIU.js";
21
- import {
22
- pluginCatalogRuntime
23
- } from "./chunk-WCNQJKFT.js";
24
- import {
25
- parseSlackMessageTs,
26
- parseSlackUserId
27
- } from "./chunk-N7TMSOZH.js";
28
- import {
29
- isRecord,
30
- logInfo,
31
- logWarn
32
- } from "./chunk-WS7NAFTM.js";
33
-
34
- // src/chat/agent/types.ts
35
- var RetryableDeliveryError = class extends Error {
36
- constructor(cause) {
37
- super("Assistant delivery was transient or ambiguous", { cause });
38
- this.name = "RetryableDeliveryError";
39
- }
40
- };
41
- function isAgentRunFeatureDisabled(disabledFeatures, feature) {
42
- return disabledFeatures?.includes(feature) ?? false;
43
- }
44
- function actorFromRun(run) {
45
- if (run.dispatch?.actor) {
46
- return run.dispatch.actor;
47
- }
48
- if (run.actor) {
49
- return run.actor;
50
- }
51
- if (run.credentialContext && !("type" in run.credentialContext.actor)) {
52
- return run.credentialContext.actor;
53
- }
54
- return void 0;
55
- }
56
- function assertRunConsistency(run) {
57
- const { destination, source } = run;
58
- switch (source.kind) {
59
- case "slack": {
60
- if (destination.platform !== "slack") {
61
- throw new TypeError(
62
- "Run source and destination platforms do not match"
63
- );
64
- }
65
- if (source.teamId !== destination.teamId) {
66
- throw new TypeError("Slack source and destination teams do not match");
67
- }
68
- break;
69
- }
70
- case "local": {
71
- if (destination.platform !== "local") {
72
- throw new TypeError(
73
- "Run source and destination platforms do not match"
74
- );
75
- }
76
- if (source.conversationId !== destination.conversationId) {
77
- throw new TypeError(
78
- "Source and destination conversation IDs do not match"
79
- );
80
- }
81
- if (run.surface !== "internal" && destination.conversationId !== run.conversationId) {
82
- throw new TypeError(
83
- "Source, destination, and run conversation IDs do not match"
84
- );
85
- }
86
- break;
87
- }
88
- case "web": {
89
- if (run.surface !== "internal" && source.conversationId !== run.conversationId) {
90
- throw new TypeError("Web source and run conversation IDs do not match");
91
- }
92
- switch (destination.platform) {
93
- case "local": {
94
- if (source.conversationId !== destination.conversationId) {
95
- throw new TypeError(
96
- "Source and destination conversation IDs do not match"
97
- );
98
- }
99
- if (run.surface !== "internal" && destination.conversationId !== run.conversationId) {
100
- throw new TypeError(
101
- "Source, destination, and run conversation IDs do not match"
102
- );
103
- }
104
- break;
105
- }
106
- case "slack":
107
- break;
108
- }
109
- break;
110
- }
111
- case "resource_event":
112
- case "scheduled_task":
113
- case "event_task":
114
- case "plugin_dispatch":
115
- case "agent_invocation":
116
- return;
117
- }
118
- const actor = run.dispatch?.actor ?? run.actor;
119
- if (!actor || actor.platform === "system") {
120
- return;
121
- }
122
- if (actor.platform !== source.kind) {
123
- throw new TypeError(
124
- `Actor platform "${actor.platform}" does not match Source kind "${source.kind}"`
125
- );
126
- }
127
- if (actor.platform === "slack" && source.kind === "slack" && actor.teamId !== source.teamId) {
128
- throw new TypeError("Slack Actor team does not match Source team");
129
- }
130
- }
131
- function toolInvocationDestination(run) {
132
- if (run.destination.platform !== "slack" || !run.toolChannelId) {
133
- return run.destination;
134
- }
135
- return {
136
- platform: "slack",
137
- teamId: run.destination.teamId,
138
- channelId: run.toolChannelId
139
- };
140
- }
141
- function surfaceFromRun(run) {
142
- if (run.surface) {
143
- return run.surface;
144
- }
145
- if (run.source.kind === "slack") {
146
- return "slack";
147
- }
148
- if (run.source.kind === "web") {
149
- return "api";
150
- }
151
- return "internal";
152
- }
153
-
154
- // src/chat/runtime/agent-runner.ts
155
- var AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
156
- function createAgentRunner(execute, options) {
157
- const attachmentStorage = options?.attachmentStorage;
158
- const streamFn = options?.streamFn;
159
- const tracePropagation = options?.tracePropagation;
160
- const bindSpawnAgent = options?.bindSpawnAgent;
161
- const canBindSpawn = Boolean(bindSpawnAgent) && isExperimentalFeatureEnabled("subagents");
162
- return {
163
- run: async (run) => {
164
- const spawnAgent = bindSpawnAgent && canBindSpawn && !isAgentRunFeatureDisabled(run.disabledFeatures, "subagents") ? bindSpawnAgent(run) : void 0;
165
- const nextRun = {
166
- ...run,
167
- environment: {
168
- ...run.environment,
169
- attachmentStorage: run.environment?.attachmentStorage ?? attachmentStorage,
170
- sandboxTracePropagation: run.environment?.sandboxTracePropagation ?? tracePropagation
171
- },
172
- ...spawnAgent ? {
173
- durability: {
174
- ...run.durability,
175
- spawnAgent
176
- }
177
- } : void 0
178
- };
179
- return await execute(nextRun, streamFn);
180
- }
181
- };
182
- }
183
- async function waitForAgentSettlement(runPromise) {
184
- let timeoutId;
185
- const settleGrace = new Promise((resolve) => {
186
- timeoutId = setTimeout(resolve, AGENT_ABORT_SETTLE_GRACE_MS);
187
- timeoutId.unref?.();
188
- });
189
- await Promise.race([
190
- runPromise.then(
191
- () => void 0,
192
- () => void 0
193
- ),
194
- settleGrace
195
- ]);
196
- if (timeoutId) {
197
- clearTimeout(timeoutId);
198
- }
199
- }
200
- async function runAgentWithTimeout(agentRunner, run, timeoutMs) {
201
- if (typeof timeoutMs !== "number") {
202
- return await agentRunner.run(run);
203
- }
204
- const timeoutError = new Error(
205
- `executeAgentRun timed out after ${timeoutMs}ms`
206
- );
207
- const abortController = new AbortController();
208
- const signal = run.signal ? AbortSignal.any([run.signal, abortController.signal]) : abortController.signal;
209
- const runPromise = agentRunner.run({ ...run, signal });
210
- let timeoutId;
211
- const timeoutPromise = new Promise((_, reject) => {
212
- timeoutId = setTimeout(() => {
213
- abortController.abort(timeoutError);
214
- reject(timeoutError);
215
- }, timeoutMs);
216
- });
217
- try {
218
- return await Promise.race([runPromise, timeoutPromise]);
219
- } catch (error) {
220
- if (abortController.signal.aborted) {
221
- await waitForAgentSettlement(runPromise);
222
- }
223
- throw error;
224
- } finally {
225
- if (timeoutId) {
226
- clearTimeout(timeoutId);
227
- }
228
- }
229
- }
230
-
231
- // src/chat/slack/outbound.ts
232
- var MAX_SLACK_MESSAGE_TEXT_CHARS = 4e4;
233
- function requireSlackConversationId(channelId, action) {
234
- const normalized = normalizeSlackConversationId(channelId);
235
- if (!normalized) {
236
- throw new Error(`${action} requires a valid channel ID`);
237
- }
238
- return normalized;
239
- }
240
- function requireSlackThreadTimestamp(threadTs, action) {
241
- const normalized = threadTs.trim();
242
- if (!normalized) {
243
- throw new Error(`${action} requires a thread timestamp`);
244
- }
245
- return normalized;
246
- }
247
- function requireSlackMessageTimestamp(timestamp, action) {
248
- const normalized = parseSlackMessageTs(timestamp);
249
- if (!normalized) {
250
- throw new Error(`${action} requires a target message timestamp`);
251
- }
252
- return normalized;
253
- }
254
- function requireSlackMessageText(text, action) {
255
- if (text.trim().length === 0) {
256
- throw new Error(`${action} requires non-empty text`);
257
- }
258
- if (text.length > MAX_SLACK_MESSAGE_TEXT_CHARS) {
259
- throw new Error(
260
- `${action} text exceeds Slack's 40000 character truncation limit`
261
- );
262
- }
263
- return text;
264
- }
265
- async function getSlackMessagePermalink(args) {
266
- try {
267
- const response = await withSlackRetries(
268
- () => getSlackClient().chat.getPermalink({
269
- channel: args.channelId,
270
- message_ts: args.messageTs
271
- }),
272
- 3,
273
- {
274
- action: "chat.getPermalink",
275
- idempotent: true,
276
- spanAttributes: {
277
- "app.slack.channel_id": args.channelId,
278
- "app.slack.message_ts": args.messageTs
279
- }
280
- }
281
- );
282
- return response.permalink;
283
- } catch {
284
- return void 0;
285
- }
286
- }
287
- async function postSlackMessage(input) {
288
- const channelId = requireSlackConversationId(
289
- input.channelId,
290
- "Slack message posting"
291
- );
292
- const text = requireSlackMessageText(input.text, "Slack message posting");
293
- const threadTs = input.threadTs ? requireSlackThreadTimestamp(
294
- input.threadTs,
295
- "Slack thread message posting"
296
- ) : void 0;
297
- const response = await withSlackRetries(
298
- () => getSlackClient().chat.postMessage({
299
- channel: channelId,
300
- text,
301
- unfurl_links: false,
302
- unfurl_media: false,
303
- ...input.blocks?.length ? {
304
- // @ts-expect-error non-overlapping boundary cast; rule forbids as-unknown-as chains
305
- blocks: input.blocks
306
- } : void 0,
307
- ...threadTs ? { thread_ts: threadTs } : void 0
308
- }),
309
- 3,
310
- {
311
- action: "chat.postMessage",
312
- spanAttributes: {
313
- "app.slack.channel_id": channelId,
314
- ...threadTs ? { "app.slack.thread_ts": threadTs } : void 0
315
- }
316
- }
317
- );
318
- const messageTs = parseSlackMessageTs(response.ts);
319
- if (!messageTs) {
320
- throw new Error("Slack message posted without ts");
321
- }
322
- return {
323
- ts: messageTs,
324
- ...input.includePermalink ? {
325
- permalink: await getSlackMessagePermalink({
326
- channelId,
327
- messageTs
328
- })
329
- } : void 0
330
- };
331
- }
332
- async function postSlackEphemeralMessage(input) {
333
- const channelId = requireSlackConversationId(
334
- input.channelId,
335
- "Slack ephemeral message posting"
336
- );
337
- const userId = parseSlackUserId(input.userId);
338
- if (!userId) {
339
- throw new Error("Slack ephemeral message posting requires a user ID");
340
- }
341
- const text = requireSlackMessageText(
342
- input.text,
343
- "Slack ephemeral message posting"
344
- );
345
- const threadTs = input.threadTs ? requireSlackThreadTimestamp(
346
- input.threadTs,
347
- "Slack ephemeral thread message posting"
348
- ) : void 0;
349
- const response = await withSlackRetries(
350
- () => getSlackClient().chat.postEphemeral({
351
- channel: channelId,
352
- user: userId,
353
- text,
354
- ...threadTs ? { thread_ts: threadTs } : void 0
355
- }),
356
- 3,
357
- {
358
- action: "chat.postEphemeral",
359
- spanAttributes: {
360
- "app.slack.channel_id": channelId,
361
- "app.slack.user_id": userId,
362
- ...threadTs ? { "app.slack.thread_ts": threadTs } : void 0
363
- }
364
- }
365
- );
366
- return {
367
- messageTs: response.message_ts
368
- };
369
- }
370
- async function uploadFilesToConversation(input) {
371
- const channelId = requireSlackConversationId(
372
- input.channelId,
373
- "Slack file upload"
374
- );
375
- const threadTs = input.threadTs ? requireSlackThreadTimestamp(input.threadTs, "Slack file upload") : void 0;
376
- if (input.files.length === 0) {
377
- throw new Error("Slack file upload requires at least one file");
378
- }
379
- const fileUploads = input.files.map((file) => {
380
- const filename = file.filename.trim();
381
- if (!filename) {
382
- throw new Error(
383
- "Slack file upload requires every file to have a filename"
384
- );
385
- }
386
- return {
387
- file: file.data,
388
- filename
389
- };
390
- });
391
- const response = await withSlackRetries(
392
- () => getSlackClient().filesUploadV2({
393
- channel_id: channelId,
394
- ...threadTs ? { thread_ts: threadTs } : void 0,
395
- file_uploads: fileUploads
396
- }),
397
- 3,
398
- {
399
- action: "filesUploadV2",
400
- spanAttributes: {
401
- "app.slack.channel_id": channelId,
402
- ...threadTs ? { "app.slack.thread_ts": threadTs } : void 0
403
- }
404
- }
405
- );
406
- return {
407
- files: (response.files ?? []).flatMap(
408
- (completion) => (completion.files ?? []).map((file) => file.id ? { id: file.id } : {})
409
- )
410
- };
411
- }
412
- async function addReactionToMessage(input) {
413
- const channelId = requireSlackConversationId(
414
- input.channelId,
415
- "Slack reaction"
416
- );
417
- const timestamp = requireSlackMessageTimestamp(
418
- input.timestamp,
419
- "Slack reaction"
420
- );
421
- const emoji = normalizeSlackEmojiName(input.emoji);
422
- if (!emoji) {
423
- throw new Error("Slack reaction requires a valid emoji alias name");
424
- }
425
- try {
426
- await withSlackRetries(
427
- () => getSlackClient().reactions.add({
428
- channel: channelId,
429
- timestamp,
430
- name: emoji
431
- }),
432
- 3,
433
- {
434
- action: "reactions.add",
435
- idempotent: true,
436
- spanAttributes: {
437
- "app.slack.channel_id": channelId,
438
- "app.slack.message_ts": timestamp,
439
- "app.slack.reaction": emoji
440
- }
441
- }
442
- );
443
- } catch (error) {
444
- if (error instanceof SlackActionError && error.code === "already_reacted") {
445
- return { ok: true };
446
- }
447
- throw error;
448
- }
449
- return { ok: true };
450
- }
451
- async function removeReactionFromMessage(input) {
452
- const channelId = requireSlackConversationId(
453
- input.channelId,
454
- "Slack reaction removal"
455
- );
456
- const timestamp = requireSlackMessageTimestamp(
457
- input.timestamp,
458
- "Slack reaction removal"
459
- );
460
- const emoji = normalizeSlackEmojiName(input.emoji);
461
- if (!emoji) {
462
- throw new Error("Slack reaction removal requires a valid emoji alias name");
463
- }
464
- try {
465
- await withSlackRetries(
466
- () => getSlackClient().reactions.remove({
467
- channel: channelId,
468
- timestamp,
469
- name: emoji
470
- }),
471
- 3,
472
- {
473
- action: "reactions.remove",
474
- idempotent: true,
475
- spanAttributes: {
476
- "app.slack.channel_id": channelId,
477
- "app.slack.message_ts": timestamp,
478
- "app.slack.reaction": emoji
479
- }
480
- }
481
- );
482
- } catch (error) {
483
- if (error instanceof SlackActionError && error.code === "no_reaction") {
484
- return { ok: true };
485
- }
486
- throw error;
487
- }
488
- return { ok: true };
489
- }
490
-
491
- // src/chat/oauth-flow.ts
492
- import { randomBytes } from "crypto";
493
- import {
494
- actorSchema,
495
- sourceSchema
496
- } from "@sentry/junior-plugin-api";
497
-
498
- // src/chat/slack/status-format.ts
499
- var SLACK_STATUS_MAX_LENGTH = 50;
500
- function truncateStatusText(text) {
501
- const trimmed = text.trim();
502
- if (!trimmed) {
503
- return "";
504
- }
505
- if (trimmed.length <= SLACK_STATUS_MAX_LENGTH) {
506
- return trimmed;
507
- }
508
- return `${trimmed.slice(0, SLACK_STATUS_MAX_LENGTH - 3).trimEnd()}...`;
509
- }
510
-
511
- // src/chat/slack/mrkdwn.ts
512
- function escapeSlackMrkdwnText(text) {
513
- return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
514
- }
515
- function escapeSlackLinkUrl(url) {
516
- return url.replaceAll("&", "&amp;").replaceAll("<", "%3C").replaceAll(">", "%3E");
517
- }
518
- function formatSlackLink(url, label) {
519
- return `<${escapeSlackLinkUrl(url)}|${escapeSlackMrkdwnText(label)}>`;
520
- }
521
- function readInlineCodeSpan(line, start) {
522
- if (line[start] !== "`") {
523
- return void 0;
524
- }
525
- let n = 1;
526
- while (line[start + n] === "`") {
527
- n++;
528
- }
529
- const marker = "`".repeat(n);
530
- let search = start + n;
531
- while (search < line.length) {
532
- const close = line.indexOf(marker, search);
533
- if (close === -1) {
534
- return void 0;
535
- }
536
- const after = close + n;
537
- if (line[after] !== "`") {
538
- return { text: line.slice(start, after), end: after };
539
- }
540
- search = after + 1;
541
- }
542
- return void 0;
543
- }
544
- function readExistingSlackAngleToken(line, start) {
545
- if (line[start] !== "<") {
546
- return void 0;
547
- }
548
- const close = line.indexOf(">", start + 1);
549
- if (close === -1) {
550
- return void 0;
551
- }
552
- const body = line.slice(start + 1, close);
553
- if (/^(?:https?:\/\/|@|#|!)/.test(body)) {
554
- return { text: line.slice(start, close + 1), end: close + 1 };
555
- }
556
- return void 0;
557
- }
558
- function readMarkdownLink(line, start) {
559
- if (line[start] !== "[") {
560
- return void 0;
561
- }
562
- const labelEnd = line.indexOf("](", start + 1);
563
- if (labelEnd === -1) {
564
- return void 0;
565
- }
566
- const destStart = labelEnd + 2;
567
- if (!line.startsWith("http://", destStart) && !line.startsWith("https://", destStart)) {
568
- return void 0;
569
- }
570
- const closeParens = line.indexOf(")", destStart);
571
- if (closeParens === -1) {
572
- return void 0;
573
- }
574
- return { text: line.slice(start, closeParens + 1), end: closeParens + 1 };
575
- }
576
- function hasUnmatchedClosingParen(text) {
577
- let balance = 0;
578
- for (const ch of text) {
579
- if (ch === "(") balance++;
580
- else if (ch === ")") balance--;
581
- }
582
- return balance < 0;
583
- }
584
- function readBareUrl(line, start) {
585
- let end = start;
586
- while (end < line.length) {
587
- const ch = line[end];
588
- if (/\s/.test(ch) || ch === "<" || ch === ">" || ch === '"' || ch === "`" || ch === "|" || ch === "*") {
589
- break;
590
- }
591
- end++;
592
- }
593
- if (end === start) {
594
- return void 0;
595
- }
596
- let raw = line.slice(start, end);
597
- let suffix = "";
598
- const peel = () => {
599
- suffix = raw.slice(-1) + suffix;
600
- raw = raw.slice(0, -1);
601
- };
602
- const shouldPeel = () => raw.endsWith("_") || /[.,!?;:]$/.test(raw) || raw.endsWith(")") && hasUnmatchedClosingParen(raw);
603
- while (raw.length > 0 && shouldPeel()) {
604
- peel();
605
- }
606
- if (!/^https?:\/\/.+/.test(raw)) {
607
- return void 0;
608
- }
609
- return { url: raw, suffix, end };
610
- }
611
- function wrapBareUrlsOnLine(line) {
612
- let result = "";
613
- let i = 0;
614
- while (i < line.length) {
615
- const codeSpan = readInlineCodeSpan(line, i);
616
- if (codeSpan) {
617
- result += codeSpan.text;
618
- i = codeSpan.end;
619
- continue;
620
- }
621
- const angleToken = readExistingSlackAngleToken(line, i);
622
- if (angleToken) {
623
- result += angleToken.text;
624
- i = angleToken.end;
625
- continue;
626
- }
627
- const mdLink = readMarkdownLink(line, i);
628
- if (mdLink) {
629
- result += mdLink.text;
630
- i = mdLink.end;
631
- continue;
632
- }
633
- if (line.startsWith("https://", i) || line.startsWith("http://", i)) {
634
- const parsed = readBareUrl(line, i);
635
- if (parsed) {
636
- result += `<${parsed.url}>${parsed.suffix}`;
637
- i = parsed.end;
638
- continue;
639
- }
640
- }
641
- result += line[i];
642
- i++;
643
- }
644
- return result;
645
- }
646
- function wrapBareUrls(text) {
647
- const lines = text.split("\n");
648
- const out = [];
649
- let inCodeBlock = false;
650
- for (const line of lines) {
651
- if (line.trimStart().startsWith("```")) {
652
- inCodeBlock = !inCodeBlock;
653
- out.push(line);
654
- continue;
655
- }
656
- out.push(inCodeBlock ? line : wrapBareUrlsOnLine(line));
657
- }
658
- return out.join("\n");
659
- }
660
- function ensureBlockSpacing(text) {
661
- const codeBlockPattern = /^```/;
662
- const listItemPattern = /^[-*•]\s|^\d+\.\s/;
663
- const lines = text.split("\n");
664
- const result = [];
665
- let inCodeBlock = false;
666
- for (let i = 0; i < lines.length; i++) {
667
- const line = lines[i];
668
- const isCodeFence = codeBlockPattern.test(line.trimStart());
669
- if (isCodeFence) {
670
- if (!inCodeBlock) {
671
- const prev2 = result.length > 0 ? result[result.length - 1] : void 0;
672
- if (prev2 !== void 0 && prev2.trim() !== "") {
673
- result.push("");
674
- }
675
- }
676
- inCodeBlock = !inCodeBlock;
677
- result.push(line);
678
- continue;
679
- }
680
- if (inCodeBlock) {
681
- result.push(line);
682
- continue;
683
- }
684
- const prev = result.length > 0 ? result[result.length - 1] : void 0;
685
- if (prev !== void 0 && prev.trim() !== "" && line.trim() !== "" && !(listItemPattern.test(prev.trimStart()) && listItemPattern.test(line.trimStart()))) {
686
- result.push("");
687
- }
688
- result.push(line);
689
- }
690
- return result.join("\n");
691
- }
692
- function normalizeSlackReplyMarkdown(text) {
693
- let normalized = applyPluginFormatMarkdown(text).replace(/\r\n?/g, "\n").replace(/[ \t]+$/gm, "");
694
- normalized = wrapBareUrls(normalized);
695
- normalized = ensureBlockSpacing(normalized);
696
- return normalized.replace(/\n{3,}/g, "\n\n").trim();
697
- }
698
- function normalizeSlackStatusText(text) {
699
- const trimmed = text.trim();
700
- if (!trimmed) {
701
- return "";
702
- }
703
- return truncateStatusText(trimmed.replace(/(?:\.\s*)+$/, "").trim());
704
- }
705
-
706
- // src/chat/slack/oauth-authorization-message.ts
707
- function formatOAuthAuthorizationMessage(args) {
708
- return `${formatSlackLink(args.authorizationUrl, args.label)}. ${args.completionText}`;
709
- }
710
-
711
- // src/chat/oauth-flow.ts
712
- var OAUTH_STATE_TTL_MS = 10 * 60 * 1e3;
713
- function optionalString(value) {
714
- return typeof value === "string" ? value : void 0;
715
- }
716
- function parseOAuthStatePayload(value) {
717
- if (!isRecord(value)) {
718
- return void 0;
719
- }
720
- if (typeof value.userId !== "string" || typeof value.provider !== "string") {
721
- return void 0;
722
- }
723
- const actor = value.actor === void 0 ? void 0 : actorSchema.safeParse(value.actor);
724
- if (value.actor !== void 0 && (!actor || !actor.success)) {
725
- return void 0;
726
- }
727
- const destination = parseDestination(value.destination);
728
- if (value.destination !== void 0 && !destination) {
729
- return void 0;
730
- }
731
- const source = value.source === void 0 ? void 0 : sourceSchema.safeParse(value.source);
732
- if (value.source !== void 0 && (!source || !source.success)) {
733
- return void 0;
734
- }
735
- return {
736
- userId: value.userId,
737
- provider: value.provider,
738
- ...actor?.success ? { actor: actor.data } : void 0,
739
- ...optionalString(value.channelId) ? { channelId: optionalString(value.channelId) } : void 0,
740
- ...destination ? { destination } : void 0,
741
- ...source?.success ? { source: source.data } : void 0,
742
- ...optionalString(value.threadTs) ? { threadTs: optionalString(value.threadTs) } : void 0,
743
- ...optionalString(value.resumeConversationId) ? { resumeConversationId: optionalString(value.resumeConversationId) } : void 0,
744
- ...optionalString(value.resumeSessionId) ? { resumeSessionId: optionalString(value.resumeSessionId) } : void 0,
745
- ...optionalString(value.scope) ? { scope: optionalString(value.scope) } : void 0
746
- };
747
- }
748
- function formatProviderLabel(provider) {
749
- const displayName = pluginCatalogRuntime.getDisplayName(provider);
750
- if (!displayName) {
751
- throw new Error(`Unknown plugin provider display name: "${provider}"`);
752
- }
753
- return displayName;
754
- }
755
- function resolveBaseUrl() {
756
- const explicit = process.env.JUNIOR_BASE_URL?.trim();
757
- if (explicit) return explicit;
758
- const vercelProd = process.env.VERCEL_PROJECT_PRODUCTION_URL?.trim();
759
- if (vercelProd) return `https://${vercelProd}`;
760
- const vercelUrl = process.env.VERCEL_URL?.trim();
761
- if (vercelUrl) return `https://${vercelUrl}`;
762
- return void 0;
763
- }
764
- async function deliverPrivateMessage(input) {
765
- let client;
766
- try {
767
- client = getSlackClient();
768
- } catch {
769
- logWarn("oauth.private_delivery.skipped", {
770
- "app.reason": "missing_bot_token"
771
- });
772
- return false;
773
- }
774
- if (input.channelId) {
775
- try {
776
- if (isDmChannel(input.channelId)) {
777
- await postSlackMessage({
778
- channelId: input.channelId,
779
- text: input.text,
780
- threadTs: input.threadTs
781
- });
782
- } else {
783
- await postSlackEphemeralMessage({
784
- channelId: input.channelId,
785
- userId: input.userId,
786
- text: input.text,
787
- threadTs: input.threadTs
788
- });
789
- }
790
- return "in_context";
791
- } catch (error) {
792
- logWarn("oauth.private_delivery.failed", {
793
- "app.slack.error": error instanceof Error ? error.message : String(error),
794
- "app.slack.channel": input.channelId
795
- });
796
- }
797
- }
798
- try {
799
- const dmChannelId = (await withSlackRetries(
800
- () => client.conversations.open({ users: input.userId }),
801
- 3,
802
- {
803
- action: "conversations.open",
804
- spanAttributes: { "app.slack.user_id": input.userId }
805
- }
806
- )).channel?.id;
807
- if (!dmChannelId) {
808
- logWarn("oauth.dm.fallback.failed", { "app.reason": "no_dm_channel_id" });
809
- return false;
810
- }
811
- await postSlackMessage({ channelId: dmChannelId, text: input.text });
812
- return "fallback_dm";
813
- } catch (error) {
814
- logWarn("oauth.dm.fallback.failed", {
815
- "app.slack.error": error instanceof Error ? error.message : String(error)
816
- });
817
- return false;
818
- }
819
- }
820
- async function deliverOAuthAuthorization(request, input) {
821
- if (input.authorization) {
822
- await input.authorization.deliver(request);
823
- return "in_context";
824
- }
825
- return await deliverPrivateMessage({
826
- channelId: input.channelId,
827
- threadTs: input.threadTs,
828
- userId: input.userId,
829
- text: formatOAuthAuthorizationMessage(request)
830
- });
831
- }
832
- async function startOAuthFlow(provider, input) {
833
- const providerConfig = pluginCatalogRuntime.getOAuthConfig(provider);
834
- if (!providerConfig) {
835
- return {
836
- ok: false,
837
- error: `Provider "${provider}" does not support OAuth authorization`
838
- };
839
- }
840
- const clientId = process.env[providerConfig.clientIdEnv]?.trim();
841
- if (!clientId) {
842
- return {
843
- ok: false,
844
- error: `Missing ${providerConfig.clientIdEnv} environment variable`
845
- };
846
- }
847
- const baseUrl = resolveBaseUrl();
848
- if (!baseUrl) {
849
- return {
850
- ok: false,
851
- error: "Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)"
852
- };
853
- }
854
- const state = input.authorization ? await input.authorization.createState() : randomBytes(32).toString("hex");
855
- const requestedScope = input.scope ?? providerConfig.scope;
856
- await getStateAdapter().set(
857
- `oauth-state:${state}`,
858
- {
859
- userId: input.actorId,
860
- provider,
861
- ...input.actor ? { actor: input.actor } : void 0,
862
- ...input.channelId ? { channelId: input.channelId } : void 0,
863
- ...input.destination ? { destination: input.destination } : void 0,
864
- ...input.source ? { source: input.source } : void 0,
865
- ...input.threadTs ? { threadTs: input.threadTs } : void 0,
866
- ...input.resumeConversationId ? { resumeConversationId: input.resumeConversationId } : void 0,
867
- ...input.resumeSessionId ? { resumeSessionId: input.resumeSessionId } : void 0,
868
- ...requestedScope ? { scope: requestedScope } : void 0
869
- },
870
- OAUTH_STATE_TTL_MS
871
- );
872
- const authorizeParams = new URLSearchParams({
873
- client_id: clientId,
874
- state,
875
- redirect_uri: `${baseUrl}${providerConfig.callbackPath}`,
876
- response_type: "code"
877
- });
878
- if (requestedScope) {
879
- authorizeParams.set("scope", requestedScope);
880
- }
881
- for (const [key, value] of Object.entries(
882
- providerConfig.authorizeParams ?? {}
883
- )) {
884
- authorizeParams.set(key, value);
885
- }
886
- logInfo("jr_rpc.oauth.started", {
887
- "app.credential.provider": provider,
888
- ...input.activeSkillName ? { "app.skill.name": input.activeSkillName } : void 0
889
- });
890
- const authorizationUrl = `${providerConfig.authorizeEndpoint}?${authorizeParams.toString()}`;
891
- const authorizationRequest = {
892
- authorizationUrl,
893
- label: `Click here to link your ${formatProviderLabel(provider)} account`,
894
- completionText: input.resumeSessionId ? "Once you've authorized, Junior will continue automatically." : "Once you've authorized, you'll see a confirmation in Slack."
895
- };
896
- return {
897
- ok: true,
898
- delivery: await deliverOAuthAuthorization(authorizationRequest, {
899
- authorization: input.authorization,
900
- channelId: input.channelId,
901
- threadTs: input.threadTs,
902
- userId: input.actorId
903
- })
904
- };
905
- }
906
-
907
- export {
908
- RetryableDeliveryError,
909
- isAgentRunFeatureDisabled,
910
- actorFromRun,
911
- assertRunConsistency,
912
- toolInvocationDestination,
913
- surfaceFromRun,
914
- getSlackMessagePermalink,
915
- postSlackMessage,
916
- uploadFilesToConversation,
917
- addReactionToMessage,
918
- removeReactionFromMessage,
919
- truncateStatusText,
920
- escapeSlackMrkdwnText,
921
- formatSlackLink,
922
- normalizeSlackReplyMarkdown,
923
- normalizeSlackStatusText,
924
- parseOAuthStatePayload,
925
- formatProviderLabel,
926
- resolveBaseUrl,
927
- deliverOAuthAuthorization,
928
- startOAuthFlow,
929
- createAgentRunner,
930
- runAgentWithTimeout
931
- };