@sentry/junior 0.118.0 → 0.119.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 (46) hide show
  1. package/dist/{agent-hooks-J2FB7XD6.js → agent-hooks-NZSV4QQR.js} +8 -8
  2. package/dist/api/conversations/detail.d.ts +17 -0
  3. package/dist/api/conversations/event-list.d.ts +17 -0
  4. package/dist/api/schema/conversation.d.ts +68 -0
  5. package/dist/api/schema.js +1 -1
  6. package/dist/api.js +58 -16
  7. package/dist/app.js +22 -22
  8. package/dist/{catalog-runtime-UHHLU53I.js → catalog-runtime-TAOYIZIZ.js} +5 -5
  9. package/dist/chat/slack/tools/canvas/api.d.ts +2 -9
  10. package/dist/chat/slack/tools/canvas/markdown.d.ts +9 -0
  11. package/dist/{chunk-S6R23MFB.js → chunk-4UIUDOOV.js} +12 -225
  12. package/dist/{chunk-HN6LFYG3.js → chunk-6ZR455DC.js} +2 -2
  13. package/dist/{chunk-GT2ZUALJ.js → chunk-BLQZACHV.js} +4 -4
  14. package/dist/{chunk-PJPKHGLG.js → chunk-BNJEPYTC.js} +4 -11
  15. package/dist/{chunk-KC5EE27Y.js → chunk-D3N4BPSL.js} +2 -2
  16. package/dist/{chunk-4LPPH7Y6.js → chunk-GKFDU3ZI.js} +4 -4
  17. package/dist/{chunk-FXOYURO4.js → chunk-HDFGNU5E.js} +1 -0
  18. package/dist/{chunk-HWUBBHLK.js → chunk-JLJLZS2N.js} +1 -1
  19. package/dist/{chunk-UXLYAVYL.js → chunk-JSTGI7TX.js} +1 -1
  20. package/dist/{chunk-L72GDKSN.js → chunk-JXRAOOXQ.js} +1 -1
  21. package/dist/{chunk-QWCF4RAC.js → chunk-NUENIPQL.js} +1 -1
  22. package/dist/{chunk-7SM3P4XR.js → chunk-O2ULQJWR.js} +82 -1
  23. package/dist/{chunk-7GADTCNS.js → chunk-QZ7XRJDB.js} +2 -2
  24. package/dist/{chunk-3LGCVRBQ.js → chunk-R53UT2OI.js} +1 -1
  25. package/dist/{chunk-4SOQPUF4.js → chunk-TAGV4Z3J.js} +1 -1
  26. package/dist/{chunk-6K2QE2UI.js → chunk-TGIQN7QW.js} +169 -31
  27. package/dist/{chunk-3N3FMCKN.js → chunk-VJTWKJWQ.js} +1 -1
  28. package/dist/{chunk-PWRFTDTY.js → chunk-VLTWQQKH.js} +2 -2
  29. package/dist/{chunk-3MUSSFMP.js → chunk-YLYJIQRX.js} +220 -13
  30. package/dist/{chunk-6BGUAOYP.js → chunk-ZFX4M743.js} +13 -7
  31. package/dist/{chunk-MLZFK4KP.js → chunk-ZJ6IVZVO.js} +1 -1
  32. package/dist/cli/chat.js +22 -22
  33. package/dist/cli/check.js +6 -6
  34. package/dist/cli/init.js +2 -2
  35. package/dist/cli/plugins.js +11 -11
  36. package/dist/cli/snapshot-create.js +9 -9
  37. package/dist/cli/upgrade.js +6 -6
  38. package/dist/{db-PMRHFSYL.js → db-FWGP5CKY.js} +6 -6
  39. package/dist/instrumentation.js +3 -3
  40. package/dist/nitro.js +2 -2
  41. package/dist/{oauth-callback-server-QJUC7S4X.js → oauth-callback-server-PM3QNXJQ.js} +15 -15
  42. package/dist/{runner-PZMV6JQW.js → runner-DV55N6ZB.js} +10 -10
  43. package/dist/{skills-W4JETYSV.js → skills-MANV5ZK6.js} +6 -6
  44. package/dist/{validation-IJLNHZSU.js → validation-QGB4INTI.js} +6 -6
  45. package/dist/version.js +1 -1
  46. package/package.json +5 -5
@@ -25,13 +25,12 @@ import {
25
25
  patchMcpAuthSession,
26
26
  resolveBaseUrl,
27
27
  selectPluginGrant,
28
- slackOutputPolicy,
29
28
  startOAuthFlow,
30
29
  surfaceFromRouting,
31
30
  toMcpProviderError,
32
31
  toolInvocationDestination,
33
32
  uploadFilesToConversation
34
- } from "./chunk-S6R23MFB.js";
33
+ } from "./chunk-4UIUDOOV.js";
35
34
  import {
36
35
  CooperativeTurnYieldError,
37
36
  JUNIOR_THREAD_STATE_TTL_MS,
@@ -73,7 +72,7 @@ import {
73
72
  stripRuntimeTurnContext,
74
73
  trimTrailingAssistantMessages,
75
74
  updateConversationStats
76
- } from "./chunk-PJPKHGLG.js";
75
+ } from "./chunk-BNJEPYTC.js";
77
76
  import {
78
77
  parseSandboxEgressAuthRequiredSignal,
79
78
  parseSandboxEgressPermissionDeniedSignal,
@@ -97,10 +96,10 @@ import {
97
96
  runNonInteractiveCommand,
98
97
  throwSandboxOperationError,
99
98
  wrapSandboxSetupError
100
- } from "./chunk-4LPPH7Y6.js";
99
+ } from "./chunk-GKFDU3ZI.js";
101
100
  import {
102
101
  incrementStat
103
- } from "./chunk-L72GDKSN.js";
102
+ } from "./chunk-JXRAOOXQ.js";
104
103
  import {
105
104
  addAgentTurnUsage,
106
105
  hasAgentTurnUsage
@@ -122,7 +121,7 @@ import {
122
121
  normalizeSlackConversationId,
123
122
  resolveChannelCapabilities,
124
123
  withSlackRetries
125
- } from "./chunk-GT2ZUALJ.js";
124
+ } from "./chunk-BLQZACHV.js";
126
125
  import {
127
126
  KNOWN_CONVERSATION_EVENT_TYPES,
128
127
  contextProvenance,
@@ -131,7 +130,7 @@ import {
131
130
  getConversationStore,
132
131
  instructionActors,
133
132
  instructionProvenanceFor
134
- } from "./chunk-KC5EE27Y.js";
133
+ } from "./chunk-D3N4BPSL.js";
135
134
  import {
136
135
  SANDBOX_DATA_ROOT,
137
136
  SANDBOX_SKILLS_ROOT,
@@ -141,7 +140,7 @@ import {
141
140
  sandboxSkillFile,
142
141
  sandboxSkillPathResolution,
143
142
  sleep
144
- } from "./chunk-3N3FMCKN.js";
143
+ } from "./chunk-VJTWKJWQ.js";
145
144
  import {
146
145
  ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
147
146
  COMPACTION_SUMMARY_PREFIX,
@@ -172,7 +171,7 @@ import {
172
171
  renderCurrentInstruction,
173
172
  resolveGatewayModel,
174
173
  unwrapCurrentInstruction
175
- } from "./chunk-PWRFTDTY.js";
174
+ } from "./chunk-VLTWQQKH.js";
176
175
  import {
177
176
  canExposeConversationPayload,
178
177
  parseSlackThreadId,
@@ -183,16 +182,16 @@ import {
183
182
  toGenAiMessagesTraceAttributes,
184
183
  toGenAiPayloadMetadata,
185
184
  toGenAiPayloadTraceAttributes
186
- } from "./chunk-FXOYURO4.js";
185
+ } from "./chunk-HDFGNU5E.js";
187
186
  import {
188
187
  discoverSkills,
189
188
  findSkillByName,
190
189
  loadSkillsByName,
191
190
  parseSkillInvocation
192
- } from "./chunk-7GADTCNS.js";
191
+ } from "./chunk-QZ7XRJDB.js";
193
192
  import {
194
193
  pluginCatalogRuntime
195
- } from "./chunk-UXLYAVYL.js";
194
+ } from "./chunk-JSTGI7TX.js";
196
195
  import {
197
196
  CredentialUnavailableError,
198
197
  OAuthProviderError,
@@ -200,7 +199,7 @@ import {
200
199
  getOAuthProviderErrorAttributes,
201
200
  resolveAuthTokenPlaceholder,
202
201
  resolvePluginCommandEnv
203
- } from "./chunk-3LGCVRBQ.js";
202
+ } from "./chunk-R53UT2OI.js";
204
203
  import {
205
204
  credentialUserSubjectId
206
205
  } from "./chunk-W3U3YQYI.js";
@@ -224,7 +223,7 @@ import {
224
223
  summarizeMessageText,
225
224
  withLogContext,
226
225
  withSpan
227
- } from "./chunk-MLZFK4KP.js";
226
+ } from "./chunk-ZJ6IVZVO.js";
228
227
  import {
229
228
  parseSlackChannelId,
230
229
  parseSlackMessageTs,
@@ -1861,13 +1860,11 @@ function buildOutputSection(platform) {
1861
1860
  "</output>"
1862
1861
  ].join("\n");
1863
1862
  }
1864
- const openTag = `<output format="slack-markdown" max_inline_chars="${slackOutputPolicy.maxInlineChars}" max_inline_lines="${slackOutputPolicy.maxInlineLines}">`;
1865
1863
  return [
1866
- openTag,
1864
+ `<output format="slack-markdown">`,
1865
+ "- Default to the shortest complete reply\u2014usually 1\u20135 sentences and under 800 characters. Include only the outcome, decisive evidence, and any blocker or required next action. If useful detail would exceed that, put it in a Slack canvas and reply with the link. An explicit user request for detail overrides this target.",
1867
1866
  "- Start with the answer or result, not internal process narration.",
1868
1867
  "- Use Slack-flavored Markdown: **bold** section labels, `code`, [text](url) links, bullet lists, and fenced code blocks. No hash-prefixed headings and no tables. When the answer primarily lists several URLs, show each URL bare instead of as a labeled link.",
1869
- "- Default to one compact thread reply containing the conclusion and only decisive evidence or action. Do not split an explainer across multiple Slack messages.",
1870
- "- Put plans, research, and other long or multi-section explainers in a Slack canvas; reply with one or two short sentences plus the link, without recapping the canvas.",
1871
1868
  "- End every turn with a final user-facing markdown response unless the Slack action rules allow a no-reply completion.",
1872
1869
  "</output>"
1873
1870
  ].join("\n");
@@ -8647,20 +8644,156 @@ function extractCanvasId(input) {
8647
8644
  }
8648
8645
  }
8649
8646
 
8650
- // src/chat/slack/tools/canvas/api.ts
8647
+ // src/chat/slack/tools/canvas/markdown.ts
8648
+ function getListType(marker) {
8649
+ return /^\d/.test(marker) ? "numbered" : "bullet";
8650
+ }
8651
+ function getPlainListMarker(marker, type) {
8652
+ return type === "numbered" ? `${marker.match(/^\d+/)?.[0] ?? "1"}:` : "\u2022";
8653
+ }
8654
+ function getIndentWidth(whitespace, startColumn = 0) {
8655
+ let column = startColumn;
8656
+ for (const character of whitespace) {
8657
+ column += character === " " ? 4 - column % 4 : 1;
8658
+ }
8659
+ return column - startColumn;
8660
+ }
8661
+ function getLineIndent(line) {
8662
+ return getIndentWidth(line.match(/^[ \t]*/)?.[0] ?? "");
8663
+ }
8664
+ function getFence(line) {
8665
+ const match = line.match(/^([ \t]*)(`{3,}|~{3,})(.*)$/);
8666
+ const run = match?.[2];
8667
+ if (!run) return void 0;
8668
+ return {
8669
+ fence: {
8670
+ marker: run[0],
8671
+ length: run.length
8672
+ },
8673
+ indent: getIndentWidth(match[1] ?? ""),
8674
+ suffix: match[3] ?? ""
8675
+ };
8676
+ }
8677
+ function isListBlockIndent(indent, listItems2) {
8678
+ return listItems2.some(
8679
+ (item) => indent >= item.contentIndent && indent <= item.contentIndent + 3
8680
+ );
8681
+ }
8682
+ function canOpenFence(fenceLine, listItems2) {
8683
+ return fenceLine.indent <= 3 || isListBlockIndent(fenceLine.indent, listItems2);
8684
+ }
8685
+ function unwrapNestedBlockquote(line, listItems2, maxQuoteDepth = Number.POSITIVE_INFINITY) {
8686
+ const match = line.match(/^([ \t]+)((?:>[ \t]*)+)(.*)$/);
8687
+ if (!match || !isListBlockIndent(getIndentWidth(match[1] ?? ""), listItems2)) {
8688
+ return { line, quoteDepth: 0 };
8689
+ }
8690
+ let quotePrefix = match[2] ?? "";
8691
+ const quoteDepth = Math.min(
8692
+ quotePrefix.match(/>/g)?.length ?? 0,
8693
+ maxQuoteDepth
8694
+ );
8695
+ for (let index = 0; index < quoteDepth; index += 1) {
8696
+ quotePrefix = quotePrefix.replace(/^>[ \t]*/, "");
8697
+ }
8698
+ return {
8699
+ line: `${match[1]}${quotePrefix}${match[3]}`,
8700
+ quoteDepth
8701
+ };
8702
+ }
8651
8703
  function normalizeCanvasMarkdown(markdown) {
8652
8704
  let normalizedHeadingCount = 0;
8653
- const normalized = markdown.split("\n").map(
8654
- (line) => line.replace(/^(#{4,})(?=\s)/, () => {
8705
+ let normalizedMixedListCount = 0;
8706
+ let unwrappedBlockquoteCount = 0;
8707
+ let openFence;
8708
+ const listItems2 = [];
8709
+ const lines = markdown.split("\n").map((originalLine) => {
8710
+ if (openFence) {
8711
+ const unwrapped2 = openFence.quoteDepth > 0 ? unwrapNestedBlockquote(
8712
+ originalLine,
8713
+ listItems2,
8714
+ openFence.quoteDepth
8715
+ ) : { line: originalLine, quoteDepth: 0 };
8716
+ if (unwrapped2.quoteDepth > 0) {
8717
+ unwrappedBlockquoteCount += 1;
8718
+ }
8719
+ const fenceLine2 = getFence(unwrapped2.line);
8720
+ if (fenceLine2?.fence.marker === openFence.marker && fenceLine2.fence.length >= openFence.length && !fenceLine2.suffix.trim()) {
8721
+ openFence = void 0;
8722
+ }
8723
+ return unwrapped2.line;
8724
+ }
8725
+ const unwrapped = unwrapNestedBlockquote(originalLine, listItems2);
8726
+ if (unwrapped.quoteDepth > 0) {
8727
+ unwrappedBlockquoteCount += 1;
8728
+ }
8729
+ const line = unwrapped.line;
8730
+ const fenceLine = getFence(line);
8731
+ if (fenceLine && canOpenFence(fenceLine, listItems2)) {
8732
+ const rootListContentIndent2 = listItems2[0]?.contentIndent;
8733
+ if (rootListContentIndent2 !== void 0 && fenceLine.indent < rootListContentIndent2) {
8734
+ listItems2.length = 0;
8735
+ }
8736
+ openFence = {
8737
+ ...fenceLine.fence,
8738
+ quoteDepth: unwrapped.quoteDepth
8739
+ };
8740
+ return line;
8741
+ }
8742
+ const listMatch = line.match(/^([ \t]*)([-+*]|\d+[.)])([ \t]+)(.*)$/);
8743
+ if (listMatch) {
8744
+ const [, whitespace = "", marker = "", gap = "", rawContent = ""] = listMatch;
8745
+ const indent = getIndentWidth(whitespace);
8746
+ const type = getListType(marker);
8747
+ const markerEnd = indent + getIndentWidth(marker);
8748
+ const contentIndent = markerEnd + getIndentWidth(gap, markerEnd);
8749
+ const contentMatch = rawContent.match(/^(?:>[ \t]*)+(.*)$/);
8750
+ const content = contentMatch?.[1] ?? rawContent;
8751
+ if (contentMatch) {
8752
+ unwrappedBlockquoteCount += 1;
8753
+ }
8754
+ while (listItems2.length > 0 && listItems2[listItems2.length - 1].indent >= indent) {
8755
+ listItems2.pop();
8756
+ }
8757
+ const parent = listItems2[listItems2.length - 1];
8758
+ if (parent && (parent.unwrapped || parent.type !== type)) {
8759
+ listItems2.push({
8760
+ contentIndent,
8761
+ indent,
8762
+ type: parent.type,
8763
+ unwrapped: true
8764
+ });
8765
+ normalizedMixedListCount += 1;
8766
+ return `${whitespace}${getPlainListMarker(marker, type)}${gap}${content}`;
8767
+ }
8768
+ listItems2.push({ contentIndent, indent, type, unwrapped: false });
8769
+ return contentMatch ? `${whitespace}${marker}${gap}${content}` : line;
8770
+ }
8771
+ const rootListContentIndent = listItems2[0]?.contentIndent;
8772
+ if (rootListContentIndent !== void 0 && line.trim() && getLineIndent(line) < rootListContentIndent) {
8773
+ listItems2.length = 0;
8774
+ }
8775
+ const headingMatch = line.match(/^([ \t]*)#{4,}(?=[ \t])/);
8776
+ const headingIndent = headingMatch ? getIndentWidth(headingMatch[1] ?? "") : void 0;
8777
+ if (headingMatch && headingIndent !== void 0 && (headingIndent <= 3 || isListBlockIndent(headingIndent, listItems2))) {
8655
8778
  normalizedHeadingCount += 1;
8656
- return "###";
8657
- })
8658
- ).join("\n");
8779
+ return line.replace(
8780
+ /^([ \t]*)#{4,}(?=[ \t])/,
8781
+ (_, indent) => `${indent}###`
8782
+ );
8783
+ }
8784
+ return line;
8785
+ });
8786
+ const normalizedCount = normalizedHeadingCount + normalizedMixedListCount + unwrappedBlockquoteCount;
8659
8787
  return {
8660
- markdown: normalized,
8661
- normalizedHeadingCount
8788
+ markdown: lines.join("\n"),
8789
+ normalizedCount,
8790
+ normalizedHeadingCount,
8791
+ normalizedMixedListCount,
8792
+ unwrappedBlockquoteCount
8662
8793
  };
8663
8794
  }
8795
+
8796
+ // src/chat/slack/tools/canvas/api.ts
8664
8797
  async function createCanvas(input) {
8665
8798
  const client = getSlackClient();
8666
8799
  const normalizedChannelId = normalizeSlackConversationId(input.channelId);
@@ -8684,8 +8817,10 @@ async function createCanvas(input) {
8684
8817
  "app.slack.canvas.has_channel_id": Boolean(input.channelId),
8685
8818
  "app.slack.canvas.title_length": input.title.length,
8686
8819
  "app.slack.canvas.markdown_length": normalizedContent.markdown.length,
8687
- "app.slack.canvas.markdown_normalized": normalizedContent.normalizedHeadingCount > 0,
8688
- "app.slack.canvas.normalized_heading_count": normalizedContent.normalizedHeadingCount
8820
+ "app.slack.canvas.markdown_normalized": normalizedContent.normalizedCount > 0,
8821
+ "app.slack.canvas.normalized_heading_count": normalizedContent.normalizedHeadingCount,
8822
+ "app.slack.canvas.normalized_mixed_list_count": normalizedContent.normalizedMixedListCount,
8823
+ "app.slack.canvas.unwrapped_blockquote_count": normalizedContent.unwrappedBlockquoteCount
8689
8824
  }
8690
8825
  }
8691
8826
  );
@@ -8761,8 +8896,10 @@ async function writeCanvasMarkdown(input) {
8761
8896
  "app.slack.canvas.canvas_id_prefix": input.canvasId.slice(0, 1),
8762
8897
  "app.slack.canvas.operation": "replace",
8763
8898
  "app.slack.canvas.markdown_length": normalizedContent.markdown.length,
8764
- "app.slack.canvas.markdown_normalized": normalizedContent.normalizedHeadingCount > 0,
8765
- "app.slack.canvas.normalized_heading_count": normalizedContent.normalizedHeadingCount
8899
+ "app.slack.canvas.markdown_normalized": normalizedContent.normalizedCount > 0,
8900
+ "app.slack.canvas.normalized_heading_count": normalizedContent.normalizedHeadingCount,
8901
+ "app.slack.canvas.normalized_mixed_list_count": normalizedContent.normalizedMixedListCount,
8902
+ "app.slack.canvas.unwrapped_blockquote_count": normalizedContent.unwrappedBlockquoteCount
8766
8903
  }
8767
8904
  }
8768
8905
  );
@@ -14084,7 +14221,8 @@ async function summarizeContext(args, deps) {
14084
14221
  "- The immediate next action",
14085
14222
  "- Durable constraints, user preferences, IDs, URLs, artifacts, sandbox references, auth state, and unresolved blockers",
14086
14223
  "",
14087
- "Do not write a user-facing reply, announce a plan, or imply that the task is complete unless the source history proves it is complete."
14224
+ "Do not write a user-facing reply or announce a plan.",
14225
+ "Treat the task as complete only when the source history contains concrete evidence that every requested outcome occurred. Do not infer completion from intent, plans, progress, intermediate artifacts, or adjacent tool activity. If evidence is missing or ambiguous, preserve the task as unfinished and state the next required action."
14088
14226
  ] : [
14089
14227
  "You are performing a CONTEXT CHECKPOINT COMPACTION for Junior.",
14090
14228
  "Create a concise continuation summary for the agent that will continue this Slack thread.",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getChatConfig
3
- } from "./chunk-PWRFTDTY.js";
3
+ } from "./chunk-VLTWQQKH.js";
4
4
 
5
5
  // src/chat/state/adapter.ts
6
6
  import { createMemoryState } from "@chat-adapter/state-memory";
@@ -4,7 +4,7 @@ import {
4
4
  toCanonicalInputMessage,
5
5
  toCanonicalOutputMessage,
6
6
  toGenAiMessagesTraceAttributes
7
- } from "./chunk-FXOYURO4.js";
7
+ } from "./chunk-HDFGNU5E.js";
8
8
  import {
9
9
  extractGenAiUsageAttributes,
10
10
  logException,
@@ -12,7 +12,7 @@ import {
12
12
  normalizeGenAiFinishReason,
13
13
  serializeGenAiAttribute,
14
14
  withSpan
15
- } from "./chunk-MLZFK4KP.js";
15
+ } from "./chunk-ZJ6IVZVO.js";
16
16
 
17
17
  // src/chat/config.ts
18
18
  import { getModel as getModel2 } from "@earendil-works/pi-ai/compat";
@@ -5,6 +5,7 @@ import {
5
5
  ConversationTurnLifecycleService,
6
6
  buildDeliveredTurnStatePatch,
7
7
  finalizeFailedTurnReplyWithEvent,
8
+ getInterruptionMarker,
8
9
  getTurnUserMessage,
9
10
  getTurnUserMessageId,
10
11
  getTurnUserReplyAttachmentContext,
@@ -12,7 +13,7 @@ import {
12
13
  persistAuthPauseTurnState,
13
14
  requireTurnFailureEventId,
14
15
  scheduleSessionCompletedPluginTasks
15
- } from "./chunk-6BGUAOYP.js";
16
+ } from "./chunk-ZFX4M743.js";
16
17
  import {
17
18
  buildSentryConversationUrl
18
19
  } from "./chunk-4CODA7P5.js";
@@ -31,15 +32,15 @@ import {
31
32
  getMcpAuthSession,
32
33
  getMcpProviderErrorAttributes,
33
34
  getMcpStoredOAuthCredentials,
35
+ normalizeSlackReplyMarkdown,
34
36
  normalizeSlackStatusText,
35
37
  parseOAuthStatePayload,
36
38
  postSlackMessage,
37
39
  removeReactionFromMessage,
38
40
  resolveBaseUrl,
39
41
  resolvePluginOAuthAccount,
40
- splitSlackReplyText,
41
42
  truncateStatusText
42
- } from "./chunk-S6R23MFB.js";
43
+ } from "./chunk-4UIUDOOV.js";
43
44
  import {
44
45
  JUNIOR_THREAD_STATE_TTL_MS,
45
46
  TurnSliceLimitExceededError,
@@ -69,7 +70,7 @@ import {
69
70
  recordDeliveredAssistantMessage,
70
71
  turnHasReply,
71
72
  updateConversationStats
72
- } from "./chunk-PJPKHGLG.js";
73
+ } from "./chunk-BNJEPYTC.js";
73
74
  import {
74
75
  SlackActionError,
75
76
  getDashboardConversationLink,
@@ -78,19 +79,19 @@ import {
78
79
  getSlackClient,
79
80
  isDmChannel,
80
81
  normalizeSlackConversationId
81
- } from "./chunk-GT2ZUALJ.js";
82
+ } from "./chunk-BLQZACHV.js";
82
83
  import {
83
84
  getConversationEventStore,
84
85
  getConversationStore,
85
86
  parseDestination,
86
87
  requireSlackDestination,
87
88
  sameDestination
88
- } from "./chunk-KC5EE27Y.js";
89
+ } from "./chunk-D3N4BPSL.js";
89
90
  import {
90
91
  acquireActiveLock,
91
92
  getDefaultRedisStateAdapterFor,
92
93
  getStateAdapter
93
- } from "./chunk-3N3FMCKN.js";
94
+ } from "./chunk-VJTWKJWQ.js";
94
95
  import {
95
96
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
96
97
  botConfig,
@@ -99,24 +100,24 @@ import {
99
100
  getRuntimeMetadata,
100
101
  normalizeSlackEmojiName,
101
102
  standardModelId
102
- } from "./chunk-PWRFTDTY.js";
103
+ } from "./chunk-VLTWQQKH.js";
103
104
  import {
104
105
  parseSlackThreadId,
105
106
  readSlackRawMessageContext,
106
107
  resolveSlackChannelIdFromMessage,
107
108
  resolveSlackChannelIdFromThreadId
108
- } from "./chunk-FXOYURO4.js";
109
+ } from "./chunk-HDFGNU5E.js";
109
110
  import {
110
111
  discoverSkills
111
- } from "./chunk-7GADTCNS.js";
112
+ } from "./chunk-QZ7XRJDB.js";
112
113
  import {
113
114
  pluginCatalogRuntime
114
- } from "./chunk-UXLYAVYL.js";
115
+ } from "./chunk-JSTGI7TX.js";
115
116
  import {
116
117
  buildOAuthTokenRequest,
117
118
  hasRequiredOAuthScope,
118
119
  parseOAuthTokenResponse
119
- } from "./chunk-3LGCVRBQ.js";
120
+ } from "./chunk-R53UT2OI.js";
120
121
  import {
121
122
  createSlackResumeActor,
122
123
  isUserActor,
@@ -127,7 +128,7 @@ import {
127
128
  logException,
128
129
  logInfo,
129
130
  logWarn
130
- } from "./chunk-MLZFK4KP.js";
131
+ } from "./chunk-ZJ6IVZVO.js";
131
132
  import {
132
133
  isRecord,
133
134
  toOptionalNumber,
@@ -545,6 +546,210 @@ function buildSlackReplyBlocks(text, footer) {
545
546
  return blocks;
546
547
  }
547
548
 
549
+ // src/chat/slack/output.ts
550
+ var MAX_INLINE_CHARS = 2200;
551
+ var MAX_INLINE_LINES = 45;
552
+ var CONTINUED_MARKER = "\n\n[Continued below]";
553
+ function countSlackLines(text) {
554
+ if (!text) {
555
+ return 0;
556
+ }
557
+ return text.split("\n").length;
558
+ }
559
+ function fitsInlineBudget(text, maxChars = MAX_INLINE_CHARS, maxLines = MAX_INLINE_LINES) {
560
+ return text.length <= maxChars && countSlackLines(text) <= maxLines;
561
+ }
562
+ function findSplitIndex(text, maxChars) {
563
+ if (text.length <= maxChars) {
564
+ return text.length;
565
+ }
566
+ const bounded = text.slice(0, maxChars);
567
+ const newlineIndex = bounded.lastIndexOf("\n");
568
+ if (newlineIndex > 0) {
569
+ return newlineIndex;
570
+ }
571
+ const spaceIndex = bounded.lastIndexOf(" ");
572
+ if (spaceIndex > 0) {
573
+ return spaceIndex;
574
+ }
575
+ return maxChars;
576
+ }
577
+ function splitByLineBudget(text, maxLines) {
578
+ if (maxLines <= 0) {
579
+ return "";
580
+ }
581
+ const lines = text.split("\n");
582
+ if (lines.length <= maxLines) {
583
+ return text;
584
+ }
585
+ return lines.slice(0, maxLines).join("\n");
586
+ }
587
+ function reserveInlineBudgetForSuffix(suffix, maxChars = MAX_INLINE_CHARS, maxLines = MAX_INLINE_LINES) {
588
+ return {
589
+ maxChars: Math.max(1, maxChars - suffix.length),
590
+ maxLines: Math.max(1, maxLines - Math.max(0, countSlackLines(suffix) - 1))
591
+ };
592
+ }
593
+ function forceSplitBudget(text, budget) {
594
+ const lineCount = countSlackLines(text);
595
+ return {
596
+ maxChars: text.length <= budget.maxChars ? Math.max(1, text.length - 1) : budget.maxChars,
597
+ maxLines: lineCount <= budget.maxLines ? Math.max(1, lineCount - 1) : budget.maxLines
598
+ };
599
+ }
600
+ function getFenceContinuation(text) {
601
+ let open;
602
+ for (const line of text.split("\n")) {
603
+ const trimmed = line.trimStart();
604
+ const openerMatch = trimmed.match(/^(`{3,}|~{3,})(.*)$/);
605
+ if (!openerMatch) {
606
+ continue;
607
+ }
608
+ if (!open) {
609
+ open = {
610
+ fence: openerMatch[1],
611
+ openerLine: trimmed
612
+ };
613
+ continue;
614
+ }
615
+ if (new RegExp(`^${open.fence}\\s*$`).test(trimmed)) {
616
+ open = void 0;
617
+ }
618
+ }
619
+ if (!open) {
620
+ return null;
621
+ }
622
+ return {
623
+ closeSuffix: text.endsWith("\n") ? open.fence : `
624
+ ${open.fence}`,
625
+ reopenPrefix: `${open.openerLine}
626
+ `
627
+ };
628
+ }
629
+ function appendSlackSuffix(text, marker) {
630
+ const carryover = getFenceContinuation(text);
631
+ return `${text}${carryover?.closeSuffix ?? ""}${marker}`;
632
+ }
633
+ function stripTrailingContinuationMarker(text) {
634
+ return text.endsWith(CONTINUED_MARKER) ? text.slice(0, -CONTINUED_MARKER.length) : text;
635
+ }
636
+ function takeSlackContinuationChunk(text, budget) {
637
+ let { prefix, rest } = takeSlackInlinePrefix(text, budget);
638
+ if (!rest) {
639
+ ({ prefix, rest } = takeSlackInlinePrefix(
640
+ text,
641
+ forceSplitBudget(text, budget)
642
+ ));
643
+ }
644
+ let carryover = rest ? getFenceContinuation(prefix) : null;
645
+ if (!carryover) {
646
+ return { prefix, rest };
647
+ }
648
+ const carryoverBudget = reserveInlineBudgetForSuffix(
649
+ `${carryover.closeSuffix}${CONTINUED_MARKER}`
650
+ );
651
+ ({ prefix, rest } = takeSlackInlinePrefix(text, carryoverBudget));
652
+ if (!rest) {
653
+ ({ prefix, rest } = takeSlackInlinePrefix(
654
+ text,
655
+ forceSplitBudget(text, carryoverBudget)
656
+ ));
657
+ }
658
+ carryover = rest ? getFenceContinuation(prefix) : null;
659
+ if (!carryover) {
660
+ return { prefix, rest };
661
+ }
662
+ return {
663
+ prefix,
664
+ rest: `${carryover.reopenPrefix}${rest}`
665
+ };
666
+ }
667
+ function takeSlackContinuationPrefix(text, options) {
668
+ const budget = {
669
+ maxChars: options?.maxChars ?? getSlackContinuationBudget().maxChars,
670
+ maxLines: options?.maxLines ?? getSlackContinuationBudget().maxLines
671
+ };
672
+ const { prefix, rest } = (() => {
673
+ if (options?.forceSplit) {
674
+ return takeSlackContinuationChunk(text, budget);
675
+ }
676
+ const initial = takeSlackInlinePrefix(text, budget);
677
+ return initial.rest ? takeSlackContinuationChunk(text, budget) : initial;
678
+ })();
679
+ return {
680
+ prefix,
681
+ renderedPrefix: rest ? appendSlackSuffix(prefix, CONTINUED_MARKER) : prefix,
682
+ rest
683
+ };
684
+ }
685
+ function takeSlackInlinePrefix(text, options) {
686
+ const maxChars = options?.maxChars ?? MAX_INLINE_CHARS;
687
+ const maxLines = options?.maxLines ?? MAX_INLINE_LINES;
688
+ const normalized = text.replace(/\r\n?/g, "\n");
689
+ if (!normalized) {
690
+ return { prefix: "", rest: "" };
691
+ }
692
+ if (fitsInlineBudget(normalized, maxChars, maxLines)) {
693
+ return { prefix: normalized, rest: "" };
694
+ }
695
+ const lineBounded = splitByLineBudget(normalized, maxLines);
696
+ const cutIndex = findSplitIndex(lineBounded, maxChars);
697
+ const prefix = lineBounded.slice(0, cutIndex).trimEnd();
698
+ if (prefix) {
699
+ return {
700
+ prefix,
701
+ rest: normalized.slice(prefix.length).trimStart()
702
+ };
703
+ }
704
+ const hardPrefix = normalized.slice(0, Math.max(1, maxChars)).trimEnd();
705
+ return {
706
+ prefix: hardPrefix || normalized.slice(0, Math.max(1, maxChars)),
707
+ rest: normalized.slice(hardPrefix.length || Math.max(1, maxChars)).trimStart()
708
+ };
709
+ }
710
+ function splitSlackReplyText(text, options) {
711
+ const normalized = normalizeSlackReplyMarkdown(text);
712
+ if (!normalized) {
713
+ return [];
714
+ }
715
+ const chunks = [];
716
+ const continuationBudget = reserveInlineBudgetForSuffix(CONTINUED_MARKER);
717
+ let remaining = normalized;
718
+ while (remaining) {
719
+ const fitsFinalChunk = options?.interrupted ? fitsInlineBudget(appendSlackSuffix(remaining, getInterruptionMarker())) : fitsInlineBudget(remaining);
720
+ if (fitsFinalChunk) {
721
+ chunks.push(
722
+ options?.interrupted ? appendSlackSuffix(remaining, getInterruptionMarker()) : remaining
723
+ );
724
+ break;
725
+ }
726
+ const { renderedPrefix, rest } = takeSlackContinuationPrefix(remaining, {
727
+ ...continuationBudget,
728
+ forceSplit: true
729
+ });
730
+ chunks.push(renderedPrefix);
731
+ remaining = rest;
732
+ }
733
+ if (chunks.length === 2) {
734
+ chunks[0] = stripTrailingContinuationMarker(chunks[0] ?? "");
735
+ }
736
+ return chunks;
737
+ }
738
+ function getSlackContinuationBudget() {
739
+ return reserveInlineBudgetForSuffix(CONTINUED_MARKER);
740
+ }
741
+ function buildSlackOutputMessage(text) {
742
+ const normalized = normalizeSlackReplyMarkdown(text);
743
+ if (!normalized) {
744
+ throw new Error(
745
+ `Slack output normalized to empty content: original_length=${text.length} parsed_length=${normalized.length}`
746
+ );
747
+ }
748
+ return {
749
+ markdown: normalized
750
+ };
751
+ }
752
+
548
753
  // src/chat/slack/reply.ts
549
754
  async function sendSlackReply(args) {
550
755
  const chunks = splitSlackReplyText(args.text);
@@ -4328,6 +4533,8 @@ export {
4328
4533
  removeActiveConversation2 as removeActiveConversation,
4329
4534
  listActiveConversationIds2 as listActiveConversationIds,
4330
4535
  createSlackAdapterAssistantStatusSession,
4536
+ splitSlackReplyText,
4537
+ buildSlackOutputMessage,
4331
4538
  sendSlackReply,
4332
4539
  getSlackApiErrorCode,
4333
4540
  getSlackErrorObservabilityAttributes,