@sentry/junior 0.118.0 → 0.120.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 (56) hide show
  1. package/dist/{agent-hooks-J2FB7XD6.js → agent-hooks-5DDPWRYO.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 +103 -82
  7. package/dist/app.js +24 -24
  8. package/dist/build/copy-build-content.d.ts +2 -2
  9. package/dist/{catalog-runtime-UHHLU53I.js → catalog-runtime-5KR5XBMJ.js} +7 -7
  10. package/dist/chat/discovery.d.ts +2 -0
  11. package/dist/chat/mcp/tool-manager.d.ts +14 -1
  12. package/dist/chat/plugins/types.d.ts +3 -9
  13. package/dist/chat/plugins/user-pages.d.ts +2 -1
  14. package/dist/chat/slack/tools/canvas/api.d.ts +2 -9
  15. package/dist/chat/slack/tools/canvas/markdown.d.ts +9 -0
  16. package/dist/{chunk-GT2ZUALJ.js → chunk-24B5R6OU.js} +92 -6
  17. package/dist/{chunk-L72GDKSN.js → chunk-6WX5SPI3.js} +1 -1
  18. package/dist/{chunk-3N3FMCKN.js → chunk-ALAKN7LR.js} +1 -1
  19. package/dist/{chunk-MLZFK4KP.js → chunk-ALYQOZG7.js} +1 -1
  20. package/dist/{chunk-6BGUAOYP.js → chunk-BHXW734F.js} +13 -7
  21. package/dist/{chunk-4LPPH7Y6.js → chunk-DJDGDJDF.js} +4 -4
  22. package/dist/{chunk-HWUBBHLK.js → chunk-DMKHRBI6.js} +4 -3
  23. package/dist/{chunk-QWCF4RAC.js → chunk-DWOH57FW.js} +1 -1
  24. package/dist/{chunk-7GADTCNS.js → chunk-EIVE6GL4.js} +3 -3
  25. package/dist/{chunk-6K2QE2UI.js → chunk-ERYVNWNE.js} +250 -37
  26. package/dist/{chunk-UXLYAVYL.js → chunk-GNNV3UTY.js} +1 -1
  27. package/dist/chunk-H4HBKISO.js +417 -0
  28. package/dist/{chunk-FXOYURO4.js → chunk-HDFGNU5E.js} +1 -0
  29. package/dist/{chunk-PJPKHGLG.js → chunk-JQWP6V22.js} +4 -11
  30. package/dist/{chunk-KC5EE27Y.js → chunk-M243JMZH.js} +2 -2
  31. package/dist/{chunk-7SM3P4XR.js → chunk-O2ULQJWR.js} +82 -1
  32. package/dist/{chunk-B3IT5END.js → chunk-OOUNJNMR.js} +16 -152
  33. package/dist/{chunk-HN6LFYG3.js → chunk-Q3RL6A4E.js} +2 -2
  34. package/dist/{chunk-3MUSSFMP.js → chunk-QOQPPRFS.js} +221 -14
  35. package/dist/{chunk-S6R23MFB.js → chunk-TKUCRFNX.js} +12 -225
  36. package/dist/{chunk-PWRFTDTY.js → chunk-VURFJVFH.js} +2 -2
  37. package/dist/{chunk-3LGCVRBQ.js → chunk-XAI2HNAY.js} +9 -5
  38. package/dist/{chunk-4SOQPUF4.js → chunk-YEAOUT5W.js} +1 -1
  39. package/dist/cli/chat.js +24 -24
  40. package/dist/cli/check.js +8 -8
  41. package/dist/cli/init.js +2 -2
  42. package/dist/cli/plugins.js +13 -13
  43. package/dist/cli/snapshot-create.js +11 -11
  44. package/dist/cli/upgrade.js +8 -8
  45. package/dist/{db-PMRHFSYL.js → db-T4ZY64PB.js} +6 -6
  46. package/dist/{discovery-RMHYSRL7.js → discovery-GUFTFBTL.js} +3 -1
  47. package/dist/instrumentation.js +3 -3
  48. package/dist/nitro.js +24 -7
  49. package/dist/{oauth-callback-server-QJUC7S4X.js → oauth-callback-server-LQ6DFI26.js} +17 -17
  50. package/dist/{runner-PZMV6JQW.js → runner-D3ZU6TJH.js} +10 -10
  51. package/dist/{skills-W4JETYSV.js → skills-JMXY7LIY.js} +8 -8
  52. package/dist/{validation-IJLNHZSU.js → validation-OEPJS7JX.js} +8 -8
  53. package/dist/version.js +1 -1
  54. package/package.json +8 -7
  55. package/skills/jr-rpc/SKILL.md +40 -0
  56. package/dist/chunk-3V7OFJZC.js +0 -264
@@ -1,149 +1,15 @@
1
1
  import {
2
2
  discoverNodeModulesDirs,
3
3
  isDirectory,
4
- isFile
5
- } from "./chunk-3V7OFJZC.js";
6
-
7
- // src/package-resolution.ts
8
- import { statSync } from "fs";
9
- import { createRequire } from "module";
10
- import path from "path";
11
- function isDirectory2(targetPath) {
12
- try {
13
- return statSync(targetPath).isDirectory();
14
- } catch {
15
- return false;
16
- }
17
- }
18
- function isFile2(targetPath) {
19
- try {
20
- return statSync(targetPath).isFile();
21
- } catch {
22
- return false;
23
- }
24
- }
25
- function uniqueResolvedPathsInOrder(values) {
26
- const seen = /* @__PURE__ */ new Set();
27
- const resolved = [];
28
- for (const value of values) {
29
- const normalized = path.resolve(value);
30
- if (seen.has(normalized)) {
31
- continue;
32
- }
33
- seen.add(normalized);
34
- resolved.push(normalized);
35
- }
36
- return resolved;
37
- }
38
- function ancestorNodeModulesDirs(cwd) {
39
- const dirs = [];
40
- let current = path.resolve(cwd);
41
- while (true) {
42
- const nodeModulesDir = path.join(current, "node_modules");
43
- if (isDirectory2(nodeModulesDir)) {
44
- dirs.push(nodeModulesDir);
45
- }
46
- const parent = path.dirname(current);
47
- if (parent === current) {
48
- break;
49
- }
50
- current = parent;
51
- }
52
- return dirs;
53
- }
54
- function packageDirInNodeModules(nodeModulesDir, packageName) {
55
- const packageDir = path.join(nodeModulesDir, ...packageName.split("/"));
56
- return isDirectory2(packageDir) ? path.resolve(packageDir) : void 0;
57
- }
58
- function isValidPackageSegment(segment) {
59
- return Boolean(segment) && segment !== "." && segment !== ".." && !segment.startsWith(".") && /^[A-Za-z0-9._~-]+$/.test(segment);
60
- }
61
- function isValidPackageName(packageName) {
62
- if (!packageName || packageName.includes("\\") || path.isAbsolute(packageName)) {
63
- return false;
64
- }
65
- const parts = packageName.split("/");
66
- if (parts[0].startsWith("@")) {
67
- return parts.length === 2 && parts[0].length > 1 && isValidPackageSegment(parts[0].slice(1)) && isValidPackageSegment(parts[1]);
68
- }
69
- return parts.length === 1 && isValidPackageSegment(parts[0]);
70
- }
71
- function findPackageRoot(entryPath) {
72
- let dir = path.dirname(entryPath);
73
- while (dir !== path.dirname(dir)) {
74
- if (isFile2(path.join(dir, "package.json"))) {
75
- return path.resolve(dir);
76
- }
77
- dir = path.dirname(dir);
78
- }
79
- return void 0;
80
- }
81
- function findPackageNodeModulesDir(packageDir, packageName) {
82
- const parts = path.resolve(packageDir).split(path.sep);
83
- const packageParts = packageName.split("/");
84
- for (let index = parts.length - 1; index >= 0; index -= 1) {
85
- if (parts[index] !== "node_modules") {
86
- continue;
87
- }
88
- const candidatePackageParts = parts.slice(
89
- index + 1,
90
- index + 1 + packageParts.length
91
- );
92
- if (candidatePackageParts.join("/") !== packageParts.join("/")) {
93
- continue;
94
- }
95
- return path.resolve(parts.slice(0, index + 1).join(path.sep) || path.sep);
96
- }
97
- return void 0;
98
- }
99
- function resolvePackageWithNode(cwd, packageName) {
100
- let requireFromCwd;
101
- try {
102
- requireFromCwd = createRequire(path.join(cwd, "package.json"));
103
- } catch {
104
- return void 0;
105
- }
106
- for (const specifier of [`${packageName}/package.json`, packageName]) {
107
- try {
108
- const resolved = requireFromCwd.resolve(specifier);
109
- const dir = specifier.endsWith("/package.json") ? path.dirname(resolved) : findPackageRoot(resolved);
110
- if (!dir) {
111
- continue;
112
- }
113
- const nodeModulesDir = findPackageNodeModulesDir(dir, packageName);
114
- return {
115
- dir,
116
- ...nodeModulesDir ? { nodeModulesDir } : {}
117
- };
118
- } catch {
119
- }
120
- }
121
- return void 0;
122
- }
123
- function resolvePackageLocation(cwd, packageName, options) {
124
- if (!isValidPackageName(packageName)) {
125
- return void 0;
126
- }
127
- const nodeModulesDirs = uniqueResolvedPathsInOrder([
128
- ...options?.nodeModulesDirs ?? [],
129
- ...ancestorNodeModulesDirs(cwd)
130
- ]);
131
- for (const nodeModulesDir of nodeModulesDirs) {
132
- const dir = packageDirInNodeModules(nodeModulesDir, packageName);
133
- if (dir) {
134
- return { dir, nodeModulesDir };
135
- }
136
- }
137
- return resolvePackageWithNode(cwd, packageName);
138
- }
139
- function resolvePackageDir(cwd, packageName) {
140
- return resolvePackageLocation(cwd, packageName)?.dir;
141
- }
4
+ isFile,
5
+ isValidPackageName,
6
+ resolvePackageLocation
7
+ } from "./chunk-H4HBKISO.js";
142
8
 
143
9
  // src/chat/plugins/package-discovery.ts
144
- import path2 from "path";
10
+ import path from "path";
145
11
  function normalizeForGlob(targetPath) {
146
- return targetPath.split(path2.sep).join("/");
12
+ return targetPath.split(path.sep).join("/");
147
13
  }
148
14
  function uniqueStringsInOrder(values) {
149
15
  const seen = /* @__PURE__ */ new Set();
@@ -158,8 +24,8 @@ function uniqueStringsInOrder(values) {
158
24
  return resolved;
159
25
  }
160
26
  function pathForTracingInclude(cwd, targetPath) {
161
- const relative = path2.relative(cwd, targetPath);
162
- if (!relative || path2.isAbsolute(relative) || relative === ".." || relative.startsWith(`..${path2.sep}`)) {
27
+ const relative = path.relative(cwd, targetPath);
28
+ if (!relative || path.isAbsolute(relative) || relative === ".." || relative.startsWith(`..${path.sep}`)) {
163
29
  return null;
164
30
  }
165
31
  const normalized = normalizeForGlob(relative);
@@ -196,10 +62,10 @@ function resolvePackageDirFromName(cwd, packageName, candidateNodeModulesDirs) {
196
62
  }) ?? null;
197
63
  }
198
64
  function readPluginPackageFlags(dir) {
199
- const hasRootPluginManifest = isFile(path2.join(dir, "plugin.yaml"));
200
- const hasMigrationsDir = isDirectory(path2.join(dir, "migrations"));
201
- const hasPluginsDir = isDirectory(path2.join(dir, "plugins"));
202
- const hasSkillsDir = isDirectory(path2.join(dir, "skills"));
65
+ const hasRootPluginManifest = isFile(path.join(dir, "plugin.yaml"));
66
+ const hasMigrationsDir = isDirectory(path.join(dir, "migrations"));
67
+ const hasPluginsDir = isDirectory(path.join(dir, "plugins"));
68
+ const hasSkillsDir = isDirectory(path.join(dir, "skills"));
203
69
  if (!hasRootPluginManifest && !hasMigrationsDir && !hasPluginsDir && !hasSkillsDir) {
204
70
  return null;
205
71
  }
@@ -244,7 +110,7 @@ function discoverDeclaredPackages(packageNames, candidateNodeModulesDirs, cwd) {
244
110
  return discovered;
245
111
  }
246
112
  function discoverInstalledPluginPackageContent(cwd = process.cwd(), options) {
247
- const resolvedCwd = path2.resolve(cwd);
113
+ const resolvedCwd = path.resolve(cwd);
248
114
  const packageNames = normalizePluginPackageNames(options?.packageNames);
249
115
  const nodeModulesDirs = options?.nodeModulesDirs ?? discoverNodeModulesDirs(resolvedCwd);
250
116
  const discoveredPackages = discoverDeclaredPackages(
@@ -258,7 +124,7 @@ function discoverInstalledPluginPackageContent(cwd = process.cwd(), options) {
258
124
  for (const pkg of discoveredPackages) {
259
125
  const tracingBasePath = pkg.nodeModulesDir ? pathForTracingInclude(
260
126
  resolvedCwd,
261
- path2.join(pkg.nodeModulesDir, ...pkg.packageName.split("/"))
127
+ path.join(pkg.nodeModulesDir, ...pkg.packageName.split("/"))
262
128
  ) : pathForTracingInclude(resolvedCwd, pkg.dir);
263
129
  if (pkg.hasRootPluginManifest) {
264
130
  manifestRoots.push(pkg.dir);
@@ -272,13 +138,13 @@ function discoverInstalledPluginPackageContent(cwd = process.cwd(), options) {
272
138
  }
273
139
  }
274
140
  if (pkg.hasPluginsDir) {
275
- manifestRoots.push(path2.join(pkg.dir, "plugins"));
141
+ manifestRoots.push(path.join(pkg.dir, "plugins"));
276
142
  if (tracingBasePath) {
277
143
  tracingIncludes.push(`${tracingBasePath}/plugins/**/*`);
278
144
  }
279
145
  }
280
146
  if (pkg.hasSkillsDir) {
281
- skillRoots.push(path2.join(pkg.dir, "skills"));
147
+ skillRoots.push(path.join(pkg.dir, "skills"));
282
148
  if (tracingBasePath) {
283
149
  tracingIncludes.push(`${tracingBasePath}/skills/**/*`);
284
150
  }
@@ -301,8 +167,6 @@ function discoverInstalledPluginPackageContent(cwd = process.cwd(), options) {
301
167
  }
302
168
 
303
169
  export {
304
- isValidPackageName,
305
- resolvePackageDir,
306
170
  normalizePluginPackageNames,
307
171
  discoverInstalledPluginPackageContent
308
172
  };
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-PE44LDDQ.js";
4
4
  import {
5
5
  normalizeSlackConversationId
6
- } from "./chunk-GT2ZUALJ.js";
6
+ } from "./chunk-24B5R6OU.js";
7
7
  import {
8
8
  parseSlackThreadId
9
- } from "./chunk-FXOYURO4.js";
9
+ } from "./chunk-HDFGNU5E.js";
10
10
 
11
11
  // src/handlers/health.ts
12
12
  function readHealthReport() {
@@ -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-BHXW734F.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-TKUCRFNX.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-JQWP6V22.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-24B5R6OU.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-M243JMZH.js";
89
90
  import {
90
91
  acquireActiveLock,
91
92
  getDefaultRedisStateAdapterFor,
92
93
  getStateAdapter
93
- } from "./chunk-3N3FMCKN.js";
94
+ } from "./chunk-ALAKN7LR.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-VURFJVFH.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-EIVE6GL4.js";
112
113
  import {
113
114
  pluginCatalogRuntime
114
- } from "./chunk-UXLYAVYL.js";
115
+ } from "./chunk-GNNV3UTY.js";
115
116
  import {
116
117
  buildOAuthTokenRequest,
117
118
  hasRequiredOAuthScope,
118
119
  parseOAuthTokenResponse
119
- } from "./chunk-3LGCVRBQ.js";
120
+ } from "./chunk-XAI2HNAY.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-ALYQOZG7.js";
131
132
  import {
132
133
  isRecord,
133
134
  toOptionalNumber,
@@ -138,7 +139,7 @@ import {
138
139
  } from "./chunk-F3B2YJ76.js";
139
140
  import {
140
141
  homeDir
141
- } from "./chunk-3V7OFJZC.js";
142
+ } from "./chunk-H4HBKISO.js";
142
143
 
143
144
  // src/chat/slack/assistant-thread/status-render.ts
144
145
  var DEFAULT_STATUS_CONTEXTS = {
@@ -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,