@sentry/junior 0.66.3 → 0.67.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 CHANGED
@@ -4,14 +4,22 @@ import {
4
4
  SlackActionError,
5
5
  TURN_CONTEXT_TAG,
6
6
  abandonAgentTurnSessionRecord,
7
+ bindSlackDirectCredentialSubject,
7
8
  buildSentryConversationUrl,
8
9
  buildSlackOutputMessage,
9
10
  buildSystemPrompt,
10
11
  buildTurnContextPrompt,
11
12
  commitMessages,
13
+ createAgentPluginHookRunner,
14
+ createAgentPluginLogger,
15
+ createPluginState,
12
16
  downloadPrivateSlackFile,
13
17
  escapeXml,
14
18
  failAgentTurnSessionRecord,
19
+ getAgentPluginRoutes,
20
+ getAgentPluginSlackConversationLink,
21
+ getAgentPluginTools,
22
+ getAgentPlugins,
15
23
  getAgentTurnSessionRecord,
16
24
  getFilePermalink,
17
25
  getHeaderString,
@@ -32,11 +40,14 @@ import {
32
40
  recordMcpProviderConnected,
33
41
  resolveSlackChannelTypeFromMessage,
34
42
  resolveSlackConversationContext,
43
+ setAgentPlugins,
35
44
  splitSlackReplyText,
36
45
  truncateStatusText,
37
46
  upsertAgentTurnSessionRecord,
47
+ validateAgentPlugins,
48
+ verifySlackDirectCredentialSubject,
38
49
  withSlackRetries
39
- } from "./chunk-DG2I6GXC.js";
50
+ } from "./chunk-HFMZE67J.js";
40
51
  import {
41
52
  discoverSkills,
42
53
  findSkillByName,
@@ -51,7 +62,7 @@ import {
51
62
  isSnapshotMissingError,
52
63
  resolveRuntimeDependencySnapshot,
53
64
  runNonInteractiveCommand
54
- } from "./chunk-JA5QR3N4.js";
65
+ } from "./chunk-KWEE2436.js";
55
66
  import {
56
67
  ACTIVE_LOCK_TTL_MS,
57
68
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
@@ -86,7 +97,7 @@ import {
86
97
  toGenAiPayloadMetadata,
87
98
  toGenAiPayloadTraceAttributes,
88
99
  toGenAiTextMetadata
89
- } from "./chunk-SAYCFF7O.js";
100
+ } from "./chunk-NWU2Z6SM.js";
90
101
  import {
91
102
  CredentialUnavailableError,
92
103
  buildOAuthTokenRequest,
@@ -178,588 +189,6 @@ function getConfigDefaults() {
178
189
  return cloneDefaults(installDefaults);
179
190
  }
180
191
 
181
- // src/chat/plugins/logging.ts
182
- function createAgentPluginLogger(plugin) {
183
- return {
184
- info(message, metadata) {
185
- logInfo(
186
- "agent_plugin_log_info",
187
- {},
188
- { "app.plugin.name": plugin, ...metadata },
189
- message
190
- );
191
- },
192
- warn(message, metadata) {
193
- logWarn(
194
- "agent_plugin_log_warn",
195
- {},
196
- { "app.plugin.name": plugin, ...metadata },
197
- message
198
- );
199
- },
200
- error(message, metadata) {
201
- logException(
202
- new Error(message),
203
- "agent_plugin_log_error",
204
- {},
205
- { "app.plugin.name": plugin, ...metadata },
206
- message
207
- );
208
- }
209
- };
210
- }
211
-
212
- // src/chat/plugins/state.ts
213
- import { createHash } from "crypto";
214
- var MAX_PLUGIN_STATE_KEY_LENGTH = 512;
215
- function hashKeyPart(value) {
216
- return createHash("sha256").update(value).digest("hex").slice(0, 32);
217
- }
218
- function pluginStateKey(plugin, key) {
219
- return `junior:plugin_state:${hashKeyPart(plugin)}:${hashKeyPart(key)}`;
220
- }
221
- function validatePluginStateKey(key) {
222
- if (!key.trim()) {
223
- throw new Error("Plugin state key is required");
224
- }
225
- if (key.length > MAX_PLUGIN_STATE_KEY_LENGTH) {
226
- throw new Error("Plugin state key exceeds the maximum length");
227
- }
228
- }
229
- function legacyStateKey(key, options) {
230
- for (const prefix of options?.legacyStatePrefixes ?? []) {
231
- const trimmed = prefix.trim();
232
- if (!trimmed) {
233
- continue;
234
- }
235
- if (key === trimmed || key.startsWith(`${trimmed}:`)) {
236
- return key;
237
- }
238
- }
239
- return void 0;
240
- }
241
- function createPluginState(plugin, options) {
242
- return {
243
- async delete(key) {
244
- validatePluginStateKey(key);
245
- const state = getStateAdapter();
246
- await state.connect();
247
- await state.delete(pluginStateKey(plugin, key));
248
- const legacyKey = legacyStateKey(key, options);
249
- if (legacyKey) {
250
- await state.delete(legacyKey);
251
- }
252
- },
253
- async get(key) {
254
- validatePluginStateKey(key);
255
- const state = getStateAdapter();
256
- await state.connect();
257
- const value = await state.get(pluginStateKey(plugin, key));
258
- if (value !== null && value !== void 0) {
259
- return value;
260
- }
261
- const legacyKey = legacyStateKey(key, options);
262
- return legacyKey ? await state.get(legacyKey) ?? void 0 : void 0;
263
- },
264
- async set(key, value, ttlMs) {
265
- validatePluginStateKey(key);
266
- const state = getStateAdapter();
267
- await state.connect();
268
- await state.set(pluginStateKey(plugin, key), value, ttlMs);
269
- },
270
- async setIfNotExists(key, value, ttlMs) {
271
- validatePluginStateKey(key);
272
- const state = getStateAdapter();
273
- await state.connect();
274
- const legacyKey = legacyStateKey(key, options);
275
- if (legacyKey) {
276
- const existing = await state.get(legacyKey);
277
- if (existing !== null && existing !== void 0) {
278
- return false;
279
- }
280
- }
281
- return await state.setIfNotExists(
282
- pluginStateKey(plugin, key),
283
- value,
284
- ttlMs
285
- );
286
- },
287
- async withLock(key, ttlMs, callback) {
288
- validatePluginStateKey(key);
289
- const state = getStateAdapter();
290
- await state.connect();
291
- const lockKey = legacyStateKey(key, options) ?? pluginStateKey(plugin, key);
292
- const lock = await state.acquireLock(lockKey, ttlMs);
293
- if (!lock) {
294
- throw new Error(`Could not acquire plugin state lock for ${key}`);
295
- }
296
- try {
297
- return await callback();
298
- } finally {
299
- await state.releaseLock(lock);
300
- }
301
- }
302
- };
303
- }
304
-
305
- // src/chat/credentials/subject.ts
306
- import { createHmac, timingSafeEqual } from "crypto";
307
- var CREDENTIAL_SUBJECT_HMAC_CONTEXT = "junior.credential_subject.v1";
308
- var CREDENTIAL_SUBJECT_SIGNATURE_VERSION = "v1";
309
- function getCredentialSubjectSecret() {
310
- return process.env.JUNIOR_SECRET?.trim() || void 0;
311
- }
312
- function buildPayload(input) {
313
- return [
314
- CREDENTIAL_SUBJECT_HMAC_CONTEXT,
315
- input.allowedWhen,
316
- input.teamId,
317
- input.channelId,
318
- input.userId
319
- ].join("\0");
320
- }
321
- function signPayload(secret, payload) {
322
- const digest = createHmac("sha256", secret).update(payload).digest("hex");
323
- return `${CREDENTIAL_SUBJECT_SIGNATURE_VERSION}=${digest}`;
324
- }
325
- function timingSafeMatch(expected, actual) {
326
- const expectedBuffer = Buffer.from(expected);
327
- const actualBuffer = Buffer.from(actual);
328
- if (expectedBuffer.length !== actualBuffer.length) {
329
- return false;
330
- }
331
- return timingSafeEqual(expectedBuffer, actualBuffer);
332
- }
333
- function createSlackDirectCredentialSubject(input) {
334
- const channelId = normalizeSlackConversationId(input.channelId);
335
- const teamId = input.teamId?.trim();
336
- const userId = input.userId?.trim();
337
- if (!channelId || !teamId || !userId || !isDmChannel(channelId)) {
338
- return void 0;
339
- }
340
- return {
341
- type: "user",
342
- userId,
343
- allowedWhen: "private-direct-conversation"
344
- };
345
- }
346
- function bindSlackDirectCredentialSubject(input) {
347
- const channelId = normalizeSlackConversationId(input.channelId);
348
- const teamId = input.teamId.trim();
349
- const secret = getCredentialSubjectSecret();
350
- const { subject } = input;
351
- const userId = subject.userId.trim();
352
- if (!channelId || !teamId || !secret || !isDmChannel(channelId) || subject.type !== "user" || !userId || subject.allowedWhen !== "private-direct-conversation") {
353
- return void 0;
354
- }
355
- return {
356
- type: "user",
357
- userId,
358
- allowedWhen: subject.allowedWhen,
359
- binding: {
360
- type: "slack-direct-conversation",
361
- teamId,
362
- channelId,
363
- signature: signPayload(
364
- secret,
365
- buildPayload({
366
- allowedWhen: subject.allowedWhen,
367
- teamId,
368
- channelId,
369
- userId
370
- })
371
- )
372
- }
373
- };
374
- }
375
- function verifySlackDirectCredentialSubject(input) {
376
- const channelId = normalizeSlackConversationId(input.channelId);
377
- const secret = getCredentialSubjectSecret();
378
- if (!channelId || !secret) {
379
- return false;
380
- }
381
- const { subject } = input;
382
- const binding = subject.binding;
383
- if (subject.type !== "user" || typeof subject.userId !== "string" || !subject.userId || subject.allowedWhen !== "private-direct-conversation" || !binding || binding.type !== "slack-direct-conversation" || typeof binding.signature !== "string" || !binding.signature || binding.teamId !== input.teamId || binding.channelId !== channelId) {
384
- return false;
385
- }
386
- const expected = signPayload(
387
- secret,
388
- buildPayload({
389
- allowedWhen: subject.allowedWhen,
390
- teamId: binding.teamId,
391
- channelId: binding.channelId,
392
- userId: subject.userId
393
- })
394
- );
395
- return timingSafeMatch(expected, binding.signature);
396
- }
397
-
398
- // src/chat/plugins/agent-hooks.ts
399
- var AgentPluginHookDeniedError = class extends Error {
400
- constructor(message) {
401
- super(message);
402
- this.name = "AgentPluginHookDeniedError";
403
- }
404
- };
405
- var agentPlugins = [];
406
- var AGENT_PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
407
- var AGENT_PLUGIN_TOOL_NAME_RE = /^[a-z][A-Za-z0-9]*$/;
408
- var AGENT_PLUGIN_ROUTE_METHODS = /* @__PURE__ */ new Set([
409
- "GET",
410
- "POST",
411
- "PUT",
412
- "PATCH",
413
- "DELETE",
414
- "HEAD",
415
- "OPTIONS",
416
- "ALL"
417
- ]);
418
- function validateLegacyStatePrefixes(plugin) {
419
- const prefixes = plugin.legacyStatePrefixes;
420
- if (prefixes === void 0) {
421
- return;
422
- }
423
- if (!Array.isArray(prefixes)) {
424
- throw new Error(
425
- `Trusted plugin "${plugin.name}" legacyStatePrefixes must be an array`
426
- );
427
- }
428
- const allowedPrefix = `junior:${plugin.name}`;
429
- for (const rawPrefix of prefixes) {
430
- const prefix = typeof rawPrefix === "string" ? rawPrefix.trim() : "";
431
- if (!prefix) {
432
- throw new Error(
433
- `Trusted plugin "${plugin.name}" legacy state prefixes must be non-empty strings`
434
- );
435
- }
436
- if (prefix !== allowedPrefix && !prefix.startsWith(`${allowedPrefix}:`)) {
437
- throw new Error(
438
- `Trusted plugin "${plugin.name}" legacy state prefix "${prefix}" must stay under "${allowedPrefix}"`
439
- );
440
- }
441
- }
442
- }
443
- function validateAgentPlugins(plugins) {
444
- const seen = /* @__PURE__ */ new Set();
445
- for (const plugin of plugins) {
446
- if (!AGENT_PLUGIN_NAME_RE.test(plugin.name)) {
447
- throw new Error(
448
- `Trusted plugin name "${plugin.name}" must be a lowercase plugin identifier`
449
- );
450
- }
451
- if (seen.has(plugin.name)) {
452
- throw new Error(`Duplicate trusted plugin name "${plugin.name}"`);
453
- }
454
- seen.add(plugin.name);
455
- validateLegacyStatePrefixes(plugin);
456
- }
457
- }
458
- function setAgentPlugins(plugins) {
459
- validateAgentPlugins(plugins);
460
- const previous = agentPlugins;
461
- agentPlugins = [...plugins].sort(
462
- (left, right) => left.name.localeCompare(right.name)
463
- );
464
- return previous;
465
- }
466
- function getAgentPlugins() {
467
- return [...agentPlugins];
468
- }
469
- function getAgentPluginTools(context) {
470
- const tools = {};
471
- for (const plugin of getAgentPlugins()) {
472
- const hook = plugin.hooks?.tools;
473
- if (!hook) {
474
- continue;
475
- }
476
- const log = createAgentPluginLogger(plugin.name);
477
- const credentialSubject = createSlackDirectCredentialSubject({
478
- channelId: context.channelId,
479
- teamId: context.teamId,
480
- userId: context.requester?.userId
481
- });
482
- const pluginTools = hook({
483
- plugin: { name: plugin.name },
484
- log,
485
- requester: context.requester,
486
- channelCapabilities: context.channelCapabilities,
487
- channelId: context.channelId,
488
- ...credentialSubject ? { credentialSubject } : {},
489
- teamId: context.teamId,
490
- messageTs: context.messageTs,
491
- threadTs: context.threadTs,
492
- userText: context.userText,
493
- state: createPluginState(plugin.name, {
494
- legacyStatePrefixes: plugin.legacyStatePrefixes
495
- })
496
- });
497
- for (const [name, tool2] of Object.entries(pluginTools)) {
498
- if (!AGENT_PLUGIN_TOOL_NAME_RE.test(name)) {
499
- throw new Error(
500
- `Trusted plugin tool "${name}" from plugin "${plugin.name}" must be a camelCase identifier`
501
- );
502
- }
503
- if (tools[name]) {
504
- throw new Error(
505
- `Duplicate trusted plugin tool "${name}" from plugin "${plugin.name}"`
506
- );
507
- }
508
- tools[name] = tool2;
509
- }
510
- }
511
- return tools;
512
- }
513
- function routeMethods(route, pluginName) {
514
- const methods = Array.isArray(route.method) ? route.method : [route.method ?? "ALL"];
515
- if (methods.length === 0) {
516
- throw new Error(
517
- `Trusted plugin route "${route.path}" from plugin "${pluginName}" must declare at least one method`
518
- );
519
- }
520
- for (const method of methods) {
521
- if (!AGENT_PLUGIN_ROUTE_METHODS.has(method)) {
522
- throw new Error(
523
- `Trusted plugin route "${route.path}" from plugin "${pluginName}" has invalid method "${String(method)}"`
524
- );
525
- }
526
- }
527
- if (methods.includes("ALL") && methods.length > 1) {
528
- throw new Error(
529
- `Trusted plugin route "${route.path}" from plugin "${pluginName}" must not combine ALL with explicit methods`
530
- );
531
- }
532
- return methods;
533
- }
534
- function getAgentPluginRoutes() {
535
- const routes = [];
536
- const seen = /* @__PURE__ */ new Set();
537
- const methodsByPath = /* @__PURE__ */ new Map();
538
- for (const plugin of getAgentPlugins()) {
539
- const hook = plugin.hooks?.routes;
540
- if (!hook) {
541
- continue;
542
- }
543
- const log = createAgentPluginLogger(plugin.name);
544
- const pluginRoutes = hook({
545
- plugin: { name: plugin.name },
546
- log
547
- });
548
- if (!Array.isArray(pluginRoutes)) {
549
- throw new Error(
550
- `Trusted plugin routes hook from plugin "${plugin.name}" must return an array`
551
- );
552
- }
553
- for (const route of pluginRoutes) {
554
- if (!isRecord2(route)) {
555
- throw new Error(
556
- `Trusted plugin route from plugin "${plugin.name}" must be an object`
557
- );
558
- }
559
- if (typeof route.path !== "string" || !route.path.startsWith("/")) {
560
- throw new Error(
561
- `Trusted plugin route "${route.path}" from plugin "${plugin.name}" must start with /`
562
- );
563
- }
564
- if (typeof route.handler !== "function") {
565
- throw new Error(
566
- `Trusted plugin route "${route.path}" from plugin "${plugin.name}" must provide a handler`
567
- );
568
- }
569
- const methods = routeMethods(route, plugin.name);
570
- const pathMethods = methodsByPath.get(route.path) ?? /* @__PURE__ */ new Set();
571
- if (pathMethods.has("ALL") || methods.includes("ALL") && pathMethods.size > 0) {
572
- throw new Error(
573
- `Trusted plugin route "${route.path}" conflicts with an ALL route for the same path`
574
- );
575
- }
576
- for (const method of methods) {
577
- const key = `${method}:${route.path}`;
578
- if (seen.has(key)) {
579
- throw new Error(
580
- `Duplicate trusted plugin route "${method} ${route.path}"`
581
- );
582
- }
583
- seen.add(key);
584
- pathMethods.add(method);
585
- }
586
- methodsByPath.set(route.path, pathMethods);
587
- routes.push({
588
- ...route,
589
- pluginName: plugin.name
590
- });
591
- }
592
- }
593
- return routes;
594
- }
595
- function trustedSlackConversationUrl(pluginName, link) {
596
- const url = typeof link?.url === "string" ? link.url.trim() : "";
597
- if (!url) {
598
- return void 0;
599
- }
600
- let parsed;
601
- try {
602
- parsed = new URL(url);
603
- } catch (error) {
604
- throw new Error(
605
- `Trusted plugin "${pluginName}" slackConversationLink must return an absolute http(s) URL`,
606
- { cause: error }
607
- );
608
- }
609
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
610
- throw new Error(
611
- `Trusted plugin "${pluginName}" slackConversationLink must return an absolute http(s) URL`
612
- );
613
- }
614
- return parsed.toString();
615
- }
616
- function getAgentPluginSlackConversationLink(conversationId) {
617
- for (const plugin of getAgentPlugins()) {
618
- const hook = plugin.hooks?.slackConversationLink;
619
- if (!hook) {
620
- continue;
621
- }
622
- const log = createAgentPluginLogger(plugin.name);
623
- const link = hook({
624
- plugin: { name: plugin.name },
625
- log,
626
- conversationId
627
- });
628
- const url = trustedSlackConversationUrl(plugin.name, link);
629
- if (url) {
630
- return { url };
631
- }
632
- }
633
- return void 0;
634
- }
635
- function isRecord2(value) {
636
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
637
- }
638
- function normalizeEnv(value) {
639
- if (!isRecord2(value)) {
640
- return {};
641
- }
642
- const env = {};
643
- for (const [key, rawValue] of Object.entries(value)) {
644
- if (typeof rawValue === "string") {
645
- env[key] = rawValue;
646
- }
647
- }
648
- return env;
649
- }
650
- function createSandboxCapability(sandbox) {
651
- return {
652
- root: SANDBOX_WORKSPACE_ROOT,
653
- juniorRoot: `${SANDBOX_WORKSPACE_ROOT}/.junior`,
654
- async readFile(filePath) {
655
- return await sandbox.readFileToBuffer({ path: filePath }) ?? null;
656
- },
657
- async run(input) {
658
- const result = await sandbox.runCommand(input);
659
- const [stdout, stderr] = await Promise.all([
660
- result.stdout(),
661
- result.stderr()
662
- ]);
663
- return {
664
- exitCode: result.exitCode,
665
- stdout,
666
- stderr
667
- };
668
- },
669
- async writeFile(input) {
670
- await sandbox.writeFiles([
671
- {
672
- path: input.path,
673
- content: input.content,
674
- ...input.mode !== void 0 ? { mode: input.mode } : {}
675
- }
676
- ]);
677
- }
678
- };
679
- }
680
- function createAgentPluginHookRunner(input = {}) {
681
- const loaded = getAgentPlugins();
682
- return {
683
- async prepareSandbox(sandbox) {
684
- const sandboxCapability = createSandboxCapability(sandbox);
685
- for (const plugin of loaded) {
686
- const hook = plugin.hooks?.sandboxPrepare;
687
- if (!hook) {
688
- continue;
689
- }
690
- logInfo(
691
- "agent_plugin_hook_sandbox_prepare",
692
- {},
693
- { "app.plugin.name": plugin.name },
694
- "Running agent plugin sandbox prepare hook"
695
- );
696
- await hook({
697
- plugin: { name: plugin.name },
698
- log: createAgentPluginLogger(plugin.name),
699
- requester: input.requester,
700
- sandbox: sandboxCapability
701
- });
702
- }
703
- },
704
- async beforeToolExecute(tool2) {
705
- let nextInput = { ...tool2.input };
706
- const env = normalizeEnv(nextInput.env);
707
- for (const plugin of loaded) {
708
- const hook = plugin.hooks?.beforeToolExecute;
709
- if (!hook) {
710
- continue;
711
- }
712
- let replacement;
713
- let denied;
714
- await hook({
715
- plugin: { name: plugin.name },
716
- log: createAgentPluginLogger(plugin.name),
717
- requester: input.requester,
718
- tool: {
719
- name: tool2.name,
720
- input: nextInput
721
- },
722
- env: {
723
- get(key) {
724
- return env[key];
725
- },
726
- set(key, value) {
727
- env[key] = value;
728
- }
729
- },
730
- decision: {
731
- deny(message) {
732
- denied = message;
733
- },
734
- replaceInput(input2) {
735
- replacement = input2;
736
- }
737
- }
738
- });
739
- if (denied) {
740
- throw new AgentPluginHookDeniedError(denied);
741
- }
742
- if (replacement !== void 0) {
743
- if (!isRecord2(replacement)) {
744
- throw new Error(
745
- `Plugin "${plugin.name}" replaced tool input with a non-object value`
746
- );
747
- }
748
- nextInput = { ...replacement };
749
- Object.assign(env, normalizeEnv(nextInput.env));
750
- }
751
- }
752
- return {
753
- input: {
754
- ...nextInput,
755
- ...Object.keys(env).length > 0 ? { env } : {}
756
- },
757
- env
758
- };
759
- }
760
- };
761
- }
762
-
763
192
  // src/chat/respond.ts
764
193
  import { Agent as Agent2 } from "@earendil-works/pi-agent-core";
765
194
  import { THREAD_STATE_TTL_MS as THREAD_STATE_TTL_MS3 } from "chat";
@@ -1915,7 +1344,7 @@ function parseMcpProviderFromToolName(toolName) {
1915
1344
 
1916
1345
  // src/chat/pi/derived-state.ts
1917
1346
  var MCP_BRIDGE_TOOLS = /* @__PURE__ */ new Set(["callMcpTool", "searchMcpTools"]);
1918
- function isRecord3(value) {
1347
+ function isRecord2(value) {
1919
1348
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1920
1349
  }
1921
1350
  function providerFromToolName(value) {
@@ -1937,7 +1366,7 @@ function addBridgeToolProvider(toolName, value, providers) {
1937
1366
  if (bridgeTool === "searchMcpTools") {
1938
1367
  for (const argsKey of ["input", "args", "arguments", "params"]) {
1939
1368
  const args = value[argsKey];
1940
- if (isRecord3(args)) {
1369
+ if (isRecord2(args)) {
1941
1370
  addString(providers, args.provider);
1942
1371
  }
1943
1372
  }
@@ -1946,7 +1375,7 @@ function addBridgeToolProvider(toolName, value, providers) {
1946
1375
  if (bridgeTool === "callMcpTool") {
1947
1376
  for (const argsKey of ["input", "args", "arguments", "params"]) {
1948
1377
  const args = value[argsKey];
1949
- if (isRecord3(args)) {
1378
+ if (isRecord2(args)) {
1950
1379
  addString(providers, providerFromToolName(args.tool_name));
1951
1380
  }
1952
1381
  }
@@ -1959,18 +1388,18 @@ function addMcpResultProvider(message, providers) {
1959
1388
  return;
1960
1389
  }
1961
1390
  if (toolName === "loadSkill") {
1962
- if (isRecord3(message.details)) {
1391
+ if (isRecord2(message.details)) {
1963
1392
  addString(providers, message.details.mcp_provider);
1964
1393
  }
1965
1394
  addString(providers, message.mcp_provider);
1966
1395
  return;
1967
1396
  }
1968
1397
  if (toolName === "searchMcpTools") {
1969
- if (isRecord3(message.details)) {
1398
+ if (isRecord2(message.details)) {
1970
1399
  addString(providers, message.details.provider);
1971
1400
  if (Array.isArray(message.details.tools)) {
1972
1401
  for (const tool2 of message.details.tools) {
1973
- if (isRecord3(tool2)) {
1402
+ if (isRecord2(tool2)) {
1974
1403
  addString(providers, providerFromToolName(tool2.tool_name));
1975
1404
  }
1976
1405
  }
@@ -1982,11 +1411,11 @@ function addMcpResultProvider(message, providers) {
1982
1411
  if (toolName === "callMcpTool") {
1983
1412
  for (const argsKey of ["input", "args", "arguments", "params"]) {
1984
1413
  const args = message[argsKey];
1985
- if (isRecord3(args)) {
1414
+ if (isRecord2(args)) {
1986
1415
  addString(providers, providerFromToolName(args.tool_name));
1987
1416
  }
1988
1417
  }
1989
- if (isRecord3(message.details)) {
1418
+ if (isRecord2(message.details)) {
1990
1419
  addString(providers, message.details.provider);
1991
1420
  addString(providers, providerFromToolName(message.details.tool_name));
1992
1421
  }
@@ -1994,7 +1423,7 @@ function addMcpResultProvider(message, providers) {
1994
1423
  }
1995
1424
  }
1996
1425
  function scanMcpProviders(message, providers) {
1997
- if (!isRecord3(message)) {
1426
+ if (!isRecord2(message)) {
1998
1427
  return;
1999
1428
  }
2000
1429
  if (message.role === "toolResult") {
@@ -2006,15 +1435,15 @@ function scanMcpProviders(message, providers) {
2006
1435
  return;
2007
1436
  }
2008
1437
  for (const part of content) {
2009
- if (!isRecord3(part)) {
1438
+ if (!isRecord2(part)) {
2010
1439
  continue;
2011
1440
  }
2012
1441
  addBridgeToolProvider(getToolName(part), part, providers);
2013
1442
  }
2014
1443
  }
2015
1444
  function scanLoadedSkills(message, skills) {
2016
- if (isRecord3(message) && message.role === "toolResult" && message.toolName === "loadSkill" && message.isError !== true) {
2017
- if (isRecord3(message.details)) {
1445
+ if (isRecord2(message) && message.role === "toolResult" && message.toolName === "loadSkill" && message.isError !== true) {
1446
+ if (isRecord2(message.details)) {
2018
1447
  addString(skills, message.details.skill_name);
2019
1448
  }
2020
1449
  addString(skills, message.skill_name);
@@ -7308,7 +6737,7 @@ async function startOAuthFlow(provider, input) {
7308
6737
  }
7309
6738
 
7310
6739
  // src/chat/sandbox/egress-session.ts
7311
- import { createHmac as createHmac2, randomUUID, timingSafeEqual as timingSafeEqual2 } from "crypto";
6740
+ import { createHmac, randomUUID, timingSafeEqual } from "crypto";
7312
6741
  var SANDBOX_EGRESS_PROXY_PATH = "/api/internal/sandbox-egress";
7313
6742
  var SANDBOX_EGRESS_TOKEN_VERSION = "v1";
7314
6743
  var SANDBOX_EGRESS_HMAC_CONTEXT = "junior.sandbox_egress.v1";
@@ -7332,16 +6761,16 @@ function base64Url(input) {
7332
6761
  function fromBase64Url(input) {
7333
6762
  return Buffer.from(input, "base64url").toString("utf8");
7334
6763
  }
7335
- function signPayload2(payload) {
7336
- return createHmac2("sha256", getSandboxEgressSecret()).update(`${SANDBOX_EGRESS_HMAC_CONTEXT}:${payload}`).digest("base64url");
6764
+ function signPayload(payload) {
6765
+ return createHmac("sha256", getSandboxEgressSecret()).update(`${SANDBOX_EGRESS_HMAC_CONTEXT}:${payload}`).digest("base64url");
7337
6766
  }
7338
- function timingSafeMatch2(expected, actual) {
6767
+ function timingSafeMatch(expected, actual) {
7339
6768
  const expectedBuffer = Buffer.from(expected);
7340
6769
  const actualBuffer = Buffer.from(actual);
7341
6770
  if (expectedBuffer.length !== actualBuffer.length) {
7342
6771
  return false;
7343
6772
  }
7344
- return timingSafeEqual2(expectedBuffer, actualBuffer);
6773
+ return timingSafeEqual(expectedBuffer, actualBuffer);
7345
6774
  }
7346
6775
  function parseSandboxEgressContext(value) {
7347
6776
  if (!value || typeof value !== "object") {
@@ -7400,7 +6829,7 @@ function createSandboxEgressCredentialToken(input) {
7400
6829
  const payload = `${SANDBOX_EGRESS_TOKEN_VERSION}.${base64Url(
7401
6830
  JSON.stringify(context)
7402
6831
  )}`;
7403
- return `${payload}.${signPayload2(payload)}`;
6832
+ return `${payload}.${signPayload(payload)}`;
7404
6833
  }
7405
6834
  function parseSandboxEgressCredentialToken(token) {
7406
6835
  if (!token) {
@@ -7416,7 +6845,7 @@ function parseSandboxEgressCredentialToken(token) {
7416
6845
  return void 0;
7417
6846
  }
7418
6847
  const payload = `${parts[0]}.${encodedSession}`;
7419
- if (!timingSafeMatch2(signPayload2(payload), signature)) {
6848
+ if (!timingSafeMatch(signPayload(payload), signature)) {
7420
6849
  return void 0;
7421
6850
  }
7422
6851
  try {
@@ -11125,6 +10554,7 @@ async function persistRunningSessionRecord(args) {
11125
10554
  sliceId: args.sliceId,
11126
10555
  state: "running",
11127
10556
  piMessages: args.messages,
10557
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
11128
10558
  ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
11129
10559
  ...args.requester ?? latestSessionRecord?.requester ? { requester: args.requester ?? latestSessionRecord?.requester } : {},
11130
10560
  ...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {}
@@ -11164,6 +10594,7 @@ async function persistCompletedSessionRecord(args) {
11164
10594
  sliceId: args.sliceId,
11165
10595
  state: "completed",
11166
10596
  piMessages: args.allMessages,
10597
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
11167
10598
  ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
11168
10599
  ...args.requester ?? latestSessionRecord?.requester ? { requester: args.requester ?? latestSessionRecord?.requester } : {},
11169
10600
  ...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {}
@@ -11209,6 +10640,7 @@ async function persistAuthPauseSessionRecord(args) {
11209
10640
  sliceId: nextSliceId,
11210
10641
  state: "awaiting_resume",
11211
10642
  piMessages,
10643
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
11212
10644
  ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
11213
10645
  resumeReason: "auth",
11214
10646
  resumedFromSliceId: args.currentSliceId,
@@ -11264,6 +10696,7 @@ async function persistTimeoutSessionRecord(args) {
11264
10696
  sliceId: args.currentSliceId,
11265
10697
  state: "failed",
11266
10698
  piMessages,
10699
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
11267
10700
  ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
11268
10701
  resumeReason: "timeout",
11269
10702
  resumedFromSliceId: latestSessionRecord?.resumedFromSliceId,
@@ -11281,6 +10714,7 @@ async function persistTimeoutSessionRecord(args) {
11281
10714
  sliceId: nextSliceId,
11282
10715
  state: "awaiting_resume",
11283
10716
  piMessages,
10717
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
11284
10718
  ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
11285
10719
  resumeReason: "timeout",
11286
10720
  resumedFromSliceId: args.currentSliceId,
@@ -11330,6 +10764,7 @@ async function persistYieldSessionRecord(args) {
11330
10764
  sliceId: args.currentSliceId,
11331
10765
  state: "awaiting_resume",
11332
10766
  piMessages,
10767
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
11333
10768
  ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
11334
10769
  resumeReason: "yield",
11335
10770
  resumedFromSliceId: latestSessionRecord?.resumedFromSliceId,
@@ -11797,6 +11232,23 @@ function requesterFromContext(requester, requesterId) {
11797
11232
  };
11798
11233
  return Object.keys(identity).length > 0 ? identity : void 0;
11799
11234
  }
11235
+ function surfaceFromContext(context) {
11236
+ if (context.surface) {
11237
+ return context.surface;
11238
+ }
11239
+ const conversationId = context.correlation?.conversationId ?? context.correlation?.threadId ?? context.correlation?.runId;
11240
+ if (context.slackConversation || (conversationId ? parseSlackThreadId(conversationId) : void 0)) {
11241
+ return "slack";
11242
+ }
11243
+ const actor = context.credentialContext?.actor;
11244
+ if (actor?.type === "system" && actor.id === "scheduler") {
11245
+ return "scheduler";
11246
+ }
11247
+ if (conversationId) {
11248
+ return "api";
11249
+ }
11250
+ return void 0;
11251
+ }
11800
11252
  function supportsRouterTextPreview(mediaType) {
11801
11253
  const baseMediaType = mediaType.split(";", 1)[0]?.trim().toLowerCase();
11802
11254
  if (!baseMediaType) {
@@ -11912,6 +11364,7 @@ async function generateAssistantReply(messageText2, context = {}) {
11912
11364
  context.requester,
11913
11365
  context.correlation?.requesterId
11914
11366
  );
11367
+ const surface = surfaceFromContext(context);
11915
11368
  const credentialActor = context.credentialContext?.actor;
11916
11369
  const credentialActorLogContext = credentialActor ? {
11917
11370
  actorType: credentialActor.type,
@@ -12437,7 +11890,8 @@ async function generateAssistantReply(messageText2, context = {}) {
12437
11890
  messages,
12438
11891
  loadedSkillNames: loadedSkillNamesForResume,
12439
11892
  logContext: sessionRecordLogContext,
12440
- requester
11893
+ requester,
11894
+ ...surface ? { surface } : {}
12441
11895
  });
12442
11896
  if (!persisted) {
12443
11897
  return false;
@@ -12750,7 +12204,8 @@ async function generateAssistantReply(messageText2, context = {}) {
12750
12204
  allMessages: agent.state.messages,
12751
12205
  loadedSkillNames: loadedSkillNamesForResume,
12752
12206
  logContext: sessionRecordLogContext,
12753
- requester
12207
+ requester,
12208
+ ...surface ? { surface } : {}
12754
12209
  });
12755
12210
  }
12756
12211
  return buildTurnResult({
@@ -12785,7 +12240,8 @@ async function generateAssistantReply(messageText2, context = {}) {
12785
12240
  errorMessage: error.message,
12786
12241
  loadedSkillNames: loadedSkillNamesForResume,
12787
12242
  logContext: sessionRecordLogContext,
12788
- requester
12243
+ requester,
12244
+ ...surface ? { surface } : {}
12789
12245
  });
12790
12246
  if (!sessionRecord) {
12791
12247
  throw new Error(
@@ -12808,7 +12264,8 @@ async function generateAssistantReply(messageText2, context = {}) {
12808
12264
  errorMessage: error instanceof Error ? error.message : String(error),
12809
12265
  loadedSkillNames: loadedSkillNamesForResume,
12810
12266
  logContext: sessionRecordLogContext,
12811
- requester
12267
+ requester,
12268
+ ...surface ? { surface } : {}
12812
12269
  });
12813
12270
  if (!sessionRecord) {
12814
12271
  throw new Error(
@@ -12850,7 +12307,8 @@ async function generateAssistantReply(messageText2, context = {}) {
12850
12307
  errorMessage: error.message,
12851
12308
  loadedSkillNames: loadedSkillNamesForResume,
12852
12309
  logContext: sessionRecordLogContext,
12853
- requester
12310
+ requester,
12311
+ ...surface ? { surface } : {}
12854
12312
  });
12855
12313
  if (sessionRecord) {
12856
12314
  throw new RetryableTurnError(
@@ -13630,7 +13088,7 @@ function finalizeFailedTurnReply(args) {
13630
13088
  }
13631
13089
 
13632
13090
  // src/chat/agent-dispatch/signing.ts
13633
- import { createHmac as createHmac3, timingSafeEqual as timingSafeEqual3 } from "crypto";
13091
+ import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "crypto";
13634
13092
  var DISPATCH_CALLBACK_PATH = "/api/internal/agent-dispatch";
13635
13093
  var DISPATCH_HMAC_CONTEXT = "junior.agent_dispatch.v1";
13636
13094
  var DISPATCH_SIGNATURE_VERSION = "v1";
@@ -13645,16 +13103,16 @@ function buildSignedPayload(timestamp, body) {
13645
13103
  return `${DISPATCH_HMAC_CONTEXT}:${timestamp}:${body}`;
13646
13104
  }
13647
13105
  function signBody(secret, timestamp, body) {
13648
- const digest = createHmac3("sha256", secret).update(buildSignedPayload(timestamp, body)).digest("hex");
13106
+ const digest = createHmac2("sha256", secret).update(buildSignedPayload(timestamp, body)).digest("hex");
13649
13107
  return `${DISPATCH_SIGNATURE_VERSION}=${digest}`;
13650
13108
  }
13651
- function timingSafeMatch3(expected, actual) {
13109
+ function timingSafeMatch2(expected, actual) {
13652
13110
  const expectedBuffer = Buffer.from(expected);
13653
13111
  const actualBuffer = Buffer.from(actual);
13654
13112
  if (expectedBuffer.length !== actualBuffer.length) {
13655
13113
  return false;
13656
13114
  }
13657
- return timingSafeEqual3(expectedBuffer, actualBuffer);
13115
+ return timingSafeEqual2(expectedBuffer, actualBuffer);
13658
13116
  }
13659
13117
  function parseDispatchCallback(value) {
13660
13118
  if (!value || typeof value !== "object") {
@@ -13713,7 +13171,7 @@ async function verifyDispatchCallbackRequest(request) {
13713
13171
  }
13714
13172
  const body = await request.text();
13715
13173
  const expectedSignature = signBody(secret, timestamp, body);
13716
- if (!timingSafeMatch3(expectedSignature, signature)) {
13174
+ if (!timingSafeMatch2(expectedSignature, signature)) {
13717
13175
  return void 0;
13718
13176
  }
13719
13177
  try {
@@ -13724,7 +13182,7 @@ async function verifyDispatchCallbackRequest(request) {
13724
13182
  }
13725
13183
 
13726
13184
  // src/chat/agent-dispatch/store.ts
13727
- import { createHash as createHash2 } from "crypto";
13185
+ import { createHash } from "crypto";
13728
13186
  var DISPATCH_PREFIX = "junior:agent_dispatch";
13729
13187
  var DISPATCH_LOCK_TTL_MS = 10 * 60 * 1e3;
13730
13188
  var DISPATCH_INDEX_LOCK_TTL_MS = 1e4;
@@ -13752,7 +13210,7 @@ function normalizeMetadata(metadata) {
13752
13210
  return entries.length > 0 ? Object.fromEntries(entries) : void 0;
13753
13211
  }
13754
13212
  function buildDispatchId(plugin, idempotencyKey) {
13755
- const digest = createHash2("sha256").update(plugin).update("\0").update(idempotencyKey).digest("hex").slice(0, 32);
13213
+ const digest = createHash("sha256").update(plugin).update("\0").update(idempotencyKey).digest("hex").slice(0, 32);
13756
13214
  return `dispatch_${digest}`;
13757
13215
  }
13758
13216
  function getDispatchDestinationLockId(destination) {
@@ -14059,6 +13517,7 @@ async function runAgentDispatchSlice(callback, deps = {}) {
14059
13517
  channelId: dispatch.destination.channelId,
14060
13518
  teamId: dispatch.destination.teamId
14061
13519
  },
13520
+ surface: dispatch.actor.id === "scheduler" ? "scheduler" : "api",
14062
13521
  toolChannelId: dispatch.destination.channelId,
14063
13522
  sandbox: {
14064
13523
  sandboxId,
@@ -14234,10 +13693,10 @@ async function POST(request, waitUntil) {
14234
13693
  }
14235
13694
 
14236
13695
  // src/handlers/heartbeat.ts
14237
- import { timingSafeEqual as timingSafeEqual5 } from "crypto";
13696
+ import { timingSafeEqual as timingSafeEqual4 } from "crypto";
14238
13697
 
14239
13698
  // src/chat/services/timeout-resume.ts
14240
- import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual4 } from "crypto";
13699
+ import { createHmac as createHmac3, timingSafeEqual as timingSafeEqual3 } from "crypto";
14241
13700
 
14242
13701
  // src/chat/task-execution/store.ts
14243
13702
  import { randomUUID as randomUUID4 } from "crypto";
@@ -14836,16 +14295,16 @@ function buildSignedPayload2(timestamp, body) {
14836
14295
  return `${TURN_TIMEOUT_RESUME_HMAC_CONTEXT}:${timestamp}:${body}`;
14837
14296
  }
14838
14297
  function signTurnTimeoutResumeBody(secret, timestamp, body) {
14839
- const digest = createHmac4("sha256", secret).update(buildSignedPayload2(timestamp, body)).digest("hex");
14298
+ const digest = createHmac3("sha256", secret).update(buildSignedPayload2(timestamp, body)).digest("hex");
14840
14299
  return `${TURN_TIMEOUT_RESUME_SIGNATURE_VERSION}=${digest}`;
14841
14300
  }
14842
- function timingSafeMatch4(expected, actual) {
14301
+ function timingSafeMatch3(expected, actual) {
14843
14302
  const expectedBuffer = Buffer.from(expected);
14844
14303
  const actualBuffer = Buffer.from(actual);
14845
14304
  if (expectedBuffer.length !== actualBuffer.length) {
14846
14305
  return false;
14847
14306
  }
14848
- return timingSafeEqual4(expectedBuffer, actualBuffer);
14307
+ return timingSafeEqual3(expectedBuffer, actualBuffer);
14849
14308
  }
14850
14309
  function parseTurnTimeoutResumeRequest(value) {
14851
14310
  if (!value || typeof value !== "object") {
@@ -14900,7 +14359,7 @@ async function verifyTurnTimeoutResumeRequest(request) {
14900
14359
  }
14901
14360
  const body = await request.text();
14902
14361
  const expectedSignature = signTurnTimeoutResumeBody(secret, timestamp, body);
14903
- if (!timingSafeMatch4(expectedSignature, signature)) {
14362
+ if (!timingSafeMatch3(expectedSignature, signature)) {
14904
14363
  return void 0;
14905
14364
  }
14906
14365
  try {
@@ -15402,7 +14861,7 @@ function verifyHeartbeatRequest(request) {
15402
14861
  }
15403
14862
  const actual = Buffer.from(authorization.slice("Bearer ".length));
15404
14863
  const expected = Buffer.from(secret);
15405
- return actual.length === expected.length && timingSafeEqual5(actual, expected);
14864
+ return actual.length === expected.length && timingSafeEqual4(actual, expected);
15406
14865
  }
15407
14866
  async function GET2(request, waitUntil, options = {}) {
15408
14867
  if (!verifyHeartbeatRequest(request)) {
@@ -20630,6 +20089,7 @@ function createReplyToThread(deps) {
20630
20089
  sliceId: 1,
20631
20090
  startedAtMs: message.metadata.dateSent.getTime(),
20632
20091
  state: "running",
20092
+ surface: "slack",
20633
20093
  requester,
20634
20094
  traceId: getActiveTraceId()
20635
20095
  }).catch((error) => {
@@ -20817,6 +20277,7 @@ function createReplyToThread(deps) {
20817
20277
  omittedImageAttachmentCount,
20818
20278
  userAttachments,
20819
20279
  slackConversation,
20280
+ surface: "slack",
20820
20281
  turnDeadlineAtMs: getTurnRequestDeadline()?.deadlineAtMs,
20821
20282
  correlation: {
20822
20283
  conversationId,
@@ -22055,6 +21516,9 @@ function isExternalSlackUser(raw) {
22055
21516
  async function postEphemeral(event, text) {
22056
21517
  await event.channel.postEphemeral(event.user, text, { fallbackToDM: false });
22057
21518
  }
21519
+ function getCommandName() {
21520
+ return getChatConfig().slack.slashCommand;
21521
+ }
22058
21522
  async function handleLink(event, provider) {
22059
21523
  if (!isPluginProvider(provider)) {
22060
21524
  await postEphemeral(event, `Unknown provider: \`${provider}\``);
@@ -22106,7 +21570,7 @@ async function handleUnlink(event, provider) {
22106
21570
  "slash_command_unlink",
22107
21571
  { slackUserId: event.user.userId },
22108
21572
  { "app.credential.provider": provider },
22109
- `Unlinked ${formatProviderLabel(provider)} account via /jr slash command`
21573
+ `Unlinked ${formatProviderLabel(provider)} account via ${getCommandName()} slash command`
22110
21574
  );
22111
21575
  await postEphemeral(
22112
21576
  event,
@@ -22118,12 +21582,15 @@ async function handleSlashCommand(event) {
22118
21582
  if (!subcommand || !["link", "unlink"].includes(subcommand)) {
22119
21583
  await postEphemeral(
22120
21584
  event,
22121
- "Usage: `/jr link <provider>` or `/jr unlink <provider>`"
21585
+ `Usage: \`${getCommandName()} link <provider>\` or \`${getCommandName()} unlink <provider>\``
22122
21586
  );
22123
21587
  return;
22124
21588
  }
22125
21589
  if (!provider || rest.length > 0) {
22126
- await postEphemeral(event, `Usage: \`/jr ${subcommand} <provider>\``);
21590
+ await postEphemeral(
21591
+ event,
21592
+ `Usage: \`${getCommandName()} ${subcommand} <provider>\``
21593
+ );
22127
21594
  return;
22128
21595
  }
22129
21596
  const normalized = provider.toLowerCase();
@@ -23242,16 +22709,16 @@ function mountAgentPluginRoutes(app, routes) {
23242
22709
  async function createApp(options) {
23243
22710
  const virtualConfig = await resolveVirtualConfig();
23244
22711
  const configuredPlugins = options?.plugins ?? virtualConfig?.pluginSet;
23245
- const agentPlugins2 = trustedPluginRegistrationsFromPluginSet(configuredPlugins);
22712
+ const agentPlugins = trustedPluginRegistrationsFromPluginSet(configuredPlugins);
23246
22713
  const pluginConfig = configuredPlugins ? pluginCatalogConfigFromPluginSet(configuredPlugins) : virtualConfig?.plugins ?? resolveEnvPluginCatalogConfig();
23247
22714
  if (configuredPlugins) {
23248
22715
  validateBuildIncludesPluginPackages(pluginConfig, virtualConfig);
23249
22716
  }
23250
- validateBuildIncludesTrustedRegistrations(agentPlugins2, virtualConfig);
23251
- validateAgentPlugins(agentPlugins2);
22717
+ validateBuildIncludesTrustedRegistrations(agentPlugins, virtualConfig);
22718
+ validateAgentPlugins(agentPlugins);
23252
22719
  const shouldValidatePluginCatalog = hasConfiguredPluginCatalog(pluginConfig) || Boolean(configuredPlugins?.registrations.length) || Boolean(Object.keys(options?.configDefaults ?? {}).length);
23253
22720
  const previousPluginCatalogConfig = setPluginCatalogConfig(pluginConfig);
23254
- const previousAgentPlugins = setAgentPlugins(agentPlugins2);
22721
+ const previousAgentPlugins = setAgentPlugins(agentPlugins);
23255
22722
  const previousConfigDefaults = getConfigDefaults();
23256
22723
  let agentPluginRoutes = [];
23257
22724
  try {