@sentry/junior 0.92.0 → 0.93.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/{agent-hooks-BYSSWCNW.js → agent-hooks-ZG7IDOIN.js} +5 -5
  2. package/dist/api/people/list.js +3 -3
  3. package/dist/api/people/profile.js +3 -3
  4. package/dist/app.js +44 -15
  5. package/dist/chat/agent/tools.d.ts +2 -0
  6. package/dist/chat/pi/client.d.ts +1 -1
  7. package/dist/chat/pi/sdk.d.ts +7 -0
  8. package/dist/chat/plugins/agent-hooks.d.ts +2 -0
  9. package/dist/{chunk-H7KUZAMZ.js → chunk-6H4PP63X.js} +2 -2
  10. package/dist/{chunk-ZATRYQLR.js → chunk-7STN2ZSK.js} +1 -1
  11. package/dist/{chunk-OJP53WIU.js → chunk-HDNWZMUN.js} +3 -3
  12. package/dist/{chunk-7DVIELX3.js → chunk-JJUJ4CO2.js} +416 -415
  13. package/dist/{chunk-BMQ5DXHV.js → chunk-LE5ANBUZ.js} +2 -2
  14. package/dist/{chunk-N25HRI6B.js → chunk-LNCREA5Z.js} +2 -2
  15. package/dist/{chunk-ACJENBVF.js → chunk-MAVOJ54A.js} +7 -7
  16. package/dist/{chunk-3F54A3YM.js → chunk-NAPITCZ6.js} +12 -10
  17. package/dist/{chunk-NIFONS4W.js → chunk-NFXSLTYG.js} +1 -1
  18. package/dist/{chunk-TF5VLGA7.js → chunk-QGEWC27H.js} +2 -2
  19. package/dist/{chunk-7FS3K243.js → chunk-QL66APYJ.js} +4 -3
  20. package/dist/{chunk-OZJXGX4U.js → chunk-TNUUATT7.js} +1 -1
  21. package/dist/{chunk-VY7TVOIK.js → chunk-UUB3D2XI.js} +5 -3
  22. package/dist/{chunk-APIVR44P.js → chunk-YJ4OPVNA.js} +1 -1
  23. package/dist/cli/chat.js +13 -13
  24. package/dist/cli/plugins.js +5 -5
  25. package/dist/cli/snapshot-warmup.js +3 -3
  26. package/dist/cli/upgrade.js +5 -5
  27. package/dist/{db-GCK43OO3.js → db-YDN6AFJH.js} +2 -2
  28. package/dist/reporting.js +8 -8
  29. package/dist/{runner-XWTFA26U.js → runner-XAZPJNAQ.js} +8 -8
  30. package/package.json +8 -8
@@ -11,7 +11,7 @@ import {
11
11
  persistRunningSessionRecord,
12
12
  persistTimeoutSessionRecord,
13
13
  persistYieldSessionRecord
14
- } from "./chunk-OJP53WIU.js";
14
+ } from "./chunk-HDNWZMUN.js";
15
15
  import {
16
16
  JUNIOR_THREAD_STATE_TTL_MS
17
17
  } from "./chunk-PFXC67GJ.js";
@@ -23,7 +23,7 @@ import {
23
23
  isSnapshotMissingError,
24
24
  resolveRuntimeDependencySnapshot,
25
25
  runNonInteractiveCommand
26
- } from "./chunk-H7KUZAMZ.js";
26
+ } from "./chunk-6H4PP63X.js";
27
27
  import {
28
28
  JUNIOR_PERSONALITY,
29
29
  buildPluginSystemPromptContributions,
@@ -33,15 +33,17 @@ import {
33
33
  formatSlackLink,
34
34
  isNoReplyMarker,
35
35
  stripNoReplyMarker
36
- } from "./chunk-BMQ5DXHV.js";
36
+ } from "./chunk-LE5ANBUZ.js";
37
37
  import {
38
+ instructionActors,
39
+ instructionProvenanceFor,
38
40
  loadConnectedMcpProviders,
39
41
  recordAuthorizationRequested,
40
42
  recordMcpProviderConnected,
41
43
  recordSubagentEnded,
42
44
  recordSubagentStarted,
43
45
  recordToolExecutionStarted
44
- } from "./chunk-7FS3K243.js";
46
+ } from "./chunk-QL66APYJ.js";
45
47
  import {
46
48
  SlackActionError,
47
49
  createPluginHookRunner,
@@ -58,10 +60,10 @@ import {
58
60
  normalizeSlackConversationId,
59
61
  resolveChannelCapabilities,
60
62
  withSlackRetries
61
- } from "./chunk-VY7TVOIK.js";
63
+ } from "./chunk-UUB3D2XI.js";
62
64
  import {
63
65
  createPluginLogger
64
- } from "./chunk-OZJXGX4U.js";
66
+ } from "./chunk-TNUUATT7.js";
65
67
  import {
66
68
  SANDBOX_DATA_ROOT,
67
69
  SANDBOX_SKILLS_ROOT,
@@ -72,11 +74,11 @@ import {
72
74
  import {
73
75
  acquireActiveLock,
74
76
  getStateAdapter
75
- } from "./chunk-ZATRYQLR.js";
77
+ } from "./chunk-7STN2ZSK.js";
76
78
  import {
77
79
  getConversationStore,
78
80
  getDb
79
- } from "./chunk-NIFONS4W.js";
81
+ } from "./chunk-NFXSLTYG.js";
80
82
  import {
81
83
  GEN_AI_PROVIDER_NAME,
82
84
  GEN_AI_SERVER_ADDRESS,
@@ -101,7 +103,7 @@ import {
101
103
  renderCurrentInstruction,
102
104
  resolveGatewayModel,
103
105
  stripRuntimeTurnContext
104
- } from "./chunk-3F54A3YM.js";
106
+ } from "./chunk-NAPITCZ6.js";
105
107
  import {
106
108
  parseSlackThreadId,
107
109
  resolveConversationPrivacy,
@@ -451,7 +453,7 @@ var SkillSandbox = class {
451
453
  // src/chat/pi/traced-stream.ts
452
454
  import {
453
455
  streamSimple
454
- } from "@earendil-works/pi-ai";
456
+ } from "@earendil-works/pi-ai/compat";
455
457
  function attributeModeForPrivacy(conversationPrivacy) {
456
458
  return conversationPrivacy === "public" ? "content" : "metadata";
457
459
  }
@@ -8077,7 +8079,7 @@ function createWebFetchTool(hooks, options = {}) {
8077
8079
  import { z as z35 } from "zod";
8078
8080
  import { generateText } from "ai";
8079
8081
  import { createGatewayProvider } from "@ai-sdk/gateway";
8080
- import { getModel } from "@earendil-works/pi-ai";
8082
+ import { getModel } from "@earendil-works/pi-ai/compat";
8081
8083
  var SEARCH_TIMEOUT_MS = 6e4;
8082
8084
  var MAX_RESULTS2 = 5;
8083
8085
  var DEFAULT_SEARCH_MODEL = getModel("vercel-ai-gateway", "openai/gpt-5.4").id;
@@ -8668,280 +8670,10 @@ import { PluginToolInputError } from "@sentry/junior-plugin-api";
8668
8670
  // src/chat/services/plugin-auth-orchestration.ts
8669
8671
  import { THREAD_STATE_TTL_MS as THREAD_STATE_TTL_MS2 } from "chat";
8670
8672
 
8671
- // src/chat/mcp/auth-store.ts
8672
- import {
8673
- sourceSchema
8674
- } from "@sentry/junior-plugin-api";
8675
- var MCP_AUTH_SESSION_PREFIX = "junior:mcp_auth_session";
8676
- var MCP_AUTH_CREDENTIALS_PREFIX = "junior:mcp_auth_credentials";
8677
- var MCP_AUTH_SESSION_INDEX_PREFIX = "junior:mcp_auth_session_index";
8678
- var MCP_SERVER_SESSION_PREFIX = "junior:mcp_server_session";
8679
- var MCP_AUTH_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
8680
- var MCP_AUTH_CREDENTIALS_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
8681
- var MCP_SERVER_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
8682
- function sessionKey(authSessionId) {
8683
- return `${MCP_AUTH_SESSION_PREFIX}:${authSessionId}`;
8684
- }
8685
- function credentialsKey(userId, provider) {
8686
- return `${MCP_AUTH_CREDENTIALS_PREFIX}:${userId}:${provider}`;
8687
- }
8688
- function sessionIndexKey(userId, provider) {
8689
- return `${MCP_AUTH_SESSION_INDEX_PREFIX}:${userId}:${provider}`;
8690
- }
8691
- function serverSessionKey(userId, provider) {
8692
- return `${MCP_SERVER_SESSION_PREFIX}:${userId}:${provider}`;
8693
- }
8694
- function parseSessionIndex(value) {
8695
- if (typeof value !== "string") {
8696
- return [];
8697
- }
8698
- try {
8699
- const parsed = JSON.parse(value);
8700
- if (!Array.isArray(parsed)) {
8701
- return [];
8702
- }
8703
- return [
8704
- ...new Set(parsed.filter((id) => typeof id === "string"))
8705
- ];
8706
- } catch {
8707
- return [];
8708
- }
8709
- }
8710
- function parseMcpAuthSession(value) {
8711
- if (typeof value !== "string") {
8712
- return void 0;
8713
- }
8714
- try {
8715
- const parsed = JSON.parse(value);
8716
- if (!isRecord(parsed)) {
8717
- return void 0;
8718
- }
8719
- if (typeof parsed.authSessionId !== "string" || typeof parsed.provider !== "string" || typeof parsed.userId !== "string" || typeof parsed.conversationId !== "string" || typeof parsed.sessionId !== "string" || typeof parsed.userMessage !== "string" || typeof parsed.createdAtMs !== "number" || typeof parsed.updatedAtMs !== "number") {
8720
- return void 0;
8721
- }
8722
- const destination = parsed.destination === void 0 ? void 0 : parseDestination(parsed.destination);
8723
- if (parsed.destination !== void 0 && !destination) {
8724
- return void 0;
8725
- }
8726
- const source = parsed.source === void 0 ? void 0 : sourceSchema.safeParse(parsed.source);
8727
- if (parsed.source !== void 0 && (!source || !source.success)) {
8728
- return void 0;
8729
- }
8730
- return {
8731
- authSessionId: parsed.authSessionId,
8732
- provider: parsed.provider,
8733
- userId: parsed.userId,
8734
- conversationId: parsed.conversationId,
8735
- ...destination ? { destination } : {},
8736
- ...source?.success ? { source: source.data } : {},
8737
- sessionId: parsed.sessionId,
8738
- userMessage: parsed.userMessage,
8739
- createdAtMs: parsed.createdAtMs,
8740
- updatedAtMs: parsed.updatedAtMs,
8741
- ...typeof parsed.channelId === "string" ? { channelId: parsed.channelId } : {},
8742
- ...typeof parsed.threadTs === "string" ? { threadTs: parsed.threadTs } : {},
8743
- ...typeof parsed.toolChannelId === "string" ? { toolChannelId: parsed.toolChannelId } : {},
8744
- ...isRecord(parsed.configuration) ? { configuration: parsed.configuration } : {},
8745
- ...isRecord(parsed.artifactState) ? { artifactState: parsed.artifactState } : {},
8746
- ...typeof parsed.authorizationUrl === "string" ? { authorizationUrl: parsed.authorizationUrl } : {},
8747
- ...typeof parsed.codeVerifier === "string" ? { codeVerifier: parsed.codeVerifier } : {}
8748
- };
8749
- } catch {
8750
- return void 0;
8751
- }
8752
- }
8753
- function parseServerSession(value) {
8754
- if (typeof value !== "string") {
8755
- return void 0;
8756
- }
8757
- try {
8758
- const parsed = JSON.parse(value);
8759
- if (!isRecord(parsed) || typeof parsed.sessionId !== "string" || typeof parsed.updatedAtMs !== "number") {
8760
- return void 0;
8761
- }
8762
- return {
8763
- sessionId: parsed.sessionId,
8764
- updatedAtMs: parsed.updatedAtMs
8765
- };
8766
- } catch {
8767
- return void 0;
8768
- }
8769
- }
8770
- function parseStoredCredentials(value) {
8771
- if (typeof value !== "string") {
8772
- return void 0;
8773
- }
8774
- try {
8775
- const parsed = JSON.parse(value);
8776
- if (!isRecord(parsed)) {
8777
- return void 0;
8778
- }
8779
- return {
8780
- ...isRecord(parsed.clientInformation) ? {
8781
- clientInformation: parsed.clientInformation
8782
- } : {},
8783
- ...isRecord(parsed.discoveryState) ? {
8784
- discoveryState: parsed.discoveryState
8785
- } : {},
8786
- ...isRecord(parsed.tokens) ? { tokens: parsed.tokens } : {}
8787
- };
8788
- } catch {
8789
- return void 0;
8790
- }
8791
- }
8792
- async function getConnectedStateAdapter() {
8793
- const stateAdapter = getStateAdapter();
8794
- await stateAdapter.connect();
8795
- return stateAdapter;
8796
- }
8797
- async function getMcpAuthSession(authSessionId) {
8798
- const stateAdapter = await getConnectedStateAdapter();
8799
- return parseMcpAuthSession(await stateAdapter.get(sessionKey(authSessionId)));
8800
- }
8801
- async function putMcpAuthSession(session, ttlMs2 = MCP_AUTH_SESSION_TTL_MS) {
8802
- const stateAdapter = await getConnectedStateAdapter();
8803
- await stateAdapter.set(
8804
- sessionKey(session.authSessionId),
8805
- JSON.stringify(session),
8806
- ttlMs2
8807
- );
8808
- const nextIndex = parseSessionIndex(
8809
- await stateAdapter.get(sessionIndexKey(session.userId, session.provider))
8810
- );
8811
- if (!nextIndex.includes(session.authSessionId)) {
8812
- nextIndex.push(session.authSessionId);
8813
- }
8814
- await stateAdapter.set(
8815
- sessionIndexKey(session.userId, session.provider),
8816
- JSON.stringify(nextIndex),
8817
- ttlMs2
8818
- );
8819
- }
8820
- async function patchMcpAuthSession(authSessionId, patch) {
8821
- const current = await getMcpAuthSession(authSessionId);
8822
- if (!current) {
8823
- throw new Error(`Unknown MCP auth session: ${authSessionId}`);
8824
- }
8825
- const next = {
8826
- ...current,
8827
- ...patch,
8828
- authSessionId: current.authSessionId,
8829
- provider: current.provider,
8830
- userId: current.userId,
8831
- conversationId: current.conversationId,
8832
- ...current.destination ? { destination: current.destination } : {},
8833
- sessionId: current.sessionId,
8834
- userMessage: current.userMessage,
8835
- createdAtMs: current.createdAtMs,
8836
- updatedAtMs: Date.now()
8837
- };
8838
- await putMcpAuthSession(next);
8839
- return next;
8840
- }
8841
- async function deleteMcpAuthSession(authSessionId) {
8842
- const stateAdapter = await getConnectedStateAdapter();
8843
- const current = parseMcpAuthSession(
8844
- await stateAdapter.get(sessionKey(authSessionId))
8845
- );
8846
- await stateAdapter.delete(sessionKey(authSessionId));
8847
- if (!current) {
8848
- return;
8849
- }
8850
- const nextIndex = parseSessionIndex(
8851
- await stateAdapter.get(sessionIndexKey(current.userId, current.provider))
8852
- ).filter((id) => id !== authSessionId);
8853
- if (nextIndex.length > 0) {
8854
- await stateAdapter.set(
8855
- sessionIndexKey(current.userId, current.provider),
8856
- JSON.stringify(nextIndex),
8857
- MCP_AUTH_SESSION_TTL_MS
8858
- );
8859
- return;
8860
- }
8861
- await stateAdapter.delete(sessionIndexKey(current.userId, current.provider));
8862
- }
8863
- async function deleteMcpAuthSessionsForUserProvider(userId, provider) {
8864
- const stateAdapter = await getConnectedStateAdapter();
8865
- const indexKey = sessionIndexKey(userId, provider);
8866
- const authSessionIds = parseSessionIndex(await stateAdapter.get(indexKey));
8867
- for (const authSessionId of authSessionIds) {
8868
- await stateAdapter.delete(sessionKey(authSessionId));
8869
- }
8870
- await stateAdapter.delete(indexKey);
8871
- }
8872
- async function getLatestMcpAuthSessionForUserProvider(userId, provider) {
8873
- const stateAdapter = await getConnectedStateAdapter();
8874
- const authSessionIds = parseSessionIndex(
8875
- await stateAdapter.get(sessionIndexKey(userId, provider))
8876
- );
8877
- let latestSession;
8878
- for (const authSessionId of authSessionIds) {
8879
- const session = parseMcpAuthSession(
8880
- await stateAdapter.get(sessionKey(authSessionId))
8881
- );
8882
- if (!session) {
8883
- continue;
8884
- }
8885
- if (!latestSession || session.updatedAtMs > latestSession.updatedAtMs) {
8886
- latestSession = session;
8887
- }
8888
- }
8889
- return latestSession;
8890
- }
8891
- async function getMcpStoredOAuthCredentials(userId, provider) {
8892
- const stateAdapter = await getConnectedStateAdapter();
8893
- return parseStoredCredentials(
8894
- await stateAdapter.get(credentialsKey(userId, provider))
8895
- );
8896
- }
8897
- async function putMcpStoredOAuthCredentials(userId, provider, value, ttlMs2 = MCP_AUTH_CREDENTIALS_TTL_MS) {
8898
- const stateAdapter = await getConnectedStateAdapter();
8899
- await stateAdapter.set(
8900
- credentialsKey(userId, provider),
8901
- JSON.stringify(value),
8902
- ttlMs2
8903
- );
8904
- }
8905
- async function deleteMcpStoredOAuthCredentials(userId, provider) {
8906
- const stateAdapter = await getConnectedStateAdapter();
8907
- await stateAdapter.delete(credentialsKey(userId, provider));
8908
- }
8909
- async function getMcpServerSessionId(userId, provider) {
8910
- const stateAdapter = await getConnectedStateAdapter();
8911
- return parseServerSession(
8912
- await stateAdapter.get(serverSessionKey(userId, provider))
8913
- )?.sessionId;
8914
- }
8915
- async function putMcpServerSessionId(userId, provider, sessionId, ttlMs2 = MCP_SERVER_SESSION_TTL_MS) {
8916
- const stateAdapter = await getConnectedStateAdapter();
8917
- await stateAdapter.set(
8918
- serverSessionKey(userId, provider),
8919
- JSON.stringify({
8920
- sessionId,
8921
- updatedAtMs: Date.now()
8922
- }),
8923
- ttlMs2
8924
- );
8925
- }
8926
- async function deleteMcpServerSessionId(userId, provider) {
8927
- const stateAdapter = await getConnectedStateAdapter();
8928
- await stateAdapter.delete(serverSessionKey(userId, provider));
8929
- }
8930
-
8931
- // src/chat/credentials/unlink-provider.ts
8932
- async function unlinkProvider(userId, provider, userTokenStore) {
8933
- await Promise.all([
8934
- userTokenStore.delete(userId, provider),
8935
- deleteMcpStoredOAuthCredentials(userId, provider),
8936
- deleteMcpServerSessionId(userId, provider),
8937
- deleteMcpAuthSessionsForUserProvider(userId, provider)
8938
- ]);
8939
- }
8940
-
8941
8673
  // src/chat/oauth-flow.ts
8942
8674
  import { randomBytes } from "crypto";
8943
8675
  import {
8944
- sourceSchema as sourceSchema2
8676
+ sourceSchema
8945
8677
  } from "@sentry/junior-plugin-api";
8946
8678
 
8947
8679
  // src/chat/oauth-authorization-message.ts
@@ -8965,7 +8697,7 @@ function parseOAuthStatePayload(value) {
8965
8697
  if (value.destination !== void 0 && !destination) {
8966
8698
  return void 0;
8967
8699
  }
8968
- const source = value.source === void 0 ? void 0 : sourceSchema2.safeParse(value.source);
8700
+ const source = value.source === void 0 ? void 0 : sourceSchema.safeParse(value.source);
8969
8701
  if (value.source !== void 0 && (!source || !source.success)) {
8970
8702
  return void 0;
8971
8703
  }
@@ -9306,9 +9038,6 @@ function createPluginAuthOrchestration(input) {
9306
9038
  );
9307
9039
  }
9308
9040
  }
9309
- if (options?.unlinkExistingProvider && input.actorId && input.userTokenStore) {
9310
- await unlinkProvider(input.actorId, provider, input.userTokenStore);
9311
- }
9312
9041
  if (input.sessionId && recordPendingAuth) {
9313
9042
  await recordPendingAuth({
9314
9043
  kind: "plugin",
@@ -9376,10 +9105,10 @@ function createPluginAuthOrchestration(input) {
9376
9105
  signal.message ?? `${formatProviderLabel(provider)} credentials are required but the provider is not configured for OAuth.`
9377
9106
  );
9378
9107
  }
9379
- await startAuthorizationPause(authorization.provider, {
9380
- ...authorization.scope ? { scope: authorization.scope } : {},
9381
- unlinkExistingProvider: true
9382
- });
9108
+ await startAuthorizationPause(
9109
+ authorization.provider,
9110
+ authorization.scope ? { scope: authorization.scope } : void 0
9111
+ );
9383
9112
  },
9384
9113
  getPendingPause: () => pendingPause
9385
9114
  };
@@ -11704,132 +11433,392 @@ function createSandboxExecutor(options) {
11704
11433
  );
11705
11434
  return { result };
11706
11435
  };
11707
- const executeFindFilesTool = async (rawInput) => {
11708
- const pattern = String(rawInput.pattern ?? "");
11709
- if (!pattern) {
11710
- throw new ToolInputError("pattern is required");
11711
- }
11712
- logSandboxBootRequest("tool.findFiles");
11713
- const limit = positiveInteger(rawInput.limit);
11714
- const executors = await sessionManager.ensureToolExecutors();
11715
- const result = await withSandboxToolSpan(
11716
- "sandbox.findFiles",
11717
- "sandbox.fs.find",
11718
- {
11719
- "app.sandbox.pattern.length": pattern.length
11720
- },
11721
- async () => {
11722
- const response = await findFiles({
11723
- fs: executors.fs,
11724
- pattern,
11725
- ...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
11726
- ...limit ? { limit } : {}
11727
- });
11728
- setSpanStatus("ok");
11729
- return response;
11730
- }
11436
+ const executeFindFilesTool = async (rawInput) => {
11437
+ const pattern = String(rawInput.pattern ?? "");
11438
+ if (!pattern) {
11439
+ throw new ToolInputError("pattern is required");
11440
+ }
11441
+ logSandboxBootRequest("tool.findFiles");
11442
+ const limit = positiveInteger(rawInput.limit);
11443
+ const executors = await sessionManager.ensureToolExecutors();
11444
+ const result = await withSandboxToolSpan(
11445
+ "sandbox.findFiles",
11446
+ "sandbox.fs.find",
11447
+ {
11448
+ "app.sandbox.pattern.length": pattern.length
11449
+ },
11450
+ async () => {
11451
+ const response = await findFiles({
11452
+ fs: executors.fs,
11453
+ pattern,
11454
+ ...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
11455
+ ...limit ? { limit } : {}
11456
+ });
11457
+ setSpanStatus("ok");
11458
+ return response;
11459
+ }
11460
+ );
11461
+ return { result };
11462
+ };
11463
+ const executeListDirTool = async (rawInput) => {
11464
+ logSandboxBootRequest("tool.listDir");
11465
+ const limit = positiveInteger(rawInput.limit);
11466
+ const executors = await sessionManager.ensureToolExecutors();
11467
+ const result = await withSandboxToolSpan(
11468
+ "sandbox.listDir",
11469
+ "sandbox.fs.list",
11470
+ {},
11471
+ async () => {
11472
+ const response = await listDir({
11473
+ fs: executors.fs,
11474
+ ...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
11475
+ ...limit ? { limit } : {}
11476
+ });
11477
+ setSpanStatus("ok");
11478
+ return response;
11479
+ }
11480
+ );
11481
+ return { result };
11482
+ };
11483
+ const execute = async (params) => {
11484
+ const rawInput = params.input ?? {};
11485
+ const bashCommand = params.toolName === "bash" ? String(rawInput.command ?? "").trim() : void 0;
11486
+ if (params.toolName === "bash") {
11487
+ if (!bashCommand) {
11488
+ throw new ToolInputError("command is required");
11489
+ }
11490
+ if (options?.runBashCustomCommand) {
11491
+ const custom = await options.runBashCustomCommand(bashCommand);
11492
+ if (custom.handled) {
11493
+ if (!custom.result) {
11494
+ throw new Error("Custom bash command handler returned no result.");
11495
+ }
11496
+ return { result: bashToolResult(custom.result) };
11497
+ }
11498
+ }
11499
+ return await executeBashTool(rawInput, bashCommand, params.signal);
11500
+ }
11501
+ try {
11502
+ if (params.toolName === "readFile") {
11503
+ return await executeReadFileTool(rawInput);
11504
+ }
11505
+ if (params.toolName === "editFile") {
11506
+ return await executeEditFileTool(rawInput);
11507
+ }
11508
+ if (params.toolName === "grep") {
11509
+ return await executeGrepTool(rawInput);
11510
+ }
11511
+ if (params.toolName === "findFiles") {
11512
+ return await executeFindFilesTool(rawInput);
11513
+ }
11514
+ if (params.toolName === "listDir") {
11515
+ return await executeListDirTool(rawInput);
11516
+ }
11517
+ if (params.toolName === "writeFile") {
11518
+ return await executeWriteFileTool(rawInput);
11519
+ }
11520
+ } catch (error) {
11521
+ if (!isSandboxCommandStreamInterruptedError(error)) {
11522
+ throw error;
11523
+ }
11524
+ return { result: sandboxStreamInterruptedResult(params.toolName) };
11525
+ }
11526
+ throw new Error(`unsupported sandbox tool: ${params.toolName}`);
11527
+ };
11528
+ return {
11529
+ configureSkills(skills) {
11530
+ availableSkills = [...skills];
11531
+ sessionManager.configureSkills(skills);
11532
+ },
11533
+ configureReferenceFiles(files) {
11534
+ referenceFiles = [...files];
11535
+ sessionManager.configureReferenceFiles(files);
11536
+ },
11537
+ getSandboxId() {
11538
+ return sessionManager.getSandboxId();
11539
+ },
11540
+ getDependencyProfileHash() {
11541
+ return sessionManager.getDependencyProfileHash();
11542
+ },
11543
+ canExecute(toolName) {
11544
+ return SANDBOX_TOOL_NAMES.has(toolName);
11545
+ },
11546
+ async createSandbox() {
11547
+ return await sessionManager.createSandbox();
11548
+ },
11549
+ execute,
11550
+ async dispose() {
11551
+ await sessionManager.dispose();
11552
+ }
11553
+ };
11554
+ }
11555
+
11556
+ // src/chat/services/mcp-auth-orchestration.ts
11557
+ import { THREAD_STATE_TTL_MS as THREAD_STATE_TTL_MS3 } from "chat";
11558
+
11559
+ // src/chat/mcp/oauth.ts
11560
+ import { randomUUID as randomUUID3 } from "crypto";
11561
+ import { StreamableHTTPClientTransport as StreamableHTTPClientTransport2 } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
11562
+
11563
+ // src/chat/mcp/auth-store.ts
11564
+ import {
11565
+ sourceSchema as sourceSchema2
11566
+ } from "@sentry/junior-plugin-api";
11567
+ var MCP_AUTH_SESSION_PREFIX = "junior:mcp_auth_session";
11568
+ var MCP_AUTH_CREDENTIALS_PREFIX = "junior:mcp_auth_credentials";
11569
+ var MCP_AUTH_SESSION_INDEX_PREFIX = "junior:mcp_auth_session_index";
11570
+ var MCP_SERVER_SESSION_PREFIX = "junior:mcp_server_session";
11571
+ var MCP_AUTH_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
11572
+ var MCP_AUTH_CREDENTIALS_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
11573
+ var MCP_SERVER_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
11574
+ function sessionKey(authSessionId) {
11575
+ return `${MCP_AUTH_SESSION_PREFIX}:${authSessionId}`;
11576
+ }
11577
+ function credentialsKey(userId, provider) {
11578
+ return `${MCP_AUTH_CREDENTIALS_PREFIX}:${userId}:${provider}`;
11579
+ }
11580
+ function sessionIndexKey(userId, provider) {
11581
+ return `${MCP_AUTH_SESSION_INDEX_PREFIX}:${userId}:${provider}`;
11582
+ }
11583
+ function serverSessionKey(userId, provider) {
11584
+ return `${MCP_SERVER_SESSION_PREFIX}:${userId}:${provider}`;
11585
+ }
11586
+ function parseSessionIndex(value) {
11587
+ if (typeof value !== "string") {
11588
+ return [];
11589
+ }
11590
+ try {
11591
+ const parsed = JSON.parse(value);
11592
+ if (!Array.isArray(parsed)) {
11593
+ return [];
11594
+ }
11595
+ return [
11596
+ ...new Set(parsed.filter((id) => typeof id === "string"))
11597
+ ];
11598
+ } catch {
11599
+ return [];
11600
+ }
11601
+ }
11602
+ function parseMcpAuthSession(value) {
11603
+ if (typeof value !== "string") {
11604
+ return void 0;
11605
+ }
11606
+ try {
11607
+ const parsed = JSON.parse(value);
11608
+ if (!isRecord(parsed)) {
11609
+ return void 0;
11610
+ }
11611
+ if (typeof parsed.authSessionId !== "string" || typeof parsed.provider !== "string" || typeof parsed.userId !== "string" || typeof parsed.conversationId !== "string" || typeof parsed.sessionId !== "string" || typeof parsed.userMessage !== "string" || typeof parsed.createdAtMs !== "number" || typeof parsed.updatedAtMs !== "number") {
11612
+ return void 0;
11613
+ }
11614
+ const destination = parsed.destination === void 0 ? void 0 : parseDestination(parsed.destination);
11615
+ if (parsed.destination !== void 0 && !destination) {
11616
+ return void 0;
11617
+ }
11618
+ const source = parsed.source === void 0 ? void 0 : sourceSchema2.safeParse(parsed.source);
11619
+ if (parsed.source !== void 0 && (!source || !source.success)) {
11620
+ return void 0;
11621
+ }
11622
+ return {
11623
+ authSessionId: parsed.authSessionId,
11624
+ provider: parsed.provider,
11625
+ userId: parsed.userId,
11626
+ conversationId: parsed.conversationId,
11627
+ ...destination ? { destination } : {},
11628
+ ...source?.success ? { source: source.data } : {},
11629
+ sessionId: parsed.sessionId,
11630
+ userMessage: parsed.userMessage,
11631
+ createdAtMs: parsed.createdAtMs,
11632
+ updatedAtMs: parsed.updatedAtMs,
11633
+ ...typeof parsed.channelId === "string" ? { channelId: parsed.channelId } : {},
11634
+ ...typeof parsed.threadTs === "string" ? { threadTs: parsed.threadTs } : {},
11635
+ ...typeof parsed.toolChannelId === "string" ? { toolChannelId: parsed.toolChannelId } : {},
11636
+ ...isRecord(parsed.configuration) ? { configuration: parsed.configuration } : {},
11637
+ ...isRecord(parsed.artifactState) ? { artifactState: parsed.artifactState } : {},
11638
+ ...typeof parsed.authorizationUrl === "string" ? { authorizationUrl: parsed.authorizationUrl } : {},
11639
+ ...typeof parsed.codeVerifier === "string" ? { codeVerifier: parsed.codeVerifier } : {}
11640
+ };
11641
+ } catch {
11642
+ return void 0;
11643
+ }
11644
+ }
11645
+ function parseServerSession(value) {
11646
+ if (typeof value !== "string") {
11647
+ return void 0;
11648
+ }
11649
+ try {
11650
+ const parsed = JSON.parse(value);
11651
+ if (!isRecord(parsed) || typeof parsed.sessionId !== "string" || typeof parsed.updatedAtMs !== "number") {
11652
+ return void 0;
11653
+ }
11654
+ return {
11655
+ sessionId: parsed.sessionId,
11656
+ updatedAtMs: parsed.updatedAtMs
11657
+ };
11658
+ } catch {
11659
+ return void 0;
11660
+ }
11661
+ }
11662
+ function parseStoredCredentials(value) {
11663
+ if (typeof value !== "string") {
11664
+ return void 0;
11665
+ }
11666
+ try {
11667
+ const parsed = JSON.parse(value);
11668
+ if (!isRecord(parsed)) {
11669
+ return void 0;
11670
+ }
11671
+ return {
11672
+ ...isRecord(parsed.clientInformation) ? {
11673
+ clientInformation: parsed.clientInformation
11674
+ } : {},
11675
+ ...isRecord(parsed.discoveryState) ? {
11676
+ discoveryState: parsed.discoveryState
11677
+ } : {},
11678
+ ...isRecord(parsed.tokens) ? { tokens: parsed.tokens } : {}
11679
+ };
11680
+ } catch {
11681
+ return void 0;
11682
+ }
11683
+ }
11684
+ async function getConnectedStateAdapter() {
11685
+ const stateAdapter = getStateAdapter();
11686
+ await stateAdapter.connect();
11687
+ return stateAdapter;
11688
+ }
11689
+ async function getMcpAuthSession(authSessionId) {
11690
+ const stateAdapter = await getConnectedStateAdapter();
11691
+ return parseMcpAuthSession(await stateAdapter.get(sessionKey(authSessionId)));
11692
+ }
11693
+ async function putMcpAuthSession(session, ttlMs2 = MCP_AUTH_SESSION_TTL_MS) {
11694
+ const stateAdapter = await getConnectedStateAdapter();
11695
+ await stateAdapter.set(
11696
+ sessionKey(session.authSessionId),
11697
+ JSON.stringify(session),
11698
+ ttlMs2
11699
+ );
11700
+ const nextIndex = parseSessionIndex(
11701
+ await stateAdapter.get(sessionIndexKey(session.userId, session.provider))
11702
+ );
11703
+ if (!nextIndex.includes(session.authSessionId)) {
11704
+ nextIndex.push(session.authSessionId);
11705
+ }
11706
+ await stateAdapter.set(
11707
+ sessionIndexKey(session.userId, session.provider),
11708
+ JSON.stringify(nextIndex),
11709
+ ttlMs2
11710
+ );
11711
+ }
11712
+ async function patchMcpAuthSession(authSessionId, patch) {
11713
+ const current = await getMcpAuthSession(authSessionId);
11714
+ if (!current) {
11715
+ throw new Error(`Unknown MCP auth session: ${authSessionId}`);
11716
+ }
11717
+ const next = {
11718
+ ...current,
11719
+ ...patch,
11720
+ authSessionId: current.authSessionId,
11721
+ provider: current.provider,
11722
+ userId: current.userId,
11723
+ conversationId: current.conversationId,
11724
+ ...current.destination ? { destination: current.destination } : {},
11725
+ sessionId: current.sessionId,
11726
+ userMessage: current.userMessage,
11727
+ createdAtMs: current.createdAtMs,
11728
+ updatedAtMs: Date.now()
11729
+ };
11730
+ await putMcpAuthSession(next);
11731
+ return next;
11732
+ }
11733
+ async function deleteMcpAuthSession(authSessionId) {
11734
+ const stateAdapter = await getConnectedStateAdapter();
11735
+ const current = parseMcpAuthSession(
11736
+ await stateAdapter.get(sessionKey(authSessionId))
11737
+ );
11738
+ await stateAdapter.delete(sessionKey(authSessionId));
11739
+ if (!current) {
11740
+ return;
11741
+ }
11742
+ const nextIndex = parseSessionIndex(
11743
+ await stateAdapter.get(sessionIndexKey(current.userId, current.provider))
11744
+ ).filter((id) => id !== authSessionId);
11745
+ if (nextIndex.length > 0) {
11746
+ await stateAdapter.set(
11747
+ sessionIndexKey(current.userId, current.provider),
11748
+ JSON.stringify(nextIndex),
11749
+ MCP_AUTH_SESSION_TTL_MS
11731
11750
  );
11732
- return { result };
11733
- };
11734
- const executeListDirTool = async (rawInput) => {
11735
- logSandboxBootRequest("tool.listDir");
11736
- const limit = positiveInteger(rawInput.limit);
11737
- const executors = await sessionManager.ensureToolExecutors();
11738
- const result = await withSandboxToolSpan(
11739
- "sandbox.listDir",
11740
- "sandbox.fs.list",
11741
- {},
11742
- async () => {
11743
- const response = await listDir({
11744
- fs: executors.fs,
11745
- ...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
11746
- ...limit ? { limit } : {}
11747
- });
11748
- setSpanStatus("ok");
11749
- return response;
11750
- }
11751
+ return;
11752
+ }
11753
+ await stateAdapter.delete(sessionIndexKey(current.userId, current.provider));
11754
+ }
11755
+ async function deleteMcpAuthSessionsForUserProvider(userId, provider) {
11756
+ const stateAdapter = await getConnectedStateAdapter();
11757
+ const indexKey = sessionIndexKey(userId, provider);
11758
+ const authSessionIds = parseSessionIndex(await stateAdapter.get(indexKey));
11759
+ for (const authSessionId of authSessionIds) {
11760
+ await stateAdapter.delete(sessionKey(authSessionId));
11761
+ }
11762
+ await stateAdapter.delete(indexKey);
11763
+ }
11764
+ async function getLatestMcpAuthSessionForUserProvider(userId, provider) {
11765
+ const stateAdapter = await getConnectedStateAdapter();
11766
+ const authSessionIds = parseSessionIndex(
11767
+ await stateAdapter.get(sessionIndexKey(userId, provider))
11768
+ );
11769
+ let latestSession;
11770
+ for (const authSessionId of authSessionIds) {
11771
+ const session = parseMcpAuthSession(
11772
+ await stateAdapter.get(sessionKey(authSessionId))
11751
11773
  );
11752
- return { result };
11753
- };
11754
- const execute = async (params) => {
11755
- const rawInput = params.input ?? {};
11756
- const bashCommand = params.toolName === "bash" ? String(rawInput.command ?? "").trim() : void 0;
11757
- if (params.toolName === "bash") {
11758
- if (!bashCommand) {
11759
- throw new ToolInputError("command is required");
11760
- }
11761
- if (options?.runBashCustomCommand) {
11762
- const custom = await options.runBashCustomCommand(bashCommand);
11763
- if (custom.handled) {
11764
- if (!custom.result) {
11765
- throw new Error("Custom bash command handler returned no result.");
11766
- }
11767
- return { result: bashToolResult(custom.result) };
11768
- }
11769
- }
11770
- return await executeBashTool(rawInput, bashCommand, params.signal);
11771
- }
11772
- try {
11773
- if (params.toolName === "readFile") {
11774
- return await executeReadFileTool(rawInput);
11775
- }
11776
- if (params.toolName === "editFile") {
11777
- return await executeEditFileTool(rawInput);
11778
- }
11779
- if (params.toolName === "grep") {
11780
- return await executeGrepTool(rawInput);
11781
- }
11782
- if (params.toolName === "findFiles") {
11783
- return await executeFindFilesTool(rawInput);
11784
- }
11785
- if (params.toolName === "listDir") {
11786
- return await executeListDirTool(rawInput);
11787
- }
11788
- if (params.toolName === "writeFile") {
11789
- return await executeWriteFileTool(rawInput);
11790
- }
11791
- } catch (error) {
11792
- if (!isSandboxCommandStreamInterruptedError(error)) {
11793
- throw error;
11794
- }
11795
- return { result: sandboxStreamInterruptedResult(params.toolName) };
11774
+ if (!session) {
11775
+ continue;
11796
11776
  }
11797
- throw new Error(`unsupported sandbox tool: ${params.toolName}`);
11798
- };
11799
- return {
11800
- configureSkills(skills) {
11801
- availableSkills = [...skills];
11802
- sessionManager.configureSkills(skills);
11803
- },
11804
- configureReferenceFiles(files) {
11805
- referenceFiles = [...files];
11806
- sessionManager.configureReferenceFiles(files);
11807
- },
11808
- getSandboxId() {
11809
- return sessionManager.getSandboxId();
11810
- },
11811
- getDependencyProfileHash() {
11812
- return sessionManager.getDependencyProfileHash();
11813
- },
11814
- canExecute(toolName) {
11815
- return SANDBOX_TOOL_NAMES.has(toolName);
11816
- },
11817
- async createSandbox() {
11818
- return await sessionManager.createSandbox();
11819
- },
11820
- execute,
11821
- async dispose() {
11822
- await sessionManager.dispose();
11777
+ if (!latestSession || session.updatedAtMs > latestSession.updatedAtMs) {
11778
+ latestSession = session;
11823
11779
  }
11824
- };
11780
+ }
11781
+ return latestSession;
11782
+ }
11783
+ async function getMcpStoredOAuthCredentials(userId, provider) {
11784
+ const stateAdapter = await getConnectedStateAdapter();
11785
+ return parseStoredCredentials(
11786
+ await stateAdapter.get(credentialsKey(userId, provider))
11787
+ );
11788
+ }
11789
+ async function putMcpStoredOAuthCredentials(userId, provider, value, ttlMs2 = MCP_AUTH_CREDENTIALS_TTL_MS) {
11790
+ const stateAdapter = await getConnectedStateAdapter();
11791
+ await stateAdapter.set(
11792
+ credentialsKey(userId, provider),
11793
+ JSON.stringify(value),
11794
+ ttlMs2
11795
+ );
11796
+ }
11797
+ async function deleteMcpStoredOAuthCredentials(userId, provider) {
11798
+ const stateAdapter = await getConnectedStateAdapter();
11799
+ await stateAdapter.delete(credentialsKey(userId, provider));
11800
+ }
11801
+ async function getMcpServerSessionId(userId, provider) {
11802
+ const stateAdapter = await getConnectedStateAdapter();
11803
+ return parseServerSession(
11804
+ await stateAdapter.get(serverSessionKey(userId, provider))
11805
+ )?.sessionId;
11806
+ }
11807
+ async function putMcpServerSessionId(userId, provider, sessionId, ttlMs2 = MCP_SERVER_SESSION_TTL_MS) {
11808
+ const stateAdapter = await getConnectedStateAdapter();
11809
+ await stateAdapter.set(
11810
+ serverSessionKey(userId, provider),
11811
+ JSON.stringify({
11812
+ sessionId,
11813
+ updatedAtMs: Date.now()
11814
+ }),
11815
+ ttlMs2
11816
+ );
11817
+ }
11818
+ async function deleteMcpServerSessionId(userId, provider) {
11819
+ const stateAdapter = await getConnectedStateAdapter();
11820
+ await stateAdapter.delete(serverSessionKey(userId, provider));
11825
11821
  }
11826
-
11827
- // src/chat/services/mcp-auth-orchestration.ts
11828
- import { THREAD_STATE_TTL_MS as THREAD_STATE_TTL_MS3 } from "chat";
11829
-
11830
- // src/chat/mcp/oauth.ts
11831
- import { randomUUID as randomUUID3 } from "crypto";
11832
- import { StreamableHTTPClientTransport as StreamableHTTPClientTransport2 } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
11833
11822
 
11834
11823
  // src/chat/mcp/oauth-provider.ts
11835
11824
  function createClientMetadata(callbackUrl) {
@@ -13358,7 +13347,8 @@ async function wireAgentTools(args) {
13358
13347
  const authActorId = args.routing.credentialContext && "type" in args.routing.credentialContext.actor ? args.routing.credentialContext.actor.userId : void 0;
13359
13348
  const userTokenStore = createUserTokenStore();
13360
13349
  const pluginHooks = createPluginHookRunner({
13361
- actor: args.currentActor
13350
+ actor: args.currentActor,
13351
+ actors: args.currentActors
13362
13352
  });
13363
13353
  const sandboxExecutor = createSandboxExecutor({
13364
13354
  sandboxId: args.state.sandbox?.sandboxId,
@@ -14002,6 +13992,11 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
14002
13992
  currentSliceId,
14003
13993
  existingSessionRecord
14004
13994
  } = await restoreSessionRecord(routing);
13995
+ const committedInstructionProvenance = existingSessionRecord?.piMessageProvenance ? [
13996
+ ...existingSessionRecord.piMessageProvenance,
13997
+ ...resumedFromSessionRecord ? [] : [instructionProvenanceFor(actor)]
13998
+ ] : [instructionProvenanceFor(actor)];
13999
+ const runActors = () => instructionActors(committedInstructionProvenance);
14005
14000
  canRecordMcpProviders = Boolean(
14006
14001
  sessionRecordState.canUseTurnSession && sessionConversationId && sessionId
14007
14002
  );
@@ -14107,6 +14102,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
14107
14102
  abortAgent: () => agent?.abort(),
14108
14103
  activeSkills,
14109
14104
  currentActor: actor,
14105
+ currentActors: runActors,
14110
14106
  artifactStatePatch,
14111
14107
  availableSkills,
14112
14108
  configurationValues,
@@ -14181,6 +14177,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
14181
14177
  [...agent.state.messages, ...piMessages],
14182
14178
  messages.map((message) => message.provenance)
14183
14179
  );
14180
+ committedInstructionProvenance.push(
14181
+ ...messages.map((message) => message.provenance)
14182
+ );
14184
14183
  for (const message of piMessages) {
14185
14184
  agent.steer(message);
14186
14185
  }
@@ -14583,9 +14582,6 @@ export {
14583
14582
  removeReactionFromMessage,
14584
14583
  renderSlackLegacyAttachmentText,
14585
14584
  appendSlackLegacyAttachmentText,
14586
- deleteMcpAuthSession,
14587
- getMcpStoredOAuthCredentials,
14588
- unlinkProvider,
14589
14585
  parseOAuthStatePayload,
14590
14586
  formatProviderLabel,
14591
14587
  resolveBaseUrl,
@@ -14596,6 +14592,11 @@ export {
14596
14592
  normalizeSandboxEgressTracePropagationDomains,
14597
14593
  shouldPropagateSandboxEgressTrace,
14598
14594
  resolveSandboxEgressProviderForHost,
14595
+ deleteMcpAuthSession,
14596
+ deleteMcpAuthSessionsForUserProvider,
14597
+ getMcpStoredOAuthCredentials,
14598
+ deleteMcpStoredOAuthCredentials,
14599
+ deleteMcpServerSessionId,
14599
14600
  finalizeMcpAuthorization,
14600
14601
  resolvePluginOAuthAccount,
14601
14602
  executeCredentialedEgressRequest,