@sentry/junior 0.68.0 → 0.69.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/app.js +1464 -732
- package/dist/build/virtual-config.d.ts +2 -2
- package/dist/chat/agent-dispatch/heartbeat.d.ts +2 -2
- package/dist/chat/agent-dispatch/store.d.ts +4 -1
- package/dist/chat/agent-dispatch/types.d.ts +2 -4
- package/dist/chat/agent-dispatch/validation.d.ts +3 -2
- package/dist/chat/credentials/context.d.ts +49 -24
- package/dist/chat/credentials/user-token-store.d.ts +6 -0
- package/dist/chat/destination.d.ts +12 -0
- package/dist/chat/ingress/message-router.d.ts +1 -1
- package/dist/chat/mcp/auth-store.d.ts +2 -0
- package/dist/chat/mcp/oauth.d.ts +2 -0
- package/dist/chat/oauth-flow.d.ts +7 -0
- package/dist/chat/plugins/agent-hooks.d.ts +9 -9
- package/dist/chat/plugins/auth/auth-token-placeholder.d.ts +2 -2
- package/dist/chat/plugins/auth/oauth-request.d.ts +3 -1
- package/dist/chat/plugins/credential-hooks.d.ts +34 -0
- package/dist/chat/plugins/logging.d.ts +1 -1
- package/dist/chat/plugins/state.d.ts +1 -1
- package/dist/chat/plugins/types.d.ts +19 -23
- package/dist/chat/respond.d.ts +2 -0
- package/dist/chat/runtime/reply-executor.d.ts +3 -1
- package/dist/chat/runtime/slack-runtime.d.ts +8 -3
- package/dist/chat/sandbox/egress-credentials.d.ts +33 -0
- package/dist/chat/sandbox/egress-schemas.d.ts +105 -0
- package/dist/chat/sandbox/egress-session.d.ts +17 -17
- package/dist/chat/sandbox/sandbox.d.ts +3 -0
- package/dist/chat/sandbox/session.d.ts +1 -0
- package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -0
- package/dist/chat/services/pending-auth.d.ts +2 -0
- package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -0
- package/dist/chat/services/provider-retry.d.ts +13 -4
- package/dist/chat/services/timeout-resume.d.ts +2 -0
- package/dist/chat/services/turn-session-record.d.ts +6 -0
- package/dist/chat/slack/attachment-fetchers.d.ts +11 -0
- package/dist/chat/state/conversation.d.ts +1 -0
- package/dist/chat/state/turn-session.d.ts +4 -0
- package/dist/chat/task-execution/queue.d.ts +2 -0
- package/dist/chat/task-execution/store.d.ts +5 -0
- package/dist/chat/task-execution/vercel-callback.d.ts +4 -0
- package/dist/chat/task-execution/vercel-queue.d.ts +2 -0
- package/dist/chat/task-execution/worker.d.ts +4 -2
- package/dist/chat/tools/slack/context.d.ts +3 -0
- package/dist/chat/tools/types.d.ts +21 -2
- package/dist/chunk-76YMBKW7.js +326 -0
- package/dist/{chunk-PIVOJIUD.js → chunk-B5HKWWQB.js} +9 -5
- package/dist/chunk-BBXYXOJW.js +1858 -0
- package/dist/{chunk-V47RLIO2.js → chunk-GT67ZWZQ.js} +4 -4
- package/dist/{chunk-75UZ4JLC.js → chunk-IGLNC5H6.js} +21 -9
- package/dist/{chunk-EBVQXCD2.js → chunk-JS4HURDT.js} +362 -280
- package/dist/{chunk-UQQSW7QB.js → chunk-N3MORKTH.js} +74 -331
- package/dist/chunk-R62YWUNO.js +264 -0
- package/dist/{chunk-OIIXZOOC.js → chunk-UXG6TU2U.js} +311 -2015
- package/dist/cli/check.js +4 -4
- package/dist/cli/snapshot-warmup.js +5 -4
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +21 -19
- package/dist/plugins.d.ts +2 -2
- package/dist/reporting.d.ts +2 -2
- package/dist/reporting.js +13 -11
- package/package.json +6 -4
- package/dist/chat/plugins/auth/github-app-broker.d.ts +0 -4
- package/dist/chat/plugins/github-permissions.d.ts +0 -11
- package/dist/chat/queue/thread-message-dispatcher.d.ts +0 -33
- package/dist/chunk-KVZL5NZS.js +0 -519
|
@@ -0,0 +1,1858 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sentry_exports
|
|
3
|
+
} from "./chunk-Z3YD6NHK.js";
|
|
4
|
+
|
|
5
|
+
// src/chat/discovery.ts
|
|
6
|
+
import fs, { statSync } from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
function isDirectory(targetPath) {
|
|
10
|
+
try {
|
|
11
|
+
return statSync(targetPath).isDirectory();
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function isFile(targetPath) {
|
|
17
|
+
try {
|
|
18
|
+
return statSync(targetPath).isFile();
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function normalizePath(targetPath) {
|
|
24
|
+
return path.resolve(targetPath);
|
|
25
|
+
}
|
|
26
|
+
function uniqueResolvedPathsInOrder(values) {
|
|
27
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28
|
+
const resolved = [];
|
|
29
|
+
for (const value of values) {
|
|
30
|
+
const normalized = normalizePath(value);
|
|
31
|
+
if (seen.has(normalized)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
seen.add(normalized);
|
|
35
|
+
resolved.push(normalized);
|
|
36
|
+
}
|
|
37
|
+
return resolved;
|
|
38
|
+
}
|
|
39
|
+
function isNodeModulesPath(candidatePath) {
|
|
40
|
+
return path.basename(candidatePath) === "node_modules";
|
|
41
|
+
}
|
|
42
|
+
function isInsidePnpmStore(candidatePath) {
|
|
43
|
+
return candidatePath.split(path.sep).includes(".pnpm");
|
|
44
|
+
}
|
|
45
|
+
function runningFromInstalledPackage() {
|
|
46
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
47
|
+
const marker = `${path.sep}node_modules${path.sep}@sentry${path.sep}junior${path.sep}`;
|
|
48
|
+
return currentFile.includes(marker);
|
|
49
|
+
}
|
|
50
|
+
function listInstalledPackageNodeModulesDirs() {
|
|
51
|
+
if (!runningFromInstalledPackage()) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
const dirs = [];
|
|
55
|
+
let current = path.resolve(path.dirname(fileURLToPath(import.meta.url)));
|
|
56
|
+
while (true) {
|
|
57
|
+
if (isNodeModulesPath(current) && !isInsidePnpmStore(current) && isDirectory(current)) {
|
|
58
|
+
dirs.push(current);
|
|
59
|
+
}
|
|
60
|
+
const parent = path.dirname(current);
|
|
61
|
+
if (parent === current) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
current = parent;
|
|
65
|
+
}
|
|
66
|
+
return dirs;
|
|
67
|
+
}
|
|
68
|
+
function listCwdAncestorNodeModulesDirs(cwd) {
|
|
69
|
+
const resolvedCwd = normalizePath(cwd);
|
|
70
|
+
const dirs = [];
|
|
71
|
+
let current = resolvedCwd;
|
|
72
|
+
while (true) {
|
|
73
|
+
const nodeModulesDir = path.join(current, "node_modules");
|
|
74
|
+
if (isDirectory(nodeModulesDir)) {
|
|
75
|
+
dirs.push(nodeModulesDir);
|
|
76
|
+
}
|
|
77
|
+
if (isFile(path.join(current, "package.json"))) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
const parent = path.dirname(current);
|
|
81
|
+
if (parent === current) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
current = parent;
|
|
85
|
+
}
|
|
86
|
+
return dirs;
|
|
87
|
+
}
|
|
88
|
+
function discoverNodeModulesDirs(cwd = process.cwd(), options) {
|
|
89
|
+
const explicit = options?.candidateDirs?.filter((dir) => isDirectory(dir)) ?? [];
|
|
90
|
+
if (explicit.length > 0) {
|
|
91
|
+
return uniqueResolvedPathsInOrder(explicit);
|
|
92
|
+
}
|
|
93
|
+
return uniqueResolvedPathsInOrder([
|
|
94
|
+
...listInstalledPackageNodeModulesDirs(),
|
|
95
|
+
...listCwdAncestorNodeModulesDirs(cwd)
|
|
96
|
+
]);
|
|
97
|
+
}
|
|
98
|
+
function discoverProjectRoots(cwd = process.cwd(), options) {
|
|
99
|
+
const roots = discoverNodeModulesDirs(
|
|
100
|
+
cwd,
|
|
101
|
+
options?.nodeModulesDirs ? { candidateDirs: options.nodeModulesDirs } : void 0
|
|
102
|
+
).map((nodeModulesDir) => path.dirname(nodeModulesDir));
|
|
103
|
+
return uniqueResolvedPathsInOrder([cwd, ...roots]);
|
|
104
|
+
}
|
|
105
|
+
function unique(values) {
|
|
106
|
+
return [...new Set(values)];
|
|
107
|
+
}
|
|
108
|
+
function pathExists(targetPath) {
|
|
109
|
+
try {
|
|
110
|
+
fs.accessSync(targetPath);
|
|
111
|
+
return true;
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function hasAnyDataMarkers(appDir) {
|
|
117
|
+
return pathExists(path.join(appDir, "SOUL.md")) || pathExists(path.join(appDir, "WORLD.md"));
|
|
118
|
+
}
|
|
119
|
+
function scoreAppCandidate(appDir) {
|
|
120
|
+
let score = 0;
|
|
121
|
+
if (pathExists(path.join(appDir, "SOUL.md"))) {
|
|
122
|
+
score += 4;
|
|
123
|
+
}
|
|
124
|
+
if (pathExists(path.join(appDir, "WORLD.md"))) {
|
|
125
|
+
score += 2;
|
|
126
|
+
}
|
|
127
|
+
if (pathExists(path.join(appDir, "skills"))) {
|
|
128
|
+
score += 1;
|
|
129
|
+
}
|
|
130
|
+
if (pathExists(path.join(appDir, "plugins"))) {
|
|
131
|
+
score += 1;
|
|
132
|
+
}
|
|
133
|
+
return score;
|
|
134
|
+
}
|
|
135
|
+
function resolveCandidateAppDirs(cwd, projectRoots) {
|
|
136
|
+
const roots = projectRoots ?? discoverProjectRoots(cwd);
|
|
137
|
+
const resolved = [];
|
|
138
|
+
const seen = /* @__PURE__ */ new Set();
|
|
139
|
+
for (const root of roots) {
|
|
140
|
+
const appDir = path.resolve(root, "app");
|
|
141
|
+
if (!pathExists(appDir)) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (seen.has(appDir)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
seen.add(appDir);
|
|
148
|
+
resolved.push(appDir);
|
|
149
|
+
}
|
|
150
|
+
return resolved;
|
|
151
|
+
}
|
|
152
|
+
function homeDir() {
|
|
153
|
+
return resolveHomeDir();
|
|
154
|
+
}
|
|
155
|
+
function resolveHomeDir(cwd = process.cwd(), options) {
|
|
156
|
+
const resolvedCwd = path.resolve(cwd);
|
|
157
|
+
const directApp = path.resolve(resolvedCwd, "app");
|
|
158
|
+
if (pathExists(directApp) && hasAnyDataMarkers(directApp)) {
|
|
159
|
+
return directApp;
|
|
160
|
+
}
|
|
161
|
+
const candidates = resolveCandidateAppDirs(
|
|
162
|
+
resolvedCwd,
|
|
163
|
+
options?.projectRoots
|
|
164
|
+
);
|
|
165
|
+
if (candidates.length === 0) {
|
|
166
|
+
return directApp;
|
|
167
|
+
}
|
|
168
|
+
candidates.sort((left, right) => {
|
|
169
|
+
const leftScore = scoreAppCandidate(left);
|
|
170
|
+
const rightScore = scoreAppCandidate(right);
|
|
171
|
+
if (leftScore !== rightScore) {
|
|
172
|
+
return rightScore - leftScore;
|
|
173
|
+
}
|
|
174
|
+
const leftDistance = path.relative(resolvedCwd, left).split(path.sep).length;
|
|
175
|
+
const rightDistance = path.relative(resolvedCwd, right).split(path.sep).length;
|
|
176
|
+
if (leftDistance !== rightDistance) {
|
|
177
|
+
return leftDistance - rightDistance;
|
|
178
|
+
}
|
|
179
|
+
return left.localeCompare(right);
|
|
180
|
+
});
|
|
181
|
+
return candidates[0];
|
|
182
|
+
}
|
|
183
|
+
function resolveContentRoots(subdir) {
|
|
184
|
+
if (subdir === "data") {
|
|
185
|
+
return [homeDir()];
|
|
186
|
+
}
|
|
187
|
+
return [path.join(homeDir(), subdir)];
|
|
188
|
+
}
|
|
189
|
+
function dataRoots() {
|
|
190
|
+
return unique(resolveContentRoots("data"));
|
|
191
|
+
}
|
|
192
|
+
function skillRoots() {
|
|
193
|
+
return unique(resolveContentRoots("skills"));
|
|
194
|
+
}
|
|
195
|
+
function pluginRoots() {
|
|
196
|
+
return unique(resolveContentRoots("plugins"));
|
|
197
|
+
}
|
|
198
|
+
function soulPathCandidates() {
|
|
199
|
+
const candidates = dataRoots().map((root) => path.join(root, "SOUL.md"));
|
|
200
|
+
return unique(candidates);
|
|
201
|
+
}
|
|
202
|
+
function worldPathCandidates() {
|
|
203
|
+
const candidates = dataRoots().map((root) => path.join(root, "WORLD.md"));
|
|
204
|
+
return unique(candidates);
|
|
205
|
+
}
|
|
206
|
+
var RESERVED_APP_FILES = /* @__PURE__ */ new Set([
|
|
207
|
+
"SOUL.md",
|
|
208
|
+
"WORLD.md",
|
|
209
|
+
"DESCRIPTION.md",
|
|
210
|
+
"ABOUT.md"
|
|
211
|
+
]);
|
|
212
|
+
function listReferenceFiles() {
|
|
213
|
+
const appDir = homeDir();
|
|
214
|
+
try {
|
|
215
|
+
const entries = fs.readdirSync(appDir, { withFileTypes: true });
|
|
216
|
+
return entries.filter(
|
|
217
|
+
(entry) => entry.isFile() && entry.name.endsWith(".md") && !RESERVED_APP_FILES.has(entry.name)
|
|
218
|
+
).map((entry) => path.join(appDir, entry.name)).sort();
|
|
219
|
+
} catch {
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/chat/coerce.ts
|
|
225
|
+
function toOptionalString(value) {
|
|
226
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
227
|
+
}
|
|
228
|
+
function toOptionalNumber(value) {
|
|
229
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
230
|
+
}
|
|
231
|
+
function isRecord(value) {
|
|
232
|
+
return typeof value === "object" && value !== null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/chat/logging.ts
|
|
236
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
237
|
+
import path2 from "path";
|
|
238
|
+
import { styleText } from "util";
|
|
239
|
+
import {
|
|
240
|
+
ConfigError,
|
|
241
|
+
configureSync,
|
|
242
|
+
getConfig,
|
|
243
|
+
getLogger
|
|
244
|
+
} from "@logtape/logtape";
|
|
245
|
+
var MAX_STRING_VALUE = 1200;
|
|
246
|
+
var SECRETS_RE = [
|
|
247
|
+
/\b(sk-[A-Za-z0-9_-]{20,})\b/g,
|
|
248
|
+
/\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g,
|
|
249
|
+
/\bBearer\s+([A-Za-z0-9._\-+=]{20,})\b/gi,
|
|
250
|
+
/\b[A-Z0-9_]+(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD)\s*[=:]\s*([^\s"']{8,})/gi
|
|
251
|
+
];
|
|
252
|
+
var LEGACY_KEY_MAP = {
|
|
253
|
+
error: "exception.message",
|
|
254
|
+
"error.stack": "exception.stacktrace",
|
|
255
|
+
"gen_ai.system": "gen_ai.provider.name",
|
|
256
|
+
"gen_ai.request.messages": "gen_ai.input.messages",
|
|
257
|
+
"gen_ai.response.text": "gen_ai.output.messages",
|
|
258
|
+
"messaging.conversation.id": "messaging.message.conversation_id",
|
|
259
|
+
bytes: "file.size",
|
|
260
|
+
media_type: "app.file.mime_type",
|
|
261
|
+
skillDir: "file.path",
|
|
262
|
+
root: "file.directory",
|
|
263
|
+
originalLength: "app.output.original_length",
|
|
264
|
+
parsedLength: "app.output.parsed_length",
|
|
265
|
+
directiveMode: "app.output.directive_mode",
|
|
266
|
+
fileCount: "app.output.file_count",
|
|
267
|
+
attempt: "app.retry.attempt",
|
|
268
|
+
steps: "app.ai.steps",
|
|
269
|
+
toolCalls: "app.ai.tool_calls",
|
|
270
|
+
toolResults: "app.ai.tool_results",
|
|
271
|
+
finishReason: "gen_ai.response.finish_reasons",
|
|
272
|
+
sources: "app.ai.sources",
|
|
273
|
+
generatedFiles: "app.ai.generated_files",
|
|
274
|
+
resultFiles: "app.ai.result_files",
|
|
275
|
+
responseMessages: "app.ai.response_messages",
|
|
276
|
+
stepDiagnostics: "app.ai.step_diagnostics",
|
|
277
|
+
inferredSkill: "app.skill.name",
|
|
278
|
+
inferredScore: "app.skill.score"
|
|
279
|
+
};
|
|
280
|
+
function normalizeGenAiFinishReason(reason) {
|
|
281
|
+
return reason === "toolUse" ? "tool_use" : reason;
|
|
282
|
+
}
|
|
283
|
+
function normalizeGenAiFinishReasons(value) {
|
|
284
|
+
if (typeof value === "string" && value.trim()) {
|
|
285
|
+
return [normalizeGenAiFinishReason(value)];
|
|
286
|
+
}
|
|
287
|
+
if (!Array.isArray(value)) {
|
|
288
|
+
return value;
|
|
289
|
+
}
|
|
290
|
+
return value.map(
|
|
291
|
+
(reason) => typeof reason === "string" ? normalizeGenAiFinishReason(reason) : reason
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
var contextStorage = new AsyncLocalStorage();
|
|
295
|
+
var logRecordSinks = /* @__PURE__ */ new Set();
|
|
296
|
+
var LOGTAPE_BODY_KEY = "__logtape_body";
|
|
297
|
+
var ROOT_LOGGER_CATEGORY = ["junior"];
|
|
298
|
+
var CONSOLE_PRIORITY_KEYS = [
|
|
299
|
+
"gen_ai.conversation.id",
|
|
300
|
+
"event.name",
|
|
301
|
+
"app.log.source",
|
|
302
|
+
"exception.message",
|
|
303
|
+
"messaging.message.id",
|
|
304
|
+
"trace_id",
|
|
305
|
+
"span_id",
|
|
306
|
+
"messaging.message.conversation_id",
|
|
307
|
+
"messaging.destination.name",
|
|
308
|
+
"app.run.id",
|
|
309
|
+
"app.message.kind"
|
|
310
|
+
];
|
|
311
|
+
var CONSOLE_PRIORITY_INDEX = new Map(
|
|
312
|
+
CONSOLE_PRIORITY_KEYS.map((key, index) => [key, index])
|
|
313
|
+
);
|
|
314
|
+
var CONSOLE_ALWAYS_HIDDEN_KEYS = /* @__PURE__ */ new Set([
|
|
315
|
+
"gen_ai.agent.name",
|
|
316
|
+
"app.platform",
|
|
317
|
+
"enduser.id",
|
|
318
|
+
"enduser.pseudo.id",
|
|
319
|
+
"http.request.method",
|
|
320
|
+
"messaging.system",
|
|
321
|
+
"url.full",
|
|
322
|
+
"url.path",
|
|
323
|
+
"user_agent.original"
|
|
324
|
+
]);
|
|
325
|
+
var CONSOLE_DROP_WHEN_COUNTED_KEYS = /* @__PURE__ */ new Set([
|
|
326
|
+
"app.capability.names",
|
|
327
|
+
"app.capability.providers",
|
|
328
|
+
"app.config.keys"
|
|
329
|
+
]);
|
|
330
|
+
var CONSOLE_PREVIEW_KEYS = /* @__PURE__ */ new Set([
|
|
331
|
+
"gen_ai.input.messages",
|
|
332
|
+
"gen_ai.output.messages",
|
|
333
|
+
"gen_ai.tool.call.arguments",
|
|
334
|
+
"gen_ai.tool.call.result"
|
|
335
|
+
]);
|
|
336
|
+
var SENTRY_TAG_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
|
|
337
|
+
"app.platform",
|
|
338
|
+
"messaging.system",
|
|
339
|
+
"app.actor.type",
|
|
340
|
+
"gen_ai.agent.name",
|
|
341
|
+
"gen_ai.request.model",
|
|
342
|
+
"app.skill.name",
|
|
343
|
+
"http.request.method",
|
|
344
|
+
"url.path"
|
|
345
|
+
]);
|
|
346
|
+
function getSentryEnvironment() {
|
|
347
|
+
return (process.env.SENTRY_ENVIRONMENT ?? process.env.VERCEL_ENV ?? process.env.NODE_ENV ?? "").trim().toLowerCase();
|
|
348
|
+
}
|
|
349
|
+
function shouldSuppressInfoLog(level) {
|
|
350
|
+
return getSentryEnvironment() === "production" && level === "info";
|
|
351
|
+
}
|
|
352
|
+
function shouldEmitConsole(level) {
|
|
353
|
+
if (process.env.NODE_ENV === "test") {
|
|
354
|
+
return level === "error";
|
|
355
|
+
}
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
function isDevelopmentLoggingMode() {
|
|
359
|
+
if (process.env.NODE_ENV !== "development") {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
if (process.env.CI) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
function shouldUseDevelopmentConsoleFormat() {
|
|
368
|
+
if (!isDevelopmentLoggingMode()) {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
return process.env.JUNIOR_LOG_FORMAT?.trim().toLowerCase() !== "structured";
|
|
372
|
+
}
|
|
373
|
+
function shouldUsePrettyConsole(level) {
|
|
374
|
+
if (level === "warn" || level === "error") {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
return shouldUseDevelopmentConsoleFormat();
|
|
378
|
+
}
|
|
379
|
+
function shouldUseConsoleColor() {
|
|
380
|
+
if (!shouldUseDevelopmentConsoleFormat()) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
if (process.env.NO_COLOR) {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
return process.env.FORCE_COLOR?.trim() === "1" || Boolean(process.stdout?.isTTY) || Boolean(process.stderr?.isTTY);
|
|
387
|
+
}
|
|
388
|
+
function formatConsoleTimestamp(timestamp) {
|
|
389
|
+
if (shouldUseDevelopmentConsoleFormat()) {
|
|
390
|
+
return timestamp.toTimeString().slice(0, 8);
|
|
391
|
+
}
|
|
392
|
+
return timestamp.toISOString();
|
|
393
|
+
}
|
|
394
|
+
function findNextBlankLineBoundary(input, start) {
|
|
395
|
+
const lfBoundary = input.indexOf("\n\n", start);
|
|
396
|
+
const crlfBoundary = input.indexOf("\r\n\r\n", start);
|
|
397
|
+
if (lfBoundary === -1 && crlfBoundary === -1) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
if (lfBoundary === -1) {
|
|
401
|
+
return { start: crlfBoundary, end: crlfBoundary + 4 };
|
|
402
|
+
}
|
|
403
|
+
if (crlfBoundary === -1 || lfBoundary < crlfBoundary) {
|
|
404
|
+
return { start: lfBoundary, end: lfBoundary + 2 };
|
|
405
|
+
}
|
|
406
|
+
return { start: crlfBoundary, end: crlfBoundary + 4 };
|
|
407
|
+
}
|
|
408
|
+
function redactPrivateKeyBlocks(input) {
|
|
409
|
+
const beginPrefix = "-----BEGIN ";
|
|
410
|
+
const footerMarker = "-----";
|
|
411
|
+
let cursor = 0;
|
|
412
|
+
let output = "";
|
|
413
|
+
while (cursor < input.length) {
|
|
414
|
+
const begin = input.indexOf(beginPrefix, cursor);
|
|
415
|
+
if (begin === -1) {
|
|
416
|
+
output += input.slice(cursor);
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
const labelStart = begin + beginPrefix.length;
|
|
420
|
+
const labelEnd = input.indexOf(footerMarker, labelStart);
|
|
421
|
+
if (labelEnd === -1) {
|
|
422
|
+
output += input.slice(cursor);
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
const label = input.slice(labelStart, labelEnd);
|
|
426
|
+
if (!label.endsWith("PRIVATE KEY")) {
|
|
427
|
+
output += input.slice(cursor, labelEnd + footerMarker.length);
|
|
428
|
+
cursor = labelEnd + footerMarker.length;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
const header = input.slice(begin, labelEnd + footerMarker.length);
|
|
432
|
+
const footer = `-----END ${label}-----`;
|
|
433
|
+
const footerStart = input.indexOf(footer, labelEnd + footerMarker.length);
|
|
434
|
+
if (footerStart === -1) {
|
|
435
|
+
const resumeBoundary = findNextBlankLineBoundary(
|
|
436
|
+
input,
|
|
437
|
+
labelEnd + footerMarker.length
|
|
438
|
+
);
|
|
439
|
+
output += input.slice(cursor, begin);
|
|
440
|
+
output += `${header}
|
|
441
|
+
...redacted...`;
|
|
442
|
+
if (!resumeBoundary) {
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
output += input.slice(resumeBoundary.start, resumeBoundary.end);
|
|
446
|
+
cursor = resumeBoundary.end;
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
output += input.slice(cursor, begin);
|
|
450
|
+
output += `${header}
|
|
451
|
+
...redacted...
|
|
452
|
+
${footer}`;
|
|
453
|
+
cursor = footerStart + footer.length;
|
|
454
|
+
}
|
|
455
|
+
return output;
|
|
456
|
+
}
|
|
457
|
+
function redactSecrets(input) {
|
|
458
|
+
let out = redactPrivateKeyBlocks(input);
|
|
459
|
+
for (const pattern of SECRETS_RE) {
|
|
460
|
+
out = out.replace(pattern, (full, token) => {
|
|
461
|
+
if (typeof token !== "string") {
|
|
462
|
+
return "***";
|
|
463
|
+
}
|
|
464
|
+
if (token.length < 12) {
|
|
465
|
+
return full.replace(token, "***");
|
|
466
|
+
}
|
|
467
|
+
return full.replace(token, `${token.slice(0, 4)}...${token.slice(-4)}`);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
return out;
|
|
471
|
+
}
|
|
472
|
+
function toSnakeCase(value) {
|
|
473
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
474
|
+
}
|
|
475
|
+
function isSemanticKey(key) {
|
|
476
|
+
return /^[a-z][a-z0-9_]*(\.[a-z0-9_][a-z0-9_-]*)+$/.test(key);
|
|
477
|
+
}
|
|
478
|
+
function normalizeAttributeKey(key) {
|
|
479
|
+
const mapped = LEGACY_KEY_MAP[key];
|
|
480
|
+
if (mapped) {
|
|
481
|
+
return mapped;
|
|
482
|
+
}
|
|
483
|
+
if (isSemanticKey(key)) {
|
|
484
|
+
return key;
|
|
485
|
+
}
|
|
486
|
+
if (key === "platform") return "app.platform";
|
|
487
|
+
if (key === "request.id") return "app.request.id";
|
|
488
|
+
const snake = toSnakeCase(key);
|
|
489
|
+
if (!snake) {
|
|
490
|
+
return "app.attribute";
|
|
491
|
+
}
|
|
492
|
+
return `app.${snake}`;
|
|
493
|
+
}
|
|
494
|
+
function sanitizePrimitive(value) {
|
|
495
|
+
if (value === null || value === void 0) return void 0;
|
|
496
|
+
if (typeof value === "string") {
|
|
497
|
+
const trimmed = value.trim();
|
|
498
|
+
if (!trimmed) return void 0;
|
|
499
|
+
const redacted = redactSecrets(trimmed);
|
|
500
|
+
return redacted.length > MAX_STRING_VALUE ? `${redacted.slice(0, MAX_STRING_VALUE)}...` : redacted;
|
|
501
|
+
}
|
|
502
|
+
if (typeof value === "number") {
|
|
503
|
+
return Number.isFinite(value) ? value : void 0;
|
|
504
|
+
}
|
|
505
|
+
if (typeof value === "boolean") return value;
|
|
506
|
+
if (value instanceof Error) {
|
|
507
|
+
return redactSecrets(value.message);
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
const json = JSON.stringify(value);
|
|
511
|
+
if (!json) return void 0;
|
|
512
|
+
const redacted = redactSecrets(json);
|
|
513
|
+
return redacted.length > MAX_STRING_VALUE ? `${redacted.slice(0, MAX_STRING_VALUE)}...` : redacted;
|
|
514
|
+
} catch {
|
|
515
|
+
return void 0;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
function sanitizeValue(value) {
|
|
519
|
+
if (Array.isArray(value)) {
|
|
520
|
+
const sanitized = value.filter((entry) => typeof entry === "string").map((entry) => sanitizePrimitive(entry)).filter((entry) => typeof entry === "string");
|
|
521
|
+
return sanitized.length > 0 ? sanitized : void 0;
|
|
522
|
+
}
|
|
523
|
+
return sanitizePrimitive(value);
|
|
524
|
+
}
|
|
525
|
+
function contextToAttributes(context) {
|
|
526
|
+
const attributes = {
|
|
527
|
+
"gen_ai.conversation.id": context.conversationId,
|
|
528
|
+
"app.platform": context.platform,
|
|
529
|
+
"app.request.id": context.requestId,
|
|
530
|
+
"messaging.system": context.platform === "slack" ? "slack" : context.platform,
|
|
531
|
+
"messaging.message.conversation_id": context.slackThreadId,
|
|
532
|
+
"messaging.destination.name": context.slackChannelId,
|
|
533
|
+
"enduser.id": context.slackUserId,
|
|
534
|
+
"enduser.pseudo.id": context.slackUserName,
|
|
535
|
+
"app.run.id": context.runId,
|
|
536
|
+
"app.actor.type": context.actorType,
|
|
537
|
+
"app.actor.id": context.actorId,
|
|
538
|
+
"gen_ai.agent.name": context.assistantUserName,
|
|
539
|
+
"gen_ai.request.model": context.modelId,
|
|
540
|
+
"app.skill.name": context.skillName,
|
|
541
|
+
"http.request.method": context.httpMethod,
|
|
542
|
+
"url.path": context.httpPath,
|
|
543
|
+
"url.full": context.urlFull,
|
|
544
|
+
"user_agent.original": context.userAgent
|
|
545
|
+
};
|
|
546
|
+
const normalized = {};
|
|
547
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
548
|
+
const sanitized = sanitizeValue(value);
|
|
549
|
+
if (sanitized !== void 0) normalized[key] = sanitized;
|
|
550
|
+
}
|
|
551
|
+
return normalized;
|
|
552
|
+
}
|
|
553
|
+
function getTraceCorrelationAttributes() {
|
|
554
|
+
const sentry = sentry_exports;
|
|
555
|
+
if (typeof sentry.getActiveSpan !== "function" || typeof sentry.spanToJSON !== "function") {
|
|
556
|
+
return {};
|
|
557
|
+
}
|
|
558
|
+
try {
|
|
559
|
+
const span = sentry.getActiveSpan();
|
|
560
|
+
if (!span) return {};
|
|
561
|
+
const json = sentry.spanToJSON(span);
|
|
562
|
+
const attrs = {};
|
|
563
|
+
if (json.trace_id) attrs.trace_id = json.trace_id;
|
|
564
|
+
if (json.span_id) attrs.span_id = json.span_id;
|
|
565
|
+
return attrs;
|
|
566
|
+
} catch {
|
|
567
|
+
return {};
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
function mergeAttributes(...maps) {
|
|
571
|
+
const merged = {};
|
|
572
|
+
for (const map of maps) {
|
|
573
|
+
if (!map) continue;
|
|
574
|
+
for (const [rawKey, rawValue] of Object.entries(map)) {
|
|
575
|
+
const key = normalizeAttributeKey(rawKey);
|
|
576
|
+
const value = sanitizeValue(
|
|
577
|
+
key === "gen_ai.response.finish_reasons" ? normalizeGenAiFinishReasons(rawValue) : rawValue
|
|
578
|
+
);
|
|
579
|
+
if (value !== void 0) {
|
|
580
|
+
merged[key] = value;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return merged;
|
|
585
|
+
}
|
|
586
|
+
function fromLogTapeLevel(level) {
|
|
587
|
+
if (level === "warning") {
|
|
588
|
+
return "warn";
|
|
589
|
+
}
|
|
590
|
+
if (level === "fatal") {
|
|
591
|
+
return "error";
|
|
592
|
+
}
|
|
593
|
+
if (level === "trace") {
|
|
594
|
+
return "debug";
|
|
595
|
+
}
|
|
596
|
+
return level;
|
|
597
|
+
}
|
|
598
|
+
function getLogSource(category) {
|
|
599
|
+
if (category.length <= ROOT_LOGGER_CATEGORY.length) {
|
|
600
|
+
return void 0;
|
|
601
|
+
}
|
|
602
|
+
const sourceParts = category.slice(ROOT_LOGGER_CATEGORY.length);
|
|
603
|
+
return sourceParts.length > 0 ? sourceParts.join(".") : void 0;
|
|
604
|
+
}
|
|
605
|
+
function toEmittedLogRecord(record) {
|
|
606
|
+
const properties = { ...record.properties };
|
|
607
|
+
const rawBody = properties[LOGTAPE_BODY_KEY];
|
|
608
|
+
delete properties[LOGTAPE_BODY_KEY];
|
|
609
|
+
const attributes = mergeAttributes(properties);
|
|
610
|
+
const source = getLogSource(record.category);
|
|
611
|
+
if (source && attributes["app.log.source"] === void 0) {
|
|
612
|
+
attributes["app.log.source"] = source;
|
|
613
|
+
}
|
|
614
|
+
const body = toOptionalString(rawBody) ?? record.message.map(
|
|
615
|
+
(segment) => typeof segment === "string" ? segment : String(segment ?? "")
|
|
616
|
+
).join("");
|
|
617
|
+
const eventName = toOptionalString(attributes["event.name"]) ?? "log_record_emitted";
|
|
618
|
+
return {
|
|
619
|
+
level: fromLogTapeLevel(record.level),
|
|
620
|
+
eventName,
|
|
621
|
+
body,
|
|
622
|
+
attributes
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
function createConsoleSink() {
|
|
626
|
+
return (record) => {
|
|
627
|
+
const emitted = toEmittedLogRecord(record);
|
|
628
|
+
emitConsole(
|
|
629
|
+
emitted.level,
|
|
630
|
+
emitted.eventName,
|
|
631
|
+
emitted.body,
|
|
632
|
+
emitted.attributes
|
|
633
|
+
);
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function createSentrySink() {
|
|
637
|
+
return (record) => {
|
|
638
|
+
const emitted = toEmittedLogRecord(record);
|
|
639
|
+
emitSentry(emitted.level, emitted.body, emitted.attributes);
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function createRecordSink() {
|
|
643
|
+
return (record) => {
|
|
644
|
+
const emitted = toEmittedLogRecord(record);
|
|
645
|
+
for (const sink of logRecordSinks) {
|
|
646
|
+
try {
|
|
647
|
+
sink(emitted);
|
|
648
|
+
} catch {
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
var rootLogger;
|
|
654
|
+
var ownsLogTapeBackend = false;
|
|
655
|
+
var usesDirectEmissionFallback = false;
|
|
656
|
+
function ensureLoggerBackend() {
|
|
657
|
+
if (rootLogger || usesDirectEmissionFallback) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if (getConfig() !== null) {
|
|
661
|
+
usesDirectEmissionFallback = true;
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
try {
|
|
665
|
+
configureSync({
|
|
666
|
+
sinks: {
|
|
667
|
+
console: createConsoleSink(),
|
|
668
|
+
sentry: createSentrySink(),
|
|
669
|
+
records: createRecordSink()
|
|
670
|
+
},
|
|
671
|
+
loggers: [
|
|
672
|
+
{
|
|
673
|
+
category: [...ROOT_LOGGER_CATEGORY],
|
|
674
|
+
sinks: ["console", "sentry", "records"],
|
|
675
|
+
lowestLevel: "debug"
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
category: ["logtape"],
|
|
679
|
+
sinks: ["console"],
|
|
680
|
+
lowestLevel: "error"
|
|
681
|
+
}
|
|
682
|
+
],
|
|
683
|
+
contextLocalStorage: contextStorage
|
|
684
|
+
});
|
|
685
|
+
ownsLogTapeBackend = true;
|
|
686
|
+
rootLogger = getLogger([...ROOT_LOGGER_CATEGORY]);
|
|
687
|
+
} catch (error) {
|
|
688
|
+
if (error instanceof ConfigError && getConfig() !== null) {
|
|
689
|
+
usesDirectEmissionFallback = true;
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
throw error;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
function getLogTapeLogger(category = []) {
|
|
696
|
+
ensureLoggerBackend();
|
|
697
|
+
if (!rootLogger) {
|
|
698
|
+
throw new Error("LogTape backend is unavailable");
|
|
699
|
+
}
|
|
700
|
+
let logger = rootLogger;
|
|
701
|
+
for (const part of category) {
|
|
702
|
+
logger = logger.getChild(part);
|
|
703
|
+
}
|
|
704
|
+
return logger;
|
|
705
|
+
}
|
|
706
|
+
function emitSentry(level, body, attributes) {
|
|
707
|
+
if (shouldSuppressInfoLog(level)) {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
const sentry = sentry_exports;
|
|
711
|
+
const loggerFn = sentry.logger?.[level];
|
|
712
|
+
if (typeof loggerFn === "function") {
|
|
713
|
+
loggerFn(body, attributes);
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
const sentryWithScope = sentry.withScope;
|
|
717
|
+
const sentryCaptureMessage = sentry.captureMessage;
|
|
718
|
+
const sentryLevel = level === "warn" ? "warning" : level;
|
|
719
|
+
if (typeof sentryWithScope === "function" && typeof sentryCaptureMessage === "function") {
|
|
720
|
+
sentryWithScope((scope) => {
|
|
721
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
722
|
+
scope.setExtra(key, value);
|
|
723
|
+
}
|
|
724
|
+
sentryCaptureMessage(body, sentryLevel);
|
|
725
|
+
});
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
if (typeof sentryCaptureMessage === "function") {
|
|
729
|
+
sentryCaptureMessage(body, sentryLevel);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
function formatConsoleLevel(level) {
|
|
733
|
+
if (level === "debug") return "DBG";
|
|
734
|
+
if (level === "info") return "INF";
|
|
735
|
+
if (level === "warn") return "WRN";
|
|
736
|
+
return "ERR";
|
|
737
|
+
}
|
|
738
|
+
function consoleLevelStyle(level) {
|
|
739
|
+
if (level === "error") return "red";
|
|
740
|
+
if (level === "warn") return "yellow";
|
|
741
|
+
if (level === "info") return "green";
|
|
742
|
+
return "blue";
|
|
743
|
+
}
|
|
744
|
+
function quoteConsoleValue(value) {
|
|
745
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
746
|
+
}
|
|
747
|
+
function formatConsoleValue(value) {
|
|
748
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
749
|
+
return String(value);
|
|
750
|
+
}
|
|
751
|
+
if (Array.isArray(value)) {
|
|
752
|
+
return quoteConsoleValue(JSON.stringify(value));
|
|
753
|
+
}
|
|
754
|
+
if (/^[A-Za-z0-9._:/@+-]+$/.test(value)) {
|
|
755
|
+
return value;
|
|
756
|
+
}
|
|
757
|
+
return quoteConsoleValue(value);
|
|
758
|
+
}
|
|
759
|
+
function shouldShowConsoleDestinationName(eventName) {
|
|
760
|
+
return /^(app_home_|oauth_|queue_|slash_command_|slack_|webhook_)/.test(
|
|
761
|
+
eventName
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
function shouldShowConsoleModel(level, eventName) {
|
|
765
|
+
if (level === "warn" || level === "error") {
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
return eventName.startsWith("ai_") || eventName.startsWith("assistant_") || eventName === "agent_turn_started" || eventName === "agent_turn_completed" || eventName === "agent_turn_provider_error";
|
|
769
|
+
}
|
|
770
|
+
function shouldHideConsoleAttribute(level, eventName, key, attributes) {
|
|
771
|
+
if (CONSOLE_ALWAYS_HIDDEN_KEYS.has(key)) {
|
|
772
|
+
return true;
|
|
773
|
+
}
|
|
774
|
+
if (CONSOLE_DROP_WHEN_COUNTED_KEYS.has(key)) {
|
|
775
|
+
return true;
|
|
776
|
+
}
|
|
777
|
+
if (key === "messaging.message.conversation_id" && attributes[key] === attributes["gen_ai.conversation.id"]) {
|
|
778
|
+
return true;
|
|
779
|
+
}
|
|
780
|
+
if (key === "app.message.id" && attributes[key] === attributes["messaging.message.id"]) {
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
if (key === "messaging.destination.name" && !shouldShowConsoleDestinationName(eventName)) {
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
786
|
+
if (key === "gen_ai.request.model" && !shouldShowConsoleModel(level, eventName)) {
|
|
787
|
+
return true;
|
|
788
|
+
}
|
|
789
|
+
if (key === "gen_ai.provider.name" && eventName.startsWith("agent_tool_call_") && level !== "warn" && level !== "error") {
|
|
790
|
+
return true;
|
|
791
|
+
}
|
|
792
|
+
if (key === "gen_ai.operation.name" && eventName.startsWith("agent_tool_call_")) {
|
|
793
|
+
return true;
|
|
794
|
+
}
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
function summarizeConsoleString(value, maxChars) {
|
|
798
|
+
const collapsed = value.replace(/\s+/g, " ").trim();
|
|
799
|
+
if (collapsed.length <= maxChars) {
|
|
800
|
+
return collapsed;
|
|
801
|
+
}
|
|
802
|
+
return `${collapsed.slice(0, maxChars)}... [${collapsed.length} chars]`;
|
|
803
|
+
}
|
|
804
|
+
function abbreviateConsoleId(value) {
|
|
805
|
+
if (value.length <= 20) {
|
|
806
|
+
return value;
|
|
807
|
+
}
|
|
808
|
+
return `${value.slice(0, 12)}...${value.slice(-4)}`;
|
|
809
|
+
}
|
|
810
|
+
function toRelativeConsolePath(value) {
|
|
811
|
+
const normalized = value.trim();
|
|
812
|
+
if (!normalized) {
|
|
813
|
+
return normalized;
|
|
814
|
+
}
|
|
815
|
+
try {
|
|
816
|
+
const relative = path2.relative(process.cwd(), normalized);
|
|
817
|
+
if (relative.length > 0 && !relative.startsWith("..") && !path2.isAbsolute(relative)) {
|
|
818
|
+
return relative;
|
|
819
|
+
}
|
|
820
|
+
} catch {
|
|
821
|
+
}
|
|
822
|
+
return normalized;
|
|
823
|
+
}
|
|
824
|
+
function pushPrettyConsoleToken(tokens, token) {
|
|
825
|
+
if (!token || tokens.includes(token)) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
tokens.push(token);
|
|
829
|
+
}
|
|
830
|
+
function numericConsoleToken(label, value) {
|
|
831
|
+
return typeof value === "number" ? `${label}=${value}` : void 0;
|
|
832
|
+
}
|
|
833
|
+
function stringConsoleToken(label, value) {
|
|
834
|
+
const normalized = toOptionalString(value);
|
|
835
|
+
return normalized ? `${label}=${normalized}` : void 0;
|
|
836
|
+
}
|
|
837
|
+
function booleanConsoleToken(label, value) {
|
|
838
|
+
return typeof value === "boolean" ? `${label}=${value ? "yes" : "no"}` : void 0;
|
|
839
|
+
}
|
|
840
|
+
function shouldShowPrettyCorrelation(eventName) {
|
|
841
|
+
return !(eventName === "plugin_loaded" || eventName === "startup_discovery_summary" || eventName === "capability_catalog_loaded" || eventName.endsWith("_loaded"));
|
|
842
|
+
}
|
|
843
|
+
function getPrettyConsoleSummaryTokens(level, eventName, attributes) {
|
|
844
|
+
const tokens = [];
|
|
845
|
+
pushPrettyConsoleToken(
|
|
846
|
+
tokens,
|
|
847
|
+
toOptionalString(attributes["app.log.source"]) ?? void 0
|
|
848
|
+
);
|
|
849
|
+
pushPrettyConsoleToken(
|
|
850
|
+
tokens,
|
|
851
|
+
eventName.startsWith("plugin_heartbeat") ? stringConsoleToken("plugin", attributes["app.plugin.name"]) : toOptionalString(attributes["app.plugin.name"]) ?? void 0
|
|
852
|
+
);
|
|
853
|
+
pushPrettyConsoleToken(
|
|
854
|
+
tokens,
|
|
855
|
+
numericConsoleToken("caps", attributes["app.plugin.capability_count"])
|
|
856
|
+
);
|
|
857
|
+
pushPrettyConsoleToken(
|
|
858
|
+
tokens,
|
|
859
|
+
numericConsoleToken("config", attributes["app.plugin.config_key_count"])
|
|
860
|
+
);
|
|
861
|
+
pushPrettyConsoleToken(
|
|
862
|
+
tokens,
|
|
863
|
+
booleanConsoleToken("mcp", attributes["app.plugin.has_mcp"])
|
|
864
|
+
);
|
|
865
|
+
pushPrettyConsoleToken(
|
|
866
|
+
tokens,
|
|
867
|
+
numericConsoleToken("plugins", attributes["app.plugin.count"])
|
|
868
|
+
);
|
|
869
|
+
pushPrettyConsoleToken(
|
|
870
|
+
tokens,
|
|
871
|
+
numericConsoleToken("dispatches", attributes["app.dispatch.count"])
|
|
872
|
+
);
|
|
873
|
+
pushPrettyConsoleToken(
|
|
874
|
+
tokens,
|
|
875
|
+
numericConsoleToken("skills", attributes["app.skill.count"])
|
|
876
|
+
);
|
|
877
|
+
pushPrettyConsoleToken(
|
|
878
|
+
tokens,
|
|
879
|
+
numericConsoleToken("capabilities", attributes["app.capability.count"])
|
|
880
|
+
);
|
|
881
|
+
pushPrettyConsoleToken(
|
|
882
|
+
tokens,
|
|
883
|
+
numericConsoleToken("config", attributes["app.config.key_count"])
|
|
884
|
+
);
|
|
885
|
+
pushPrettyConsoleToken(
|
|
886
|
+
tokens,
|
|
887
|
+
numericConsoleToken("chars", attributes["app.message.length"])
|
|
888
|
+
);
|
|
889
|
+
pushPrettyConsoleToken(
|
|
890
|
+
tokens,
|
|
891
|
+
numericConsoleToken(
|
|
892
|
+
"attachments",
|
|
893
|
+
attributes["app.message.attachment_count"]
|
|
894
|
+
)
|
|
895
|
+
);
|
|
896
|
+
const rawAttachmentCount = toOptionalNumber(
|
|
897
|
+
attributes["app.message.attachment_count"]
|
|
898
|
+
);
|
|
899
|
+
const promptAttachmentCount = toOptionalNumber(
|
|
900
|
+
attributes["app.message.prompt_attachment_count"]
|
|
901
|
+
);
|
|
902
|
+
if (promptAttachmentCount !== void 0 && promptAttachmentCount !== rawAttachmentCount) {
|
|
903
|
+
pushPrettyConsoleToken(
|
|
904
|
+
tokens,
|
|
905
|
+
numericConsoleToken("prompt_attachments", promptAttachmentCount)
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
const filePath = toOptionalString(attributes["file.path"]);
|
|
909
|
+
if (filePath && eventName.endsWith("_loaded")) {
|
|
910
|
+
pushPrettyConsoleToken(tokens, toRelativeConsolePath(filePath));
|
|
911
|
+
}
|
|
912
|
+
if (shouldShowPrettyCorrelation(eventName)) {
|
|
913
|
+
const conversationId = toOptionalString(
|
|
914
|
+
attributes["gen_ai.conversation.id"]
|
|
915
|
+
);
|
|
916
|
+
const messageId = toOptionalString(attributes["messaging.message.id"]);
|
|
917
|
+
if (conversationId) {
|
|
918
|
+
pushPrettyConsoleToken(
|
|
919
|
+
tokens,
|
|
920
|
+
`conv=${abbreviateConsoleId(conversationId)}`
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
if (messageId) {
|
|
924
|
+
pushPrettyConsoleToken(tokens, `msg=${abbreviateConsoleId(messageId)}`);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
const model = toOptionalString(attributes["gen_ai.request.model"]);
|
|
928
|
+
if (model && shouldShowConsoleModel(level, eventName)) {
|
|
929
|
+
pushPrettyConsoleToken(tokens, `model=${model}`);
|
|
930
|
+
}
|
|
931
|
+
return tokens;
|
|
932
|
+
}
|
|
933
|
+
function projectConsoleValue(level, key, value) {
|
|
934
|
+
if ((level === "debug" || level === "info") && CONSOLE_PREVIEW_KEYS.has(key) && typeof value === "string") {
|
|
935
|
+
return summarizeConsoleString(
|
|
936
|
+
value,
|
|
937
|
+
key === "gen_ai.tool.call.result" ? 220 : 140
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
return value;
|
|
941
|
+
}
|
|
942
|
+
function projectConsoleAttributes(level, eventName, attributes) {
|
|
943
|
+
const projected = {};
|
|
944
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
945
|
+
if (shouldHideConsoleAttribute(level, eventName, key, attributes)) {
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
const nextValue = projectConsoleValue(level, key, value);
|
|
949
|
+
if (nextValue !== void 0) {
|
|
950
|
+
projected[key] = nextValue;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return projected;
|
|
954
|
+
}
|
|
955
|
+
function formatConsoleLine(level, eventName, body, attributes) {
|
|
956
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
957
|
+
const useColor = shouldUseConsoleColor();
|
|
958
|
+
const levelStyle = consoleLevelStyle(level);
|
|
959
|
+
const colorize = (text, style) => useColor ? styleText(style, text) : text;
|
|
960
|
+
if (shouldUsePrettyConsole(level)) {
|
|
961
|
+
const summaryTokens = getPrettyConsoleSummaryTokens(
|
|
962
|
+
level,
|
|
963
|
+
eventName,
|
|
964
|
+
attributes
|
|
965
|
+
);
|
|
966
|
+
const summary = [body, ...summaryTokens].join(" ");
|
|
967
|
+
return [
|
|
968
|
+
colorize(formatConsoleTimestamp(timestamp), "gray"),
|
|
969
|
+
colorize(formatConsoleLevel(level), levelStyle),
|
|
970
|
+
summary
|
|
971
|
+
].join(" ");
|
|
972
|
+
}
|
|
973
|
+
const parts = [
|
|
974
|
+
`${colorize(formatConsoleTimestamp(timestamp), "gray")} ${colorize(formatConsoleLevel(level), levelStyle)} ${body}`
|
|
975
|
+
];
|
|
976
|
+
const projectedAttributes = projectConsoleAttributes(
|
|
977
|
+
level,
|
|
978
|
+
eventName,
|
|
979
|
+
attributes
|
|
980
|
+
);
|
|
981
|
+
const sortedAttributes = Object.entries(projectedAttributes).sort(
|
|
982
|
+
([left], [right]) => {
|
|
983
|
+
const leftRank = CONSOLE_PRIORITY_INDEX.get(left);
|
|
984
|
+
const rightRank = CONSOLE_PRIORITY_INDEX.get(right);
|
|
985
|
+
if (leftRank !== void 0 || rightRank !== void 0) {
|
|
986
|
+
if (leftRank === void 0) return 1;
|
|
987
|
+
if (rightRank === void 0) return -1;
|
|
988
|
+
return leftRank - rightRank;
|
|
989
|
+
}
|
|
990
|
+
return left.localeCompare(right);
|
|
991
|
+
}
|
|
992
|
+
);
|
|
993
|
+
for (const [key, value] of sortedAttributes) {
|
|
994
|
+
const rendered = `${colorize(key, "cyan")}=${colorize(formatConsoleValue(value), "dim")}`;
|
|
995
|
+
parts.push(rendered);
|
|
996
|
+
}
|
|
997
|
+
return parts.join(" ");
|
|
998
|
+
}
|
|
999
|
+
function emitConsole(level, eventName, body, attributes) {
|
|
1000
|
+
if (!shouldEmitConsole(level)) {
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
const line = formatConsoleLine(level, eventName, body, attributes);
|
|
1004
|
+
if (level === "error") {
|
|
1005
|
+
console.error(line);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
if (level === "warn") {
|
|
1009
|
+
console.warn(line);
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
if (level === "info") {
|
|
1013
|
+
console.info(line);
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
console.debug(line);
|
|
1017
|
+
}
|
|
1018
|
+
function emitDirect(level, eventName, body, attributes) {
|
|
1019
|
+
for (const sink of logRecordSinks) {
|
|
1020
|
+
try {
|
|
1021
|
+
sink({
|
|
1022
|
+
level,
|
|
1023
|
+
eventName,
|
|
1024
|
+
body,
|
|
1025
|
+
attributes
|
|
1026
|
+
});
|
|
1027
|
+
} catch {
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
emitConsole(level, eventName, body, attributes);
|
|
1031
|
+
emitSentry(level, body, attributes);
|
|
1032
|
+
}
|
|
1033
|
+
function emitRecord(category, level, eventName, attrs = {}, body) {
|
|
1034
|
+
ensureLoggerBackend();
|
|
1035
|
+
const traceAttributes = getTraceCorrelationAttributes();
|
|
1036
|
+
const normalizedEventName = toSnakeCase(eventName);
|
|
1037
|
+
const message = body ? redactSecrets(body) : normalizedEventName;
|
|
1038
|
+
const source = getLogSource([...ROOT_LOGGER_CATEGORY, ...category]);
|
|
1039
|
+
const contextAttributes = ownsLogTapeBackend ? void 0 : contextStorage.getStore();
|
|
1040
|
+
const attributes = mergeAttributes(contextAttributes, traceAttributes, {
|
|
1041
|
+
"event.name": normalizedEventName,
|
|
1042
|
+
...source ? { "app.log.source": source } : {},
|
|
1043
|
+
...attrs
|
|
1044
|
+
});
|
|
1045
|
+
if (usesDirectEmissionFallback) {
|
|
1046
|
+
emitDirect(level, normalizedEventName, message, attributes);
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
const logger = getLogTapeLogger(category);
|
|
1050
|
+
const properties = {
|
|
1051
|
+
[LOGTAPE_BODY_KEY]: message,
|
|
1052
|
+
...attributes
|
|
1053
|
+
};
|
|
1054
|
+
if (level === "error") {
|
|
1055
|
+
logger.error(`{${LOGTAPE_BODY_KEY}}`, properties);
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
if (level === "warn") {
|
|
1059
|
+
logger.warn(`{${LOGTAPE_BODY_KEY}}`, properties);
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
if (level === "info") {
|
|
1063
|
+
logger.info(`{${LOGTAPE_BODY_KEY}}`, properties);
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
logger.debug(`{${LOGTAPE_BODY_KEY}}`, properties);
|
|
1067
|
+
}
|
|
1068
|
+
function emit(level, eventName, attrs = {}, body) {
|
|
1069
|
+
emitRecord([], level, eventName, attrs, body);
|
|
1070
|
+
}
|
|
1071
|
+
var log = {
|
|
1072
|
+
debug(eventName, attrs = {}, body) {
|
|
1073
|
+
emit("debug", eventName, attrs, body);
|
|
1074
|
+
},
|
|
1075
|
+
info(eventName, attrs = {}, body) {
|
|
1076
|
+
emit("info", eventName, attrs, body);
|
|
1077
|
+
},
|
|
1078
|
+
warn(eventName, attrs = {}, body) {
|
|
1079
|
+
emit("warn", eventName, attrs, body);
|
|
1080
|
+
},
|
|
1081
|
+
error(eventName, attrs = {}, body) {
|
|
1082
|
+
emit("error", eventName, attrs, body);
|
|
1083
|
+
},
|
|
1084
|
+
exception(eventName, error, attrs = {}, body, context) {
|
|
1085
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
1086
|
+
emit(
|
|
1087
|
+
"error",
|
|
1088
|
+
eventName,
|
|
1089
|
+
{
|
|
1090
|
+
...attrs,
|
|
1091
|
+
"error.type": normalizedError.name,
|
|
1092
|
+
"exception.type": normalizedError.name,
|
|
1093
|
+
"exception.message": normalizedError.message,
|
|
1094
|
+
"exception.stacktrace": normalizedError.stack
|
|
1095
|
+
},
|
|
1096
|
+
body ?? normalizedError.message
|
|
1097
|
+
);
|
|
1098
|
+
let eventId;
|
|
1099
|
+
const sentryWithScope = sentry_exports.withScope;
|
|
1100
|
+
const sentryCaptureException = sentry_exports.captureException;
|
|
1101
|
+
if (typeof sentryWithScope === "function" && typeof sentryCaptureException === "function") {
|
|
1102
|
+
sentryWithScope((scope) => {
|
|
1103
|
+
if (context) {
|
|
1104
|
+
setSentryScopeContext(scope, context);
|
|
1105
|
+
}
|
|
1106
|
+
for (const [key, value] of Object.entries(
|
|
1107
|
+
mergeAttributes(contextStorage.getStore(), attrs)
|
|
1108
|
+
)) {
|
|
1109
|
+
scope.setExtra(key, value);
|
|
1110
|
+
}
|
|
1111
|
+
eventId = sentryCaptureException(normalizedError);
|
|
1112
|
+
});
|
|
1113
|
+
return eventId;
|
|
1114
|
+
}
|
|
1115
|
+
if (typeof sentryCaptureException === "function") {
|
|
1116
|
+
if (context) {
|
|
1117
|
+
setSentryUser(sentryUserIdentityFromContext(context));
|
|
1118
|
+
}
|
|
1119
|
+
eventId = sentryCaptureException(normalizedError);
|
|
1120
|
+
}
|
|
1121
|
+
return eventId;
|
|
1122
|
+
}
|
|
1123
|
+
};
|
|
1124
|
+
var CHAT_SDK_LEVEL_PRIORITY = {
|
|
1125
|
+
debug: 10,
|
|
1126
|
+
info: 20,
|
|
1127
|
+
warn: 30,
|
|
1128
|
+
error: 40
|
|
1129
|
+
};
|
|
1130
|
+
function resolveChatSdkLogLevel() {
|
|
1131
|
+
if (isDevelopmentLoggingMode()) {
|
|
1132
|
+
return "warn";
|
|
1133
|
+
}
|
|
1134
|
+
return "info";
|
|
1135
|
+
}
|
|
1136
|
+
function shouldEmitChatSdkLevel(level, minimumLevel) {
|
|
1137
|
+
if (minimumLevel === "silent") {
|
|
1138
|
+
return false;
|
|
1139
|
+
}
|
|
1140
|
+
return CHAT_SDK_LEVEL_PRIORITY[level] >= CHAT_SDK_LEVEL_PRIORITY[minimumLevel];
|
|
1141
|
+
}
|
|
1142
|
+
function renderChatSdkArgument(value) {
|
|
1143
|
+
if (value === null || value === void 0) {
|
|
1144
|
+
return "";
|
|
1145
|
+
}
|
|
1146
|
+
if (typeof value === "string") {
|
|
1147
|
+
return value;
|
|
1148
|
+
}
|
|
1149
|
+
if (value instanceof Error) {
|
|
1150
|
+
return value.message;
|
|
1151
|
+
}
|
|
1152
|
+
try {
|
|
1153
|
+
return JSON.stringify(value);
|
|
1154
|
+
} catch {
|
|
1155
|
+
return String(value);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
function formatChatSdkBody(message, args) {
|
|
1159
|
+
const renderedArgs = args.map((arg) => renderChatSdkArgument(arg).trim()).filter((arg) => arg.length > 0);
|
|
1160
|
+
if (renderedArgs.length === 0) {
|
|
1161
|
+
return message;
|
|
1162
|
+
}
|
|
1163
|
+
return `${message} ${renderedArgs.join(" ")}`;
|
|
1164
|
+
}
|
|
1165
|
+
function createChatSdkLoggerImpl(category, minimumLevel) {
|
|
1166
|
+
const emitChatSdkLog = (level, message, args) => {
|
|
1167
|
+
if (!shouldEmitChatSdkLevel(level, minimumLevel)) {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
emitRecord(
|
|
1171
|
+
category,
|
|
1172
|
+
level === "warn" ? "warn" : level,
|
|
1173
|
+
level === "error" ? "chat_sdk_error" : level === "warn" ? "chat_sdk_warning" : "chat_sdk_log",
|
|
1174
|
+
args.length > 0 ? {
|
|
1175
|
+
"app.log.args": args.length === 1 ? args[0] : args
|
|
1176
|
+
} : {},
|
|
1177
|
+
formatChatSdkBody(message, args)
|
|
1178
|
+
);
|
|
1179
|
+
};
|
|
1180
|
+
return {
|
|
1181
|
+
child(prefix) {
|
|
1182
|
+
return createChatSdkLoggerImpl([...category, prefix], minimumLevel);
|
|
1183
|
+
},
|
|
1184
|
+
debug(message, ...args) {
|
|
1185
|
+
emitChatSdkLog("debug", message, args);
|
|
1186
|
+
},
|
|
1187
|
+
info(message, ...args) {
|
|
1188
|
+
emitChatSdkLog("info", message, args);
|
|
1189
|
+
},
|
|
1190
|
+
warn(message, ...args) {
|
|
1191
|
+
emitChatSdkLog("warn", message, args);
|
|
1192
|
+
},
|
|
1193
|
+
error(message, ...args) {
|
|
1194
|
+
emitChatSdkLog("error", message, args);
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
function createChatSdkLogger() {
|
|
1199
|
+
return createChatSdkLoggerImpl(["chat-sdk"], resolveChatSdkLogLevel());
|
|
1200
|
+
}
|
|
1201
|
+
function withLogContext(context, callback) {
|
|
1202
|
+
const next = mergeAttributes(
|
|
1203
|
+
contextStorage.getStore(),
|
|
1204
|
+
contextToAttributes(context)
|
|
1205
|
+
);
|
|
1206
|
+
return contextStorage.run(next, callback);
|
|
1207
|
+
}
|
|
1208
|
+
function setLogContext(context) {
|
|
1209
|
+
const merged = mergeAttributes(
|
|
1210
|
+
contextStorage.getStore(),
|
|
1211
|
+
contextToAttributes(context)
|
|
1212
|
+
);
|
|
1213
|
+
contextStorage.enterWith(merged);
|
|
1214
|
+
}
|
|
1215
|
+
function getLogContextAttributes() {
|
|
1216
|
+
return contextStorage.getStore() ?? {};
|
|
1217
|
+
}
|
|
1218
|
+
function createLogContextFromRequest(request, context = {}) {
|
|
1219
|
+
const url = new URL(request.url);
|
|
1220
|
+
return {
|
|
1221
|
+
...context,
|
|
1222
|
+
requestId: context.requestId ?? request.headers.get("x-request-id") ?? void 0,
|
|
1223
|
+
httpMethod: request.method,
|
|
1224
|
+
httpPath: url.pathname,
|
|
1225
|
+
urlFull: url.toString(),
|
|
1226
|
+
userAgent: request.headers.get("user-agent") ?? void 0
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
function toSpanAttributes(context) {
|
|
1230
|
+
const attrs = contextToAttributes(context);
|
|
1231
|
+
return Object.fromEntries(
|
|
1232
|
+
Object.entries(attrs).filter(
|
|
1233
|
+
([, value]) => typeof value === "string" && value.length > 0
|
|
1234
|
+
)
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1237
|
+
function setSentryTagsFromContext(context) {
|
|
1238
|
+
const attrs = contextToAttributes(context);
|
|
1239
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
1240
|
+
if (!SENTRY_TAG_ATTRIBUTE_KEYS.has(key)) {
|
|
1241
|
+
continue;
|
|
1242
|
+
}
|
|
1243
|
+
if (typeof value === "string" && value.length > 0) {
|
|
1244
|
+
sentry_exports.setTag(key, value);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
function sentryUserIdentityFromContext(context) {
|
|
1249
|
+
if (context.slackUserId) {
|
|
1250
|
+
return {
|
|
1251
|
+
id: context.slackUserId,
|
|
1252
|
+
...context.slackUserName ? { username: context.slackUserName } : {},
|
|
1253
|
+
...context.slackUserEmail ? { email: context.slackUserEmail } : {}
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
return void 0;
|
|
1257
|
+
}
|
|
1258
|
+
function sentryUserFromIdentity(identity) {
|
|
1259
|
+
return {
|
|
1260
|
+
id: identity.id,
|
|
1261
|
+
ip_address: null,
|
|
1262
|
+
...identity.username ? { username: identity.username } : {},
|
|
1263
|
+
...identity.email ? { email: identity.email } : {}
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
function setSentryUser(identity) {
|
|
1267
|
+
if (!identity) return;
|
|
1268
|
+
sentry_exports.setUser(sentryUserFromIdentity(identity));
|
|
1269
|
+
}
|
|
1270
|
+
function setSentryScopeContext(scope, context) {
|
|
1271
|
+
const attrs = contextToAttributes(context);
|
|
1272
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
1273
|
+
if (!SENTRY_TAG_ATTRIBUTE_KEYS.has(key)) {
|
|
1274
|
+
continue;
|
|
1275
|
+
}
|
|
1276
|
+
if (typeof value === "string" && value.length > 0) {
|
|
1277
|
+
scope.setTag(key, value);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const identity = sentryUserIdentityFromContext(context);
|
|
1281
|
+
if (identity) {
|
|
1282
|
+
scope.setUser(sentryUserFromIdentity(identity));
|
|
1283
|
+
}
|
|
1284
|
+
scope.setContext("app", attrs);
|
|
1285
|
+
}
|
|
1286
|
+
function toSpanAttributeValue(value) {
|
|
1287
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1288
|
+
return value;
|
|
1289
|
+
}
|
|
1290
|
+
if (!Array.isArray(value)) {
|
|
1291
|
+
return void 0;
|
|
1292
|
+
}
|
|
1293
|
+
const sanitized = value.filter(
|
|
1294
|
+
(entry) => typeof entry === "string"
|
|
1295
|
+
);
|
|
1296
|
+
return sanitized.length > 0 ? sanitized : void 0;
|
|
1297
|
+
}
|
|
1298
|
+
function normalizeSpanAttributes(attributes) {
|
|
1299
|
+
const normalized = {};
|
|
1300
|
+
for (const [rawKey, value] of Object.entries(attributes)) {
|
|
1301
|
+
const key = normalizeAttributeKey(rawKey);
|
|
1302
|
+
const normalizedValue = toSpanAttributeValue(
|
|
1303
|
+
key === "gen_ai.response.finish_reasons" ? normalizeGenAiFinishReasons(value) : value
|
|
1304
|
+
);
|
|
1305
|
+
if (normalizedValue !== void 0) {
|
|
1306
|
+
normalized[key] = normalizedValue;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
return normalized;
|
|
1310
|
+
}
|
|
1311
|
+
function logInfo(eventName, context = {}, attributes = {}, body) {
|
|
1312
|
+
log.info(eventName, { ...toSpanAttributes(context), ...attributes }, body);
|
|
1313
|
+
}
|
|
1314
|
+
function logWarn(eventName, context = {}, attributes = {}, body) {
|
|
1315
|
+
log.warn(eventName, { ...toSpanAttributes(context), ...attributes }, body);
|
|
1316
|
+
}
|
|
1317
|
+
function logError(eventName, context = {}, attributes = {}, body) {
|
|
1318
|
+
log.error(eventName, { ...toSpanAttributes(context), ...attributes }, body);
|
|
1319
|
+
}
|
|
1320
|
+
function logException(error, eventName, context = {}, attributes = {}, body) {
|
|
1321
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
1322
|
+
return log.exception(
|
|
1323
|
+
eventName,
|
|
1324
|
+
normalizedError,
|
|
1325
|
+
{ ...toSpanAttributes(context), ...attributes },
|
|
1326
|
+
body,
|
|
1327
|
+
context
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
function setTags(context = {}) {
|
|
1331
|
+
setLogContext(context);
|
|
1332
|
+
setSentryTagsFromContext(context);
|
|
1333
|
+
setSentryUser(sentryUserIdentityFromContext(context));
|
|
1334
|
+
}
|
|
1335
|
+
function createRequestContext(request, context = {}) {
|
|
1336
|
+
return createLogContextFromRequest(request, context);
|
|
1337
|
+
}
|
|
1338
|
+
async function withContext(context, callback) {
|
|
1339
|
+
return withLogContext(context, callback);
|
|
1340
|
+
}
|
|
1341
|
+
async function withSpan(name, op, context, callback, attributes = {}) {
|
|
1342
|
+
const normalizedAttributes = normalizeSpanAttributes(attributes);
|
|
1343
|
+
return withLogContext(context, () => {
|
|
1344
|
+
const inheritedAttributes = getLogContextAttributes();
|
|
1345
|
+
return sentry_exports.startSpan(
|
|
1346
|
+
{
|
|
1347
|
+
name,
|
|
1348
|
+
op,
|
|
1349
|
+
attributes: {
|
|
1350
|
+
...inheritedAttributes,
|
|
1351
|
+
...normalizedAttributes
|
|
1352
|
+
}
|
|
1353
|
+
},
|
|
1354
|
+
callback
|
|
1355
|
+
);
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
function setSpanAttributes(attributes) {
|
|
1359
|
+
const sentry = sentry_exports;
|
|
1360
|
+
const span = sentry.getActiveSpan?.();
|
|
1361
|
+
if (!span) {
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
const setAttribute = span.setAttribute;
|
|
1365
|
+
if (typeof setAttribute !== "function") {
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
for (const [key, value] of Object.entries(
|
|
1369
|
+
normalizeSpanAttributes(attributes)
|
|
1370
|
+
)) {
|
|
1371
|
+
setAttribute.call(span, key, value);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
function setSpanStatus(status) {
|
|
1375
|
+
const sentry = sentry_exports;
|
|
1376
|
+
const span = sentry.getActiveSpan?.();
|
|
1377
|
+
if (!span) {
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
const setStatus = span.setStatus;
|
|
1381
|
+
if (typeof setStatus !== "function") {
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
setStatus.call(span, status === "ok" ? "ok" : "internal_error");
|
|
1385
|
+
}
|
|
1386
|
+
function getActiveTraceId() {
|
|
1387
|
+
const sentry = sentry_exports;
|
|
1388
|
+
if (typeof sentry.getActiveSpan !== "function" || typeof sentry.spanToJSON !== "function") {
|
|
1389
|
+
return void 0;
|
|
1390
|
+
}
|
|
1391
|
+
try {
|
|
1392
|
+
const span = sentry.getActiveSpan();
|
|
1393
|
+
if (!span) {
|
|
1394
|
+
return void 0;
|
|
1395
|
+
}
|
|
1396
|
+
return toOptionalString(sentry.spanToJSON(span).trace_id);
|
|
1397
|
+
} catch {
|
|
1398
|
+
return void 0;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
var TURN_FAILURE_RESPONSE_TEMPLATE = "I ran into an internal error while processing that. Reference: `event_id={eventId}`.";
|
|
1402
|
+
function buildTurnFailureResponse(eventId) {
|
|
1403
|
+
return TURN_FAILURE_RESPONSE_TEMPLATE.replace("{eventId}", eventId);
|
|
1404
|
+
}
|
|
1405
|
+
var GEN_AI_DEFAULT_MAX_ATTRIBUTE_CHARS = 12e3;
|
|
1406
|
+
var GEN_AI_MAX_STRING_CHARS = 2e3;
|
|
1407
|
+
var GEN_AI_MAX_ARRAY_ITEMS = 50;
|
|
1408
|
+
var GEN_AI_MAX_OBJECT_KEYS = 50;
|
|
1409
|
+
function truncateGenAiString(value, maxChars) {
|
|
1410
|
+
return value.length > maxChars ? `${value.slice(0, maxChars)}...` : value;
|
|
1411
|
+
}
|
|
1412
|
+
function sanitizeGenAiValue(value, seen, depth, keyName) {
|
|
1413
|
+
if (value === null || value === void 0) {
|
|
1414
|
+
return void 0;
|
|
1415
|
+
}
|
|
1416
|
+
if (typeof value === "string") {
|
|
1417
|
+
const shouldTreatAsBlob = (keyName === "data" || keyName === "base64" || keyName?.endsWith("_base64") === true) && value.length > 256;
|
|
1418
|
+
if (shouldTreatAsBlob) {
|
|
1419
|
+
return `[omitted:${value.length}]`;
|
|
1420
|
+
}
|
|
1421
|
+
return truncateGenAiString(redactSecrets(value), GEN_AI_MAX_STRING_CHARS);
|
|
1422
|
+
}
|
|
1423
|
+
if (typeof value === "number") {
|
|
1424
|
+
return Number.isFinite(value) ? value : void 0;
|
|
1425
|
+
}
|
|
1426
|
+
if (typeof value === "boolean") {
|
|
1427
|
+
return value;
|
|
1428
|
+
}
|
|
1429
|
+
if (depth >= 8) {
|
|
1430
|
+
return "[depth_limit]";
|
|
1431
|
+
}
|
|
1432
|
+
if (Array.isArray(value)) {
|
|
1433
|
+
return value.slice(0, GEN_AI_MAX_ARRAY_ITEMS).map((entry) => sanitizeGenAiValue(entry, seen, depth + 1)).filter((entry) => entry !== void 0);
|
|
1434
|
+
}
|
|
1435
|
+
if (typeof value !== "object") {
|
|
1436
|
+
return redactSecrets(String(value));
|
|
1437
|
+
}
|
|
1438
|
+
if (seen.has(value)) {
|
|
1439
|
+
return "[circular]";
|
|
1440
|
+
}
|
|
1441
|
+
seen.add(value);
|
|
1442
|
+
const record = value;
|
|
1443
|
+
const out = {};
|
|
1444
|
+
for (const [key, entryValue] of Object.entries(record).slice(
|
|
1445
|
+
0,
|
|
1446
|
+
GEN_AI_MAX_OBJECT_KEYS
|
|
1447
|
+
)) {
|
|
1448
|
+
const sanitized = sanitizeGenAiValue(entryValue, seen, depth + 1, key);
|
|
1449
|
+
if (sanitized !== void 0) {
|
|
1450
|
+
out[key] = sanitized;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
return out;
|
|
1454
|
+
}
|
|
1455
|
+
function serializeGenAiAttribute(value, maxChars = GEN_AI_DEFAULT_MAX_ATTRIBUTE_CHARS) {
|
|
1456
|
+
const sanitized = sanitizeGenAiValue(value, /* @__PURE__ */ new WeakSet(), 0);
|
|
1457
|
+
if (sanitized === void 0) {
|
|
1458
|
+
return void 0;
|
|
1459
|
+
}
|
|
1460
|
+
const serialized = typeof sanitized === "string" ? sanitized : JSON.stringify(sanitized);
|
|
1461
|
+
if (!serialized) {
|
|
1462
|
+
return void 0;
|
|
1463
|
+
}
|
|
1464
|
+
return truncateGenAiString(redactSecrets(serialized), maxChars);
|
|
1465
|
+
}
|
|
1466
|
+
function asRecord(value) {
|
|
1467
|
+
return value && typeof value === "object" ? value : void 0;
|
|
1468
|
+
}
|
|
1469
|
+
function toFiniteTokenCount(value) {
|
|
1470
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
1471
|
+
return void 0;
|
|
1472
|
+
}
|
|
1473
|
+
const rounded = Math.floor(value);
|
|
1474
|
+
return rounded >= 0 ? rounded : void 0;
|
|
1475
|
+
}
|
|
1476
|
+
function sumTokenCounts(...values) {
|
|
1477
|
+
let total = 0;
|
|
1478
|
+
let hasValue = false;
|
|
1479
|
+
for (const value of values) {
|
|
1480
|
+
if (value === void 0) {
|
|
1481
|
+
continue;
|
|
1482
|
+
}
|
|
1483
|
+
total += value;
|
|
1484
|
+
hasValue = true;
|
|
1485
|
+
}
|
|
1486
|
+
return hasValue ? total : void 0;
|
|
1487
|
+
}
|
|
1488
|
+
var PI_USAGE_FIELDS = [
|
|
1489
|
+
["input", "inputTokens"],
|
|
1490
|
+
["output", "outputTokens"],
|
|
1491
|
+
["cacheRead", "cachedInputTokens"],
|
|
1492
|
+
["cacheWrite", "cacheCreationTokens"],
|
|
1493
|
+
["totalTokens", "totalTokens"]
|
|
1494
|
+
];
|
|
1495
|
+
function readPiUsage(source) {
|
|
1496
|
+
const record = asRecord(source);
|
|
1497
|
+
if (!record) {
|
|
1498
|
+
return {};
|
|
1499
|
+
}
|
|
1500
|
+
const usage = asRecord(record.usage) ?? record;
|
|
1501
|
+
const summary = {};
|
|
1502
|
+
for (const [piKey, ourKey] of PI_USAGE_FIELDS) {
|
|
1503
|
+
const value = toFiniteTokenCount(usage[piKey]) ?? toFiniteTokenCount(usage[ourKey]);
|
|
1504
|
+
if (value !== void 0) {
|
|
1505
|
+
summary[ourKey] = value;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
return summary;
|
|
1509
|
+
}
|
|
1510
|
+
function extractGenAiUsageSummary(...sources) {
|
|
1511
|
+
const summary = {};
|
|
1512
|
+
for (const source of sources) {
|
|
1513
|
+
const single = readPiUsage(source);
|
|
1514
|
+
for (const field of Object.keys(single)) {
|
|
1515
|
+
const value = single[field];
|
|
1516
|
+
if (value === void 0) continue;
|
|
1517
|
+
summary[field] = (summary[field] ?? 0) + value;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return summary;
|
|
1521
|
+
}
|
|
1522
|
+
function extractGenAiUsageAttributes(...sources) {
|
|
1523
|
+
const { inputTokens, outputTokens, cachedInputTokens, cacheCreationTokens } = extractGenAiUsageSummary(...sources);
|
|
1524
|
+
const semanticInputTokens = sumTokenCounts(
|
|
1525
|
+
inputTokens,
|
|
1526
|
+
cachedInputTokens,
|
|
1527
|
+
cacheCreationTokens
|
|
1528
|
+
);
|
|
1529
|
+
return {
|
|
1530
|
+
...semanticInputTokens !== void 0 ? { "gen_ai.usage.input_tokens": semanticInputTokens } : {},
|
|
1531
|
+
...outputTokens !== void 0 ? { "gen_ai.usage.output_tokens": outputTokens } : {},
|
|
1532
|
+
...cachedInputTokens !== void 0 ? { "gen_ai.usage.cache_read.input_tokens": cachedInputTokens } : {},
|
|
1533
|
+
...cacheCreationTokens !== void 0 ? { "gen_ai.usage.cache_creation.input_tokens": cacheCreationTokens } : {}
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
// src/package-resolution.ts
|
|
1538
|
+
import { statSync as statSync2 } from "fs";
|
|
1539
|
+
import { createRequire } from "module";
|
|
1540
|
+
import path3 from "path";
|
|
1541
|
+
function isDirectory2(targetPath) {
|
|
1542
|
+
try {
|
|
1543
|
+
return statSync2(targetPath).isDirectory();
|
|
1544
|
+
} catch {
|
|
1545
|
+
return false;
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
function isFile2(targetPath) {
|
|
1549
|
+
try {
|
|
1550
|
+
return statSync2(targetPath).isFile();
|
|
1551
|
+
} catch {
|
|
1552
|
+
return false;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
function uniqueResolvedPathsInOrder2(values) {
|
|
1556
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1557
|
+
const resolved = [];
|
|
1558
|
+
for (const value of values) {
|
|
1559
|
+
const normalized = path3.resolve(value);
|
|
1560
|
+
if (seen.has(normalized)) {
|
|
1561
|
+
continue;
|
|
1562
|
+
}
|
|
1563
|
+
seen.add(normalized);
|
|
1564
|
+
resolved.push(normalized);
|
|
1565
|
+
}
|
|
1566
|
+
return resolved;
|
|
1567
|
+
}
|
|
1568
|
+
function ancestorNodeModulesDirs(cwd) {
|
|
1569
|
+
const dirs = [];
|
|
1570
|
+
let current = path3.resolve(cwd);
|
|
1571
|
+
while (true) {
|
|
1572
|
+
const nodeModulesDir = path3.join(current, "node_modules");
|
|
1573
|
+
if (isDirectory2(nodeModulesDir)) {
|
|
1574
|
+
dirs.push(nodeModulesDir);
|
|
1575
|
+
}
|
|
1576
|
+
const parent = path3.dirname(current);
|
|
1577
|
+
if (parent === current) {
|
|
1578
|
+
break;
|
|
1579
|
+
}
|
|
1580
|
+
current = parent;
|
|
1581
|
+
}
|
|
1582
|
+
return dirs;
|
|
1583
|
+
}
|
|
1584
|
+
function packageDirInNodeModules(nodeModulesDir, packageName) {
|
|
1585
|
+
const packageDir = path3.join(nodeModulesDir, ...packageName.split("/"));
|
|
1586
|
+
return isDirectory2(packageDir) ? path3.resolve(packageDir) : void 0;
|
|
1587
|
+
}
|
|
1588
|
+
function isValidPackageSegment(segment) {
|
|
1589
|
+
return Boolean(segment) && segment !== "." && segment !== ".." && !segment.startsWith(".") && /^[A-Za-z0-9._~-]+$/.test(segment);
|
|
1590
|
+
}
|
|
1591
|
+
function isValidPackageName(packageName) {
|
|
1592
|
+
if (!packageName || packageName.includes("\\") || path3.isAbsolute(packageName)) {
|
|
1593
|
+
return false;
|
|
1594
|
+
}
|
|
1595
|
+
const parts = packageName.split("/");
|
|
1596
|
+
if (parts[0].startsWith("@")) {
|
|
1597
|
+
return parts.length === 2 && parts[0].length > 1 && isValidPackageSegment(parts[0].slice(1)) && isValidPackageSegment(parts[1]);
|
|
1598
|
+
}
|
|
1599
|
+
return parts.length === 1 && isValidPackageSegment(parts[0]);
|
|
1600
|
+
}
|
|
1601
|
+
function findPackageRoot(entryPath) {
|
|
1602
|
+
let dir = path3.dirname(entryPath);
|
|
1603
|
+
while (dir !== path3.dirname(dir)) {
|
|
1604
|
+
if (isFile2(path3.join(dir, "package.json"))) {
|
|
1605
|
+
return path3.resolve(dir);
|
|
1606
|
+
}
|
|
1607
|
+
dir = path3.dirname(dir);
|
|
1608
|
+
}
|
|
1609
|
+
return void 0;
|
|
1610
|
+
}
|
|
1611
|
+
function findPackageNodeModulesDir(packageDir, packageName) {
|
|
1612
|
+
const parts = path3.resolve(packageDir).split(path3.sep);
|
|
1613
|
+
const packageParts = packageName.split("/");
|
|
1614
|
+
for (let index = parts.length - 1; index >= 0; index -= 1) {
|
|
1615
|
+
if (parts[index] !== "node_modules") {
|
|
1616
|
+
continue;
|
|
1617
|
+
}
|
|
1618
|
+
const candidatePackageParts = parts.slice(
|
|
1619
|
+
index + 1,
|
|
1620
|
+
index + 1 + packageParts.length
|
|
1621
|
+
);
|
|
1622
|
+
if (candidatePackageParts.join("/") !== packageParts.join("/")) {
|
|
1623
|
+
continue;
|
|
1624
|
+
}
|
|
1625
|
+
return path3.resolve(parts.slice(0, index + 1).join(path3.sep) || path3.sep);
|
|
1626
|
+
}
|
|
1627
|
+
return void 0;
|
|
1628
|
+
}
|
|
1629
|
+
function resolvePackageWithNode(cwd, packageName) {
|
|
1630
|
+
let requireFromCwd;
|
|
1631
|
+
try {
|
|
1632
|
+
requireFromCwd = createRequire(path3.join(cwd, "package.json"));
|
|
1633
|
+
} catch {
|
|
1634
|
+
return void 0;
|
|
1635
|
+
}
|
|
1636
|
+
for (const specifier of [`${packageName}/package.json`, packageName]) {
|
|
1637
|
+
try {
|
|
1638
|
+
const resolved = requireFromCwd.resolve(specifier);
|
|
1639
|
+
const dir = specifier.endsWith("/package.json") ? path3.dirname(resolved) : findPackageRoot(resolved);
|
|
1640
|
+
if (!dir) {
|
|
1641
|
+
continue;
|
|
1642
|
+
}
|
|
1643
|
+
const nodeModulesDir = findPackageNodeModulesDir(dir, packageName);
|
|
1644
|
+
return {
|
|
1645
|
+
dir,
|
|
1646
|
+
...nodeModulesDir ? { nodeModulesDir } : {}
|
|
1647
|
+
};
|
|
1648
|
+
} catch {
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
return void 0;
|
|
1652
|
+
}
|
|
1653
|
+
function resolvePackageLocation(cwd, packageName, options) {
|
|
1654
|
+
if (!isValidPackageName(packageName)) {
|
|
1655
|
+
return void 0;
|
|
1656
|
+
}
|
|
1657
|
+
const nodeModulesDirs = uniqueResolvedPathsInOrder2([
|
|
1658
|
+
...options?.nodeModulesDirs ?? [],
|
|
1659
|
+
...ancestorNodeModulesDirs(cwd)
|
|
1660
|
+
]);
|
|
1661
|
+
for (const nodeModulesDir of nodeModulesDirs) {
|
|
1662
|
+
const dir = packageDirInNodeModules(nodeModulesDir, packageName);
|
|
1663
|
+
if (dir) {
|
|
1664
|
+
return { dir, nodeModulesDir };
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
return resolvePackageWithNode(cwd, packageName);
|
|
1668
|
+
}
|
|
1669
|
+
function resolvePackageDir(cwd, packageName) {
|
|
1670
|
+
return resolvePackageLocation(cwd, packageName)?.dir;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// src/chat/plugins/package-discovery.ts
|
|
1674
|
+
import path4 from "path";
|
|
1675
|
+
function normalizeForGlob(targetPath) {
|
|
1676
|
+
return targetPath.split(path4.sep).join("/");
|
|
1677
|
+
}
|
|
1678
|
+
function uniqueStringsInOrder(values) {
|
|
1679
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1680
|
+
const resolved = [];
|
|
1681
|
+
for (const value of values) {
|
|
1682
|
+
if (seen.has(value)) {
|
|
1683
|
+
continue;
|
|
1684
|
+
}
|
|
1685
|
+
seen.add(value);
|
|
1686
|
+
resolved.push(value);
|
|
1687
|
+
}
|
|
1688
|
+
return resolved;
|
|
1689
|
+
}
|
|
1690
|
+
function pathForTracingInclude(cwd, targetPath) {
|
|
1691
|
+
const relative = path4.relative(cwd, targetPath);
|
|
1692
|
+
if (!relative || path4.isAbsolute(relative) || relative === ".." || relative.startsWith(`..${path4.sep}`)) {
|
|
1693
|
+
return null;
|
|
1694
|
+
}
|
|
1695
|
+
const normalized = normalizeForGlob(relative);
|
|
1696
|
+
return normalized.startsWith(".") ? normalized : `./${normalized}`;
|
|
1697
|
+
}
|
|
1698
|
+
function normalizePluginPackageNames(packageNames) {
|
|
1699
|
+
if (packageNames === void 0) {
|
|
1700
|
+
return [];
|
|
1701
|
+
}
|
|
1702
|
+
if (!Array.isArray(packageNames)) {
|
|
1703
|
+
throw new Error("Plugin package names must be an array");
|
|
1704
|
+
}
|
|
1705
|
+
const normalized = [];
|
|
1706
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1707
|
+
for (const packageName of packageNames) {
|
|
1708
|
+
const normalizedPackageName = typeof packageName === "string" ? packageName.trim() : "";
|
|
1709
|
+
if (!normalizedPackageName || !isValidPackageName(normalizedPackageName)) {
|
|
1710
|
+
throw new Error("Plugin package names must be valid npm package names");
|
|
1711
|
+
}
|
|
1712
|
+
if (seen.has(normalizedPackageName)) {
|
|
1713
|
+
continue;
|
|
1714
|
+
}
|
|
1715
|
+
seen.add(normalizedPackageName);
|
|
1716
|
+
normalized.push(normalizedPackageName);
|
|
1717
|
+
}
|
|
1718
|
+
return normalized;
|
|
1719
|
+
}
|
|
1720
|
+
function formatNodeModulesDirs(candidateNodeModulesDirs) {
|
|
1721
|
+
return candidateNodeModulesDirs.length > 0 ? candidateNodeModulesDirs.join(", ") : "none found";
|
|
1722
|
+
}
|
|
1723
|
+
function resolvePackageDirFromName(cwd, packageName, candidateNodeModulesDirs) {
|
|
1724
|
+
return resolvePackageLocation(cwd, packageName, {
|
|
1725
|
+
nodeModulesDirs: candidateNodeModulesDirs
|
|
1726
|
+
}) ?? null;
|
|
1727
|
+
}
|
|
1728
|
+
function readPluginPackageFlags(dir) {
|
|
1729
|
+
const hasRootPluginManifest = isFile(path4.join(dir, "plugin.yaml"));
|
|
1730
|
+
const hasPluginsDir = isDirectory(path4.join(dir, "plugins"));
|
|
1731
|
+
const hasSkillsDir = isDirectory(path4.join(dir, "skills"));
|
|
1732
|
+
if (!hasRootPluginManifest && !hasPluginsDir && !hasSkillsDir) {
|
|
1733
|
+
return null;
|
|
1734
|
+
}
|
|
1735
|
+
return {
|
|
1736
|
+
hasRootPluginManifest,
|
|
1737
|
+
hasPluginsDir,
|
|
1738
|
+
hasSkillsDir
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1741
|
+
function discoverDeclaredPackages(packageNames, candidateNodeModulesDirs, cwd) {
|
|
1742
|
+
const discovered = [];
|
|
1743
|
+
const seenPackageDirs = /* @__PURE__ */ new Set();
|
|
1744
|
+
for (const packageName of packageNames) {
|
|
1745
|
+
const resolved = resolvePackageDirFromName(
|
|
1746
|
+
cwd,
|
|
1747
|
+
packageName,
|
|
1748
|
+
candidateNodeModulesDirs
|
|
1749
|
+
);
|
|
1750
|
+
if (!resolved) {
|
|
1751
|
+
throw new Error(
|
|
1752
|
+
`Plugin package "${packageName}" was configured but could not be resolved from node_modules or package resolution (${formatNodeModulesDirs(candidateNodeModulesDirs)})`
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
if (seenPackageDirs.has(resolved.dir)) {
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
const pluginFlags = readPluginPackageFlags(resolved.dir);
|
|
1759
|
+
if (!pluginFlags) {
|
|
1760
|
+
throw new Error(
|
|
1761
|
+
`Plugin package "${packageName}" was configured but does not contain plugin content; expected plugin.yaml, plugins/, or skills/ in ${resolved.dir}`
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
seenPackageDirs.add(resolved.dir);
|
|
1765
|
+
discovered.push({
|
|
1766
|
+
name: packageName,
|
|
1767
|
+
dir: resolved.dir,
|
|
1768
|
+
nodeModulesDir: resolved.nodeModulesDir,
|
|
1769
|
+
...pluginFlags
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
return discovered;
|
|
1773
|
+
}
|
|
1774
|
+
function discoverInstalledPluginPackageContent(cwd = process.cwd(), options) {
|
|
1775
|
+
const resolvedCwd = path4.resolve(cwd);
|
|
1776
|
+
const packageNames = normalizePluginPackageNames(options?.packageNames);
|
|
1777
|
+
const nodeModulesDirs = options?.nodeModulesDirs ?? discoverNodeModulesDirs(resolvedCwd);
|
|
1778
|
+
const discoveredPackages = discoverDeclaredPackages(
|
|
1779
|
+
packageNames,
|
|
1780
|
+
nodeModulesDirs,
|
|
1781
|
+
resolvedCwd
|
|
1782
|
+
);
|
|
1783
|
+
const manifestRoots = [];
|
|
1784
|
+
const skillRoots2 = [];
|
|
1785
|
+
const tracingIncludes = [];
|
|
1786
|
+
for (const pkg of discoveredPackages) {
|
|
1787
|
+
const tracingBasePath = pkg.nodeModulesDir ? pathForTracingInclude(
|
|
1788
|
+
resolvedCwd,
|
|
1789
|
+
path4.join(pkg.nodeModulesDir, ...pkg.name.split("/"))
|
|
1790
|
+
) : pathForTracingInclude(resolvedCwd, pkg.dir);
|
|
1791
|
+
if (pkg.hasRootPluginManifest) {
|
|
1792
|
+
manifestRoots.push(pkg.dir);
|
|
1793
|
+
if (tracingBasePath) {
|
|
1794
|
+
tracingIncludes.push(`${tracingBasePath}/plugin.yaml`);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
if (pkg.hasPluginsDir) {
|
|
1798
|
+
manifestRoots.push(path4.join(pkg.dir, "plugins"));
|
|
1799
|
+
if (tracingBasePath) {
|
|
1800
|
+
tracingIncludes.push(`${tracingBasePath}/plugins/**/*`);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
if (pkg.hasSkillsDir) {
|
|
1804
|
+
skillRoots2.push(path4.join(pkg.dir, "skills"));
|
|
1805
|
+
if (tracingBasePath) {
|
|
1806
|
+
tracingIncludes.push(`${tracingBasePath}/skills/**/*`);
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
return {
|
|
1811
|
+
packageNames: uniqueStringsInOrder(
|
|
1812
|
+
discoveredPackages.map((pkg) => pkg.name)
|
|
1813
|
+
),
|
|
1814
|
+
packages: discoveredPackages.map((pkg) => ({
|
|
1815
|
+
dir: pkg.dir,
|
|
1816
|
+
hasSkillsDir: pkg.hasSkillsDir,
|
|
1817
|
+
name: pkg.name
|
|
1818
|
+
})),
|
|
1819
|
+
manifestRoots: uniqueStringsInOrder(manifestRoots),
|
|
1820
|
+
skillRoots: uniqueStringsInOrder(skillRoots2),
|
|
1821
|
+
tracingIncludes: uniqueStringsInOrder(tracingIncludes)
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
export {
|
|
1826
|
+
homeDir,
|
|
1827
|
+
skillRoots,
|
|
1828
|
+
pluginRoots,
|
|
1829
|
+
soulPathCandidates,
|
|
1830
|
+
worldPathCandidates,
|
|
1831
|
+
listReferenceFiles,
|
|
1832
|
+
toOptionalString,
|
|
1833
|
+
toOptionalNumber,
|
|
1834
|
+
isRecord,
|
|
1835
|
+
normalizeGenAiFinishReason,
|
|
1836
|
+
createChatSdkLogger,
|
|
1837
|
+
getLogContextAttributes,
|
|
1838
|
+
setSentryUser,
|
|
1839
|
+
logInfo,
|
|
1840
|
+
logWarn,
|
|
1841
|
+
logError,
|
|
1842
|
+
logException,
|
|
1843
|
+
setTags,
|
|
1844
|
+
createRequestContext,
|
|
1845
|
+
withContext,
|
|
1846
|
+
withSpan,
|
|
1847
|
+
setSpanAttributes,
|
|
1848
|
+
setSpanStatus,
|
|
1849
|
+
getActiveTraceId,
|
|
1850
|
+
buildTurnFailureResponse,
|
|
1851
|
+
serializeGenAiAttribute,
|
|
1852
|
+
extractGenAiUsageSummary,
|
|
1853
|
+
extractGenAiUsageAttributes,
|
|
1854
|
+
isValidPackageName,
|
|
1855
|
+
resolvePackageDir,
|
|
1856
|
+
normalizePluginPackageNames,
|
|
1857
|
+
discoverInstalledPluginPackageContent
|
|
1858
|
+
};
|