@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.
- package/dist/{agent-hooks-J2FB7XD6.js → agent-hooks-5DDPWRYO.js} +8 -8
- package/dist/api/conversations/detail.d.ts +17 -0
- package/dist/api/conversations/event-list.d.ts +17 -0
- package/dist/api/schema/conversation.d.ts +68 -0
- package/dist/api/schema.js +1 -1
- package/dist/api.js +103 -82
- package/dist/app.js +24 -24
- package/dist/build/copy-build-content.d.ts +2 -2
- package/dist/{catalog-runtime-UHHLU53I.js → catalog-runtime-5KR5XBMJ.js} +7 -7
- package/dist/chat/discovery.d.ts +2 -0
- package/dist/chat/mcp/tool-manager.d.ts +14 -1
- package/dist/chat/plugins/types.d.ts +3 -9
- package/dist/chat/plugins/user-pages.d.ts +2 -1
- package/dist/chat/slack/tools/canvas/api.d.ts +2 -9
- package/dist/chat/slack/tools/canvas/markdown.d.ts +9 -0
- package/dist/{chunk-GT2ZUALJ.js → chunk-24B5R6OU.js} +92 -6
- package/dist/{chunk-L72GDKSN.js → chunk-6WX5SPI3.js} +1 -1
- package/dist/{chunk-3N3FMCKN.js → chunk-ALAKN7LR.js} +1 -1
- package/dist/{chunk-MLZFK4KP.js → chunk-ALYQOZG7.js} +1 -1
- package/dist/{chunk-6BGUAOYP.js → chunk-BHXW734F.js} +13 -7
- package/dist/{chunk-4LPPH7Y6.js → chunk-DJDGDJDF.js} +4 -4
- package/dist/{chunk-HWUBBHLK.js → chunk-DMKHRBI6.js} +4 -3
- package/dist/{chunk-QWCF4RAC.js → chunk-DWOH57FW.js} +1 -1
- package/dist/{chunk-7GADTCNS.js → chunk-EIVE6GL4.js} +3 -3
- package/dist/{chunk-6K2QE2UI.js → chunk-ERYVNWNE.js} +250 -37
- package/dist/{chunk-UXLYAVYL.js → chunk-GNNV3UTY.js} +1 -1
- package/dist/chunk-H4HBKISO.js +417 -0
- package/dist/{chunk-FXOYURO4.js → chunk-HDFGNU5E.js} +1 -0
- package/dist/{chunk-PJPKHGLG.js → chunk-JQWP6V22.js} +4 -11
- package/dist/{chunk-KC5EE27Y.js → chunk-M243JMZH.js} +2 -2
- package/dist/{chunk-7SM3P4XR.js → chunk-O2ULQJWR.js} +82 -1
- package/dist/{chunk-B3IT5END.js → chunk-OOUNJNMR.js} +16 -152
- package/dist/{chunk-HN6LFYG3.js → chunk-Q3RL6A4E.js} +2 -2
- package/dist/{chunk-3MUSSFMP.js → chunk-QOQPPRFS.js} +221 -14
- package/dist/{chunk-S6R23MFB.js → chunk-TKUCRFNX.js} +12 -225
- package/dist/{chunk-PWRFTDTY.js → chunk-VURFJVFH.js} +2 -2
- package/dist/{chunk-3LGCVRBQ.js → chunk-XAI2HNAY.js} +9 -5
- package/dist/{chunk-4SOQPUF4.js → chunk-YEAOUT5W.js} +1 -1
- package/dist/cli/chat.js +24 -24
- package/dist/cli/check.js +8 -8
- package/dist/cli/init.js +2 -2
- package/dist/cli/plugins.js +13 -13
- package/dist/cli/snapshot-create.js +11 -11
- package/dist/cli/upgrade.js +8 -8
- package/dist/{db-PMRHFSYL.js → db-T4ZY64PB.js} +6 -6
- package/dist/{discovery-RMHYSRL7.js → discovery-GUFTFBTL.js} +3 -1
- package/dist/instrumentation.js +3 -3
- package/dist/nitro.js +24 -7
- package/dist/{oauth-callback-server-QJUC7S4X.js → oauth-callback-server-LQ6DFI26.js} +17 -17
- package/dist/{runner-PZMV6JQW.js → runner-D3ZU6TJH.js} +10 -10
- package/dist/{skills-W4JETYSV.js → skills-JMXY7LIY.js} +8 -8
- package/dist/{validation-IJLNHZSU.js → validation-OEPJS7JX.js} +8 -8
- package/dist/version.js +1 -1
- package/package.json +8 -7
- package/skills/jr-rpc/SKILL.md +40 -0
- package/dist/chunk-3V7OFJZC.js +0 -264
|
@@ -1,149 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
discoverNodeModulesDirs,
|
|
3
3
|
isDirectory,
|
|
4
|
-
isFile
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
10
|
+
import path from "path";
|
|
145
11
|
function normalizeForGlob(targetPath) {
|
|
146
|
-
return targetPath.split(
|
|
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 =
|
|
162
|
-
if (!relative ||
|
|
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(
|
|
200
|
-
const hasMigrationsDir = isDirectory(
|
|
201
|
-
const hasPluginsDir = isDirectory(
|
|
202
|
-
const hasSkillsDir = isDirectory(
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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-
|
|
6
|
+
} from "./chunk-24B5R6OU.js";
|
|
7
7
|
import {
|
|
8
8
|
parseSlackThreadId
|
|
9
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
89
|
+
} from "./chunk-M243JMZH.js";
|
|
89
90
|
import {
|
|
90
91
|
acquireActiveLock,
|
|
91
92
|
getDefaultRedisStateAdapterFor,
|
|
92
93
|
getStateAdapter
|
|
93
|
-
} from "./chunk-
|
|
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-
|
|
103
|
+
} from "./chunk-VURFJVFH.js";
|
|
103
104
|
import {
|
|
104
105
|
parseSlackThreadId,
|
|
105
106
|
readSlackRawMessageContext,
|
|
106
107
|
resolveSlackChannelIdFromMessage,
|
|
107
108
|
resolveSlackChannelIdFromThreadId
|
|
108
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-HDFGNU5E.js";
|
|
109
110
|
import {
|
|
110
111
|
discoverSkills
|
|
111
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-EIVE6GL4.js";
|
|
112
113
|
import {
|
|
113
114
|
pluginCatalogRuntime
|
|
114
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-GNNV3UTY.js";
|
|
115
116
|
import {
|
|
116
117
|
buildOAuthTokenRequest,
|
|
117
118
|
hasRequiredOAuthScope,
|
|
118
119
|
parseOAuthTokenResponse
|
|
119
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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,
|