@sentry/junior 0.268.0 → 0.270.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 (83) hide show
  1. package/README.md +2 -9
  2. package/dist/{adapter-04AcD2SO.js → adapter-BQNTKVTF.js} +3 -49
  3. package/dist/{admin-DIU1QyG3.js → admin-CKVEoXa4.js} +1 -1
  4. package/dist/{agent-runner-CAYfFmU7.js → agent-runner-MSQSMFkq.js} +4538 -3251
  5. package/dist/api/schema.d.ts +2 -3
  6. package/dist/api/schema.js +7 -7
  7. package/dist/api.d.ts +3 -1
  8. package/dist/api.js +190 -301
  9. package/dist/{app-z6Uuyq3j.d.ts → app-Bz8t4P8p.d.ts} +9 -3
  10. package/dist/app.d.ts +1 -1
  11. package/dist/app.js +129 -209
  12. package/dist/{automation-CmeFBSEh.js → automation-Dwh_xcqM.js} +74 -74
  13. package/dist/{briefs-DQbV2jNr.js → briefs-DNFzFFVx.js} +5 -5
  14. package/dist/{catalog-runtime-BD9GSpc6.js → catalog-runtime-Bdym_wKy.js} +1 -1
  15. package/dist/cli/chat.js +16 -26
  16. package/dist/cli/check.js +3 -3
  17. package/dist/cli/main.js +5 -3
  18. package/dist/cli/plugins.js +4 -4
  19. package/dist/cli/snapshot-create.js +4 -4
  20. package/dist/cli/upgrade.d.ts +1 -1
  21. package/dist/cli/upgrade.js +3 -3
  22. package/dist/{client-C1yDYjoS.js → client-B2MjENki.js} +31 -16
  23. package/dist/{config-DrTeF80T.js → config-Dm3pWRqY.js} +3 -3
  24. package/dist/{connections-D46f8vvi.js → connections-0BBhiD-p.js} +10 -10
  25. package/dist/{conversation-DSo310Ps.js → conversation-AhOVzN_k.js} +11 -86
  26. package/dist/{conversation-privacy-CxlOCiUo.js → conversation-privacy-C1pJ89rs.js} +1 -1
  27. package/dist/{credential-sync-sm9fegLY.js → credential-sync-BRiWYs6_.js} +15 -14
  28. package/dist/{credentialed-lukuD-cc.js → credentialed-BeBaJMZ_.js} +565 -83
  29. package/dist/{store-xMuuXRE0.d.ts → db-BYOuu6v2.d.ts} +4 -0
  30. package/dist/{executor-4vhvsMZJ.js → executor-BB6eJkD4.js} +6 -6
  31. package/dist/instrumentation.js +2 -2
  32. package/dist/{interruption-marker-CkncDT8d.js → interruption-marker-CdblrIQK.js} +1 -1
  33. package/dist/{job-queue-In9QKz-I.js → job-queue-DiaXoSDg.js} +2 -2
  34. package/dist/{list-BkgnXEEB.js → list-BTDRxkOg.js} +331 -662
  35. package/dist/locks-D-0h111u.js +48 -0
  36. package/dist/{logging-DLSpkSSr.js → logging-C6EdT6PP.js} +1 -1
  37. package/dist/{history-C84mlAwO.js → media-U6Tuz6Mi.js} +84 -2
  38. package/dist/{message-BObyg59s.js → message-DsjiWRVg.js} +4 -4
  39. package/dist/{model-profile-Bg8EoCKD.js → model-profile-B998sjVd.js} +9 -2
  40. package/dist/nitro.d.ts +1 -1
  41. package/dist/nitro.js +5 -3
  42. package/dist/{oauth-callback-server-B-WbSdoH.js → oauth-callback-server-CjFFVGqa.js} +2 -2
  43. package/dist/{prompt-BW9jFsqZ.js → prompt-BPSdXYXV.js} +1 -1
  44. package/dist/{registry-BgecKva0.js → registry-CndmkP2P.js} +1 -1
  45. package/dist/reporting-schema-CZREhYc-.js +104 -0
  46. package/dist/{web-message-id-DlHNANtd.js → reporting-window-DRCi1Ls_.js} +139 -7
  47. package/dist/{resolve-Cpa4Bu1O.js → resolve-BkAA1wH7.js} +3 -3
  48. package/dist/{result-D3TSmZZ8.js → result-9TJTpuYP.js} +30 -11
  49. package/dist/{runner-DS5OKhEp.js → runner-BmKLSyJm.js} +12 -11
  50. package/dist/{sandbox-egress-signals-CnDjY5rx.js → sandbox-egress-signals-CjLaogMo.js} +1 -1
  51. package/dist/{schema-0050HFnB.js → schema-DNLJ_MzW.js} +36 -20
  52. package/dist/{schema-ZngqcOWM.d.ts → schema-WayPSHFu.d.ts} +149 -12
  53. package/dist/{service-account-CKV2WTY7.js → service-account-D6e9cVmH.js} +4 -3
  54. package/dist/{service-account-DGjnDw9y.js → service-account-DlhYl-Mu.js} +3 -3
  55. package/dist/{session-stop-Dam1EI7B.js → session-stop-MZRgYqYH.js} +24 -16
  56. package/dist/{skills-CfAnfImD.js → skills-BggTR_ue.js} +2 -2
  57. package/dist/{spawn-cmq9p4Ly.js → spawn-DmtlcAT_.js} +2 -2
  58. package/dist/{store-zPEoJPBB.js → store-BeWGgaMA.js} +3 -3
  59. package/dist/{store-C5PN02QO.js → store-Byarin7b.js} +4 -4
  60. package/dist/{task-queue-_mf28dSu.js → task-queue-Dt1_ZoI_.js} +3 -3
  61. package/dist/task-runner-DyKqAPpm.js +269 -0
  62. package/dist/{thread-state-BbbPh0Sn.js → thread-state-BHBLMvgb.js} +5 -5
  63. package/dist/{turn-failure-response-BKKmnMB5.js → turn-failure-response-DWXy_0oJ.js} +9 -9
  64. package/dist/{turn-lifecycle-oP0kVeGz.js → turn-lifecycle-AiXkVqCB.js} +1 -1
  65. package/dist/{tasks-SB9z-VTU.js → turn-session-routing-B9KLBhaT.js} +939 -120
  66. package/dist/{validation--JsAGLwc.js → validation-BW60Vtx_.js} +1 -1
  67. package/dist/{version-jHwJp4hC.js → version-CivPYmkH.js} +1 -1
  68. package/dist/version.js +1 -1
  69. package/dist/{viewer-CpXTGlep.js → viewer-BTgAfdUg.js} +216 -27
  70. package/dist/{work-3N-GHY9m.js → work-Bjm52fHo.js} +17 -36
  71. package/dist/{worker-CCdbcItd.js → worker-CMbgtHLu.js} +15 -7
  72. package/migrations/0069_system_identity.sql +25 -0
  73. package/migrations/0070_review_item_foreign_keys.sql +5 -0
  74. package/migrations/AGENTS.md +17 -0
  75. package/migrations/meta/0069_snapshot.json +3979 -0
  76. package/migrations/meta/0070_snapshot.json +3997 -0
  77. package/migrations/meta/_journal.json +15 -1
  78. package/package.json +5 -4
  79. package/dist/db-BU4LQD8s.d.ts +0 -6
  80. package/dist/history-BgI33Kie.d.ts +0 -78
  81. package/dist/reporting-window-DVCD_10C.js +0 -227
  82. package/dist/task-runner-DMI2prDO.js +0 -1073
  83. package/migrations/README.md +0 -30
@@ -1,6 +1,6 @@
1
1
  import { n as ConversationWorkQueue, t as ConversationQueueMessage } from "./queue-C37RbDVc.js";
2
- import { t as ConversationStore } from "./store-xMuuXRE0.js";
3
- import "./history-BgI33Kie.js";
2
+ import { t as ConversationStore } from "./db-BYOuu6v2.js";
3
+ import "./schema-WayPSHFu.js";
4
4
  import { n as JuniorPluginSet } from "./plugins-B_0Cr0MO.js";
5
5
  import { Hono } from "hono";
6
6
  import "@earendil-works/pi-ai/compat";
@@ -8,12 +8,13 @@ import "@earendil-works/pi-ai/api/anthropic-messages";
8
8
  import "ai";
9
9
  import "@sentry/node";
10
10
  import { z } from "zod";
11
+ import "drizzle-orm";
11
12
  import { Destination, OwnedObjectAnnotation, PluginRegistration, Source, User } from "@sentry/junior-plugin-api";
12
13
  import "@earendil-works/pi-agent-core";
13
14
  import "@earendil-works/pi-ai";
14
- import "@sinclair/typebox";
15
15
  import "@modelcontextprotocol/sdk/client/auth.js";
16
16
  import { Client } from "@modelcontextprotocol/sdk/client";
17
+ import "@sinclair/typebox";
17
18
  import { Message, StateAdapter } from "chat";
18
19
  import "@chat-adapter/slack";
19
20
  declare const TURN_REASONING_LEVELS: readonly ["none", "low", "medium", "high", "xhigh"];
@@ -168,6 +169,11 @@ interface InboxAttempt {
168
169
  drain(handle: (messages: InboundMessage[]) => Promise<readonly string[] | void>, options?: {
169
170
  deferred?: boolean;
170
171
  }): Promise<InboundMessage[]>;
172
+ /**
173
+ * True when a failure of this attempt can end the work: the worker gives up
174
+ * and drops the mailbox. The adapter must record its own failure first.
175
+ * Resume attempts, which have no messages, can also be final.
176
+ */
171
177
  isFinalAttempt: boolean;
172
178
  messages: InboundMessage[];
173
179
  }
package/dist/app.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ModelProfileInput, i as JuniorDashboardOptions, n as JuniorAppOptions, r as createApp, t as JuniorApp } from "./app-z6Uuyq3j.js";
1
+ import { a as ModelProfileInput, i as JuniorDashboardOptions, n as JuniorAppOptions, r as createApp, t as JuniorApp } from "./app-Bz8t4P8p.js";
2
2
  import { i as defineJuniorPlugins, n as JuniorPluginSet, r as JuniorPluginSetOptions, t as JuniorPluginInput } from "./plugins-B_0Cr0MO.js";
3
3
  import { t as JUNIOR_VERSION } from "./version-Cc2OFd9G.js";
4
4
  export { JUNIOR_VERSION, JuniorApp, JuniorAppOptions, type JuniorDashboardOptions, type JuniorPluginInput, type JuniorPluginSet, type JuniorPluginSetOptions, type ModelProfileInput, createApp, defineJuniorPlugins };
package/dist/app.js CHANGED
@@ -1,43 +1,44 @@
1
- import { $t as CONVERSATION_WORK_STALE_ENQUEUE_MS, C as automationVersionOf, I as eventGuidance, _n as isInvalidConversationRecordError, _r as setConfigDefaults, _t as settleConversationTitleWork, ar as getThreadStopDecision, b as admitEventAutomationRun, c as withScheduledAutomationLock, dr as setExperimentalFeatures, dt as appendConversationMessages, gr as getConfigDefaults, hn as hasRunnableConversationWork, i as readScheduledAutomation, l as blockEventAutomation, lr as getExperimentalFeatures, mt as projectConversationMessages, n as listScheduledAutomationsForTeam, nr as SubscribedReplyReason, o as saveScheduledAutomationInLock, p as findMatchingEventAutomations, s as scheduledRunId, u as collectEventAutomationMatchKeys, ur as isExperimentalFeatureEnabled, x as eventAutomationRunLimitReason } from "./tasks-SB9z-VTU.js";
2
- import { _ as snapshotRuntimeConfig, d as restoreRuntimeConfig, f as setBotModelConfig, g as setSlackReactionConfig, h as setRuntimeLimits, i as getChatConfig, m as setProfiles, n as botConfig, o as getSlackBotToken, p as setCrossActorMidRunMode, u as resetRuntimeConfig } from "./config-DrTeF80T.js";
3
- import { A as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, E as withSpan, N as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, T as withLogContext, b as setSpanAttributes, h as logWarn, m as logInfo, p as logException, r as createRequestContext, w as withContext, z as normalizeIdentityEmail } from "./logging-DLSpkSSr.js";
1
+ import { B as readScheduledAutomation, G as blockEventAutomation, Gr as setExperimentalFeatures, H as saveScheduledAutomationInLock, Ir as SubscribedReplyReason, Jn as hasRunnableConversationWork, K as collectEventAutomationMatchKeys, M as recordAutomationExecution, Mn as CONVERSATION_WORK_STALE_ENQUEUE_MS, R as listScheduledAutomationsForTeam, S as existingConversationId, U as scheduledRunId, Ur as getExperimentalFeatures, W as withScheduledAutomationLock, Wr as isExperimentalFeatureEnabled, Wt as appendConversationMessages, Xn as isInvalidConversationRecordError, Xr as getConfigDefaults, Xt as settleConversationTitleWork, Y as findMatchingEventAutomations, Zr as setConfigDefaults, a as confirmDispatchMailboxAppend, b as notifyAutomationBlocked, f as getPluginDispatchProjection, ht as eventGuidance, it as automationVersionOf, m as listPendingDispatchMailboxAppends, nt as eventAutomationRunLimitReason, o as createOrGetDispatch, p as isTerminalDispatchStatus, qt as projectConversationMessages, r as buildDispatchId, s as getDispatchConversationId, tt as admitEventAutomationRun, u as getDispatchRecord, v as markDispatchFailed, zr as getThreadStopDecision } from "./turn-session-routing-B9KLBhaT.js";
2
+ import { _ as snapshotRuntimeConfig, d as restoreRuntimeConfig, f as setBotModelConfig, g as setSlackReactionConfig, h as setRuntimeLimits, i as getChatConfig, m as setProfiles, n as botConfig, o as getSlackBotToken, p as setCrossActorMidRunMode, u as resetRuntimeConfig } from "./config-Dm3pWRqY.js";
3
+ import { A as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, E as withSpan, L as GOOGLE_IDENTITY_PROVIDER, N as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, T as withLogContext, b as setSpanAttributes, h as logWarn, m as logInfo, p as logException, r as createRequestContext, w as withContext, z as normalizeIdentityEmail } from "./logging-C6EdT6PP.js";
4
4
  import { n as captureMessage } from "./sentry-MDkYAVPV.js";
5
- import { t as JUNIOR_VERSION } from "./version-jHwJp4hC.js";
5
+ import { t as JUNIOR_VERSION } from "./version-CivPYmkH.js";
6
6
  import { f as parseSlackTeamId, g as slackMessageTsSchema, h as slackMessageTsFromMs, m as parseSlackMessageTs, n as createSlackActor, p as parseSlackUserId, s as parseActorUserId, u as parseSlackChannelId } from "./actor-CP9K2Idu.js";
7
- import { O as recordGoogleSignIn, _ as withConversationEventLock, b as withConversationMutationLock, d as getConversationEventStore, h as getSqlExecutor, i as readActorIdentity, l as closeDb, m as getDb, o as resolveViewerUser, p as getConversationStore } from "./viewer-CpXTGlep.js";
7
+ import { C as getSqlExecutor, M as resolveActorIdentityId, O as withConversationMutationLock, R as recordGoogleSignIn, S as getDb, T as withConversationEventLock, _ as closeDb, g as createCache, i as readActorIdentity, l as resolveViewerUser, p as parseAvatarUrl, x as getConversationStore, y as getConversationEventStore } from "./viewer-BTgAfdUg.js";
8
8
  import { a as juniorAgentInvocations, d as juniorDestinations, i as juniorAgentBindings, s as juniorConversations } from "./agent-invocations-C1RNOCs8.js";
9
- import { d as juniorAutomations, g as juniorConversationBriefs, l as juniorAutomationRuns, y as juniorConversationEvents } from "./executor-4vhvsMZJ.js";
10
- import { n as pluginCatalogRuntime } from "./catalog-runtime-BD9GSpc6.js";
11
- import { C as getOpenSlackUserInput, Ct as requestAttachmentDeletion, Dt as recordSubagentEnded, E as parseSlackThreadId, Et as stopConversationSession, G as parseSlackReviewItemClick, H as syncReviewItemSlackCards, J as buildSlackUserInputModal, K as parseSlackReviewItemFormTarget, N as logScheduledAutomationRunSkipped, Nt as processWorkspaceSnapshotJob, P as scheduledAutomationRunAttributes, Pt as ingestEvent, Q as slackUserInputAnswerNote, R as effectiveTaskOutcomes, S as closeSlackUserInput, T as releaseSlackUserInput, V as readSlackReviewItemCardConversationId, W as buildSlackReviewItemModal, X as parseSlackUserInputSubmission, Y as parseSlackUserInputFormTarget, Z as slackUserInputAction, _ as unpublishedArtifactHeaders, _t as recordWebConversationActivity, dt as sendReviewItemMessages, et as runWithSlackInstallation, g as readPublicArtifact, h as publicArtifactHeaders, mt as conversationTurnIdForMessage, n as executeAgentRun, pt as appendAndEnqueueWebMessage, t as createAgentRunner, tt as verifySlackSignature, ut as renderReviewItemMessage, v as lookupSlackUserProfile, vt as webActorFromEmail, w as persistSlackUserInputReply, x as claimSlackUserInput, xt as collectAttachmentGarbage } from "./agent-runner-CAYfFmU7.js";
12
- import { $ as openSlackModal, I as isVercelSandboxEgressRequest, In as createPluginLogger, Jt as bindScheduledAutomationCredentialSubject, Kt as takeDueTimerWatches, L as proxyVercelSandboxEgressRequest, Ln as readConversationAccessFromSql, Nn as createPluginState, Qt as verifySlackDirectCredentialSubject, Tt as normalizeSandboxEgressTracePropagationDomains, Ut as findMatchingWatches, V as resolveBaseUrl, Xt as verifyEventAutomationCredentialSubject, Yt as bindSlackDirectCredentialSubject, Zt as verifyScheduledAutomationCredentialSubject, _n as getDashboardTaskLink, _t as consumeSandboxEgressPermissionDeniedSignal, at as slackEntitySchema, c as getPluginRoutes, cr as createPluginCache, dn as getWorkspaceTeamId, er as resolveRootVisibility, et as postSlackEphemeralMessage, fn as runWithWorkspaceTeamId, gt as consumeSandboxEgressAuthRequiredSignal, h as validatePlugins, ht as clearSandboxEgressSignals, in as getSlackClient, lr as createCache, m as setPlugins, mn as getDashboardConversationLink, n as createUserTokenStore, on as isDmChannel, ot as slackExternalRefIdSchema, p as getPlugins, q as slackMention, qt as bindEventAutomationCredentialSubject, rr as listConversationAnnotations, s as getPluginApiRoutes, v as setBriefsConfig, vn as setDashboardConversationLinkOptions, yt as parseSandboxEgressCredentialToken, zt as collectEventMatchKeys } from "./credentialed-lukuD-cc.js";
13
- import { a as MUTATION_LOCK_TTL_MS, c as withLock, i as getStateAdapter, s as fenceLock, t as disconnectStateAdapter } from "./adapter-04AcD2SO.js";
9
+ import { c as juniorReviewItems, d as juniorAutomations, g as juniorConversationBriefs, l as juniorAutomationRuns, y as juniorConversationEvents } from "./executor-BB6eJkD4.js";
10
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-Bdym_wKy.js";
11
+ import { A as verifySlackSignature, C as syncReviewItemSlackCards, Ct as processWorkspaceSnapshotJob, D as parseSlackReviewItemFormTarget, E as parseSlackReviewItemClick, J as readViewerAutomationSummary, L as logScheduledAutomationRunSkipped, O as parseSlackUserInputSubmission, Q as effectiveTaskOutcomes, R as scheduledAutomationRunAttributes, S as readSlackReviewItemCardConversationId, T as buildSlackReviewItemModal, _ as unpublishedArtifactHeaders, _t as recordSubagentEnded, ct as webActorFromEmail, dt as collectAttachmentGarbage, et as deliverReviewItemChange, g as readPublicArtifact, gt as stopConversationSession, h as publicArtifactHeaders, it as conversationTurnIdForMessage, j as parseSlackThreadId, k as runWithSlackInstallation, n as executeAgentRun, pt as requestAttachmentDeletion, rt as appendAndEnqueueWebMessage, st as recordWebConversationActivity, t as createAgentRunner, tt as renderReviewItemMessage, v as lookupSlackUserProfile, wt as ingestEvent, x as createSlackReviewItemShow } from "./agent-runner-MSQSMFkq.js";
12
+ import { At as slackEntitySchema, Bn as getDashboardTaskLink, Bt as clearSandboxEgressSignals, Cr as resolveRootVisibility, Dn as getSlackClient, Er as listConversationAnnotations, Fn as runWithWorkspaceTeamId, Ht as consumeSandboxEgressPermissionDeniedSignal, Ln as getDashboardConversationLink, M as canActOnReviewItem, Pn as getWorkspaceTeamId, S as dismissOpenReviewItems, Tt as postSlackEphemeralMessage, Vn as setDashboardConversationLinkOptions, Vt as consumeSandboxEgressAuthRequiredSignal, Wt as parseSandboxEgressCredentialToken, Xt as normalizeSandboxEgressTracePropagationDomains, _n as bindScheduledAutomationCredentialSubject, ar as createPluginLogger, bn as verifyScheduledAutomationCredentialSubject, c as getPluginRoutes, cn as collectEventMatchKeys, ct as proxyVercelSandboxEgressRequest, fn as findMatchingWatches, ft as resolveBaseUrl, gn as bindEventAutomationCredentialSubject, h as validatePlugins, hn as takeDueTimerWatches, jr as createPluginCache, jt as slackExternalRefIdSchema, kn as isDmChannel, m as setPlugins, n as createUserTokenStore, nr as createPluginState, or as readConversationAccessFromSql, p as getPlugins, rr as createPluginEmbedder, s as getPluginApiRoutes, st as isVercelSandboxEgressRequest, v as setBriefsConfig, vn as bindSlackDirectCredentialSubject, vt as slackMention, wt as openSlackModal, xn as verifySlackDirectCredentialSubject, yn as verifyEventAutomationCredentialSubject } from "./credentialed-BeBaJMZ_.js";
13
+ import { a as withLock, i as fenceLock, n as MUTATION_LOCK_TTL_MS } from "./locks-D-0h111u.js";
14
+ import { r as getStateAdapter, t as disconnectStateAdapter } from "./adapter-BQNTKVTF.js";
14
15
  import { n as getNextRunAtMs } from "./cadence-R7Em4RjE.js";
15
- import { D as conversationSurfaceSchema, I as annotationCard, T as conversationReportStatusSchema, h as conversationFeedQuerySchema } from "./conversation-DSo310Ps.js";
16
- import { b as listPendingAgentInvocationMailboxAppends, x as listPendingAgentInvocationResults } from "./store-C5PN02QO.js";
17
- import { E as renderSlackObjectCard, S as renderTaskInput, d as getEventCatalog, f as SLACK_EVENT_NAMESPACE, g as slackChannelMessageRunsAutomation, h as slackChannelMessageReplyThreadTs, m as slackChannelMessageEvent } from "./session-stop-Dam1EI7B.js";
18
- import { a as isEmptyUserInputAnswer, i as formatUserInputAnswer, o as normalizeUserInputAnswer, r as buttonUserInputField } from "./web-message-id-DlHNANtd.js";
19
- import { c as setSandboxResourceConfig, o as getSandboxResourceConfig } from "./resolve-Cpa4Bu1O.js";
20
- import { a as getVercelConversationWorkQueue, d as getQueueProvider, g as isConversationQueueMessageRejectedError, h as conversationQueueMessageSchema, i as verifyWorkspaceSnapshotJobMessage, o as resolveConversationWorkQueueTopic, s as verifyConversationQueueMessage, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-In9QKz-I.js";
21
- import { S as removeActiveConversation, _ as hasRunnableConversationWork$1, c as clearExpiredConversationLease, g as getConversationWorkState, h as getConversation, m as ensureConversationWake, r as appendAndEnqueueInboundMessage, v as listActiveConversationIds } from "./store-zPEoJPBB.js";
22
- import { D as scheduledRunSchema } from "./automation-CmeFBSEh.js";
23
- import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "./validation--JsAGLwc.js";
16
+ import { D as conversationSurfaceSchema, I as annotationCard, T as conversationReportStatusSchema, h as conversationFeedQuerySchema } from "./conversation-AhOVzN_k.js";
17
+ import { b as listPendingAgentInvocationMailboxAppends, x as listPendingAgentInvocationResults } from "./store-Byarin7b.js";
18
+ import { E as renderSlackObjectCard, S as renderTaskInput, d as getEventCatalog, f as SLACK_EVENT_NAMESPACE, g as slackChannelMessageRunsAutomation, h as slackChannelMessageReplyThreadTs, m as slackChannelMessageEvent } from "./session-stop-MZRgYqYH.js";
19
+ import { h as buttonUserInputField } from "./reporting-window-DRCi1Ls_.js";
20
+ import { c as setSandboxResourceConfig, o as getSandboxResourceConfig } from "./resolve-BkAA1wH7.js";
21
+ import { a as getVercelConversationWorkQueue, d as getQueueProvider, g as isConversationQueueMessageRejectedError, h as conversationQueueMessageSchema, i as verifyWorkspaceSnapshotJobMessage, o as resolveConversationWorkQueueTopic, s as verifyConversationQueueMessage, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-DiaXoSDg.js";
22
+ import { S as removeActiveConversation, _ as hasRunnableConversationWork$1, c as clearExpiredConversationLease, g as getConversationWorkState, h as getConversation, m as ensureConversationWake, r as appendAndEnqueueInboundMessage, v as listActiveConversationIds } from "./store-BeWGgaMA.js";
23
+ import { M as scheduledRunSchema } from "./automation-Dwh_xcqM.js";
24
+ import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "./validation-BW60Vtx_.js";
24
25
  import { a as pluginRuntimeRegistrationsFromPluginSet, n as pluginCatalogConfigFromEnv, r as pluginCatalogConfigFromPluginSet, t as defineJuniorPlugins } from "./plugins-DOm9Y6qI.js";
25
- import { A as assertNoLegacyAllowedDomains, B as normalizeIncomingSlackThreadId, E as readViewerAutomationSummary, F as recordSkippedConversationMessage, G as parseContent, H as stopConversationTurn, I as buildSlackInboundMessage, J as canActOnReviewItem, K as ReviewItemActionError, L as clearSlackPendingReactions, M as isAllowedSignInEmail, N as readEnvList, P as resolveAllowedDomains, Q as getAttachmentStorage, R as isSlackMessageStopped, U as THREAD_OPTOUT_ACK, V as withNormalizedThreadId, W as startProcessingReaction, X as readReviewItemForUser, Z as reviewItemChange, _ as createProductionConversationWorkOptions, b as createSlackWebApiStatusSender, et as enqueueAgentDispatch, j as isAllowedDomain, q as actOnReviewItem, t as readConversationFeed, tt as GET$3, v as createProductionSlackWebhookServices, y as getProductionSlackAdapter, z as stopSlackThread } from "./list-BkgnXEEB.js";
26
- import { C as existingConversationId, N as recordAutomationExecution, c as getDispatchConversationId, d as getDispatchRecord, h as listPendingDispatchMailboxAppends, i as buildDispatchId, m as isTerminalDispatchStatus, o as confirmDispatchMailboxAppend, p as getPluginDispatchProjection, s as createOrGetDispatch, t as processPluginTask, x as notifyAutomationBlocked, y as markDispatchFailed } from "./task-runner-DMI2prDO.js";
27
- import { o as getAuthPausedConversationTurnId, t as enqueueAgentInvocationResult } from "./result-D3TSmZZ8.js";
28
- import { r as enqueueAgentInvocation } from "./work-3N-GHY9m.js";
29
- import { o as coerceThreadConversationState } from "./thread-state-BbbPh0Sn.js";
30
- import { o as unlinkProvider } from "./connections-D46f8vvi.js";
31
- import { a as GET$4, i as publishAppHomeView, r as GET$5, t as receiveLocalOAuthCredential } from "./credential-sync-sm9fegLY.js";
32
- import { a as pluginTaskQueueConsumer, c as queueCallback, n as createVercelPluginTaskCallback, o as registerVercelPluginTaskDevConsumer } from "./task-queue-_mf28dSu.js";
33
- import { t as processConversationWork } from "./worker-CCdbcItd.js";
34
- import { t as bindMessageAgent } from "./message-BObyg59s.js";
35
- import { t as bindSpawnAgent } from "./spawn-cmq9p4Ly.js";
26
+ import { A as stopSlackThread, B as actOnReviewItem, C as isAllowedSignInEmail, D as buildSlackInboundMessage, E as recordSkippedConversationMessage, F as bindMessageAuthorIdentityId, H as readReviewItemForUser, I as startProcessingReaction, K as enqueueAgentDispatch, L as stripLeadingBotMention, M as withNormalizedThreadId, N as stopConversationTurn, O as clearSlackPendingReactions, P as THREAD_OPTOUT_ACK, R as parseContent, S as isAllowedDomain, T as resolveAllowedDomains, U as reviewItemChange, V as closeReviewItemsAnsweredByReply, W as getAttachmentStorage, _ as createProductionConversationWorkOptions, b as createSlackWebApiStatusSender, j as normalizeIncomingSlackThreadId, k as isSlackMessageStopped, q as GET$3, t as readConversationFeed, v as createProductionSlackWebhookServices, w as readEnvList, x as assertNoLegacyAllowedDomains, y as getProductionSlackAdapter, z as ReviewItemActionError } from "./list-BTDRxkOg.js";
27
+ import { n as enqueueAgentInvocationResult, o as getAuthPausedConversationTurnId } from "./result-9TJTpuYP.js";
28
+ import { r as enqueueAgentInvocation } from "./work-Bjm52fHo.js";
29
+ import { o as coerceThreadConversationState } from "./thread-state-BHBLMvgb.js";
30
+ import { o as unlinkProvider } from "./connections-0BBhiD-p.js";
31
+ import { a as GET$4, i as publishAppHomeView, r as GET$5, t as receiveLocalOAuthCredential } from "./credential-sync-BRiWYs6_.js";
32
+ import { a as pluginTaskQueueConsumer, c as queueCallback, n as createVercelPluginTaskCallback, o as registerVercelPluginTaskDevConsumer } from "./task-queue-Dt1_ZoI_.js";
33
+ import { t as processConversationWork } from "./worker-CMbgtHLu.js";
34
+ import { t as bindMessageAgent } from "./message-DsjiWRVg.js";
35
+ import { t as bindSpawnAgent } from "./spawn-DmtlcAT_.js";
36
+ import { t as processPluginTask } from "./task-runner-DyKqAPpm.js";
36
37
  import { createRequire } from "node:module";
37
38
  import { Hono } from "hono";
38
39
  import { z } from "zod";
39
40
  import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
40
- import { and, asc, eq, inArray, isNotNull, isNull, lte, or, sql } from "drizzle-orm";
41
+ import { and, asc, eq, inArray, isNotNull, isNull, lte, ne, or, sql } from "drizzle-orm";
41
42
  import { EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, dispatchOptionsSchema, eventSchema, eventTriggerFiltersText, isSlackDestination, userSchema } from "@sentry/junior-plugin-api";
42
43
  import { pathToFileURL } from "node:url";
43
44
  import net from "node:net";
@@ -269,6 +270,7 @@ function createHeartbeatContext(args) {
269
270
  cache: createPluginCache(pluginName),
270
271
  nowMs: args.nowMs,
271
272
  db: getDb(),
273
+ embedder: createPluginEmbedder(pluginName),
272
274
  state: createPluginState(pluginName),
273
275
  log: createPluginLogger(pluginName),
274
276
  agent: {
@@ -1226,6 +1228,12 @@ async function selectExpiredRoots(executor, args) {
1226
1228
  where bindings.parent_conversation_id = tree.conversation_id
1227
1229
  or bindings.child_conversation_id = tree.conversation_id
1228
1230
  )
1231
+ or exists (
1232
+ select 1 from junior_review_items review_items
1233
+ where review_items.added_by_conversation_id = tree.conversation_id
1234
+ and review_items.status = 'open'
1235
+ and review_items.automation_id is null
1236
+ )
1229
1237
  or (
1230
1238
  ${juniorDestinations.visibility} is distinct from 'public'
1231
1239
  and (
@@ -1233,6 +1241,15 @@ async function selectExpiredRoots(executor, args) {
1233
1241
  select 1 from junior_conversation_briefs briefs
1234
1242
  where briefs.conversation_id = tree.conversation_id
1235
1243
  )
1244
+ or exists (
1245
+ select 1 from junior_review_items review_items
1246
+ where review_items.added_by_conversation_id = tree.conversation_id
1247
+ and review_items.visibility = 'private'
1248
+ and (
1249
+ review_items.status <> 'open'
1250
+ or review_items.automation_id is null
1251
+ )
1252
+ )
1236
1253
  or exists (
1237
1254
  select 1 from junior_conversations metadata
1238
1255
  where metadata.conversation_id = tree.conversation_id
@@ -1258,7 +1275,9 @@ async function selectExpiredRoots(executor, args) {
1258
1275
  * event rows for the given conversation and every descendant, stamp
1259
1276
  * `transcript_purged_at`, and — for non-public content — null the raw-payload
1260
1277
  * metadata (`title`, `channel_name`, legacy actor JSON) so purged private
1261
- * conversations keep only safe metadata. The metadata rows themselves survive.
1278
+ * conversations keep only safe metadata. Non-public content also loses its
1279
+ * Briefs and the Review items that it added. The metadata rows themselves
1280
+ * survive.
1262
1281
  */
1263
1282
  async function purgeConversationTree(executor, args) {
1264
1283
  return await withConversationMutationLock(executor, args.rootConversationId, async () => {
@@ -1303,9 +1322,17 @@ async function purgeConversationTree(executor, args) {
1303
1322
  await executor.db().delete(juniorConversationEvents).where(inArray(juniorConversationEvents.conversationId, ids));
1304
1323
  await executor.db().delete(juniorAgentInvocations).where(or(inArray(juniorAgentInvocations.parentConversationId, ids), inArray(juniorAgentInvocations.childConversationId, ids)));
1305
1324
  await executor.db().delete(juniorAgentBindings).where(or(inArray(juniorAgentBindings.parentConversationId, ids), inArray(juniorAgentBindings.childConversationId, ids)));
1325
+ await dismissOpenReviewItems(executor.db(), {
1326
+ addedByConversationIds: ids,
1327
+ nowMs: args.nowMs,
1328
+ reason: "Conversation purged"
1329
+ });
1306
1330
  await requestAttachmentDeletion(executor, ids, args.nowMs);
1307
1331
  const scrubMetadata = args.retention ? !isPublic : resolvedScrubMetadata;
1308
- if (scrubMetadata) await executor.db().delete(juniorConversationBriefs).where(inArray(juniorConversationBriefs.conversationId, ids));
1332
+ if (scrubMetadata) {
1333
+ await executor.db().delete(juniorConversationBriefs).where(inArray(juniorConversationBriefs.conversationId, ids));
1334
+ await executor.db().delete(juniorReviewItems).where(and(inArray(juniorReviewItems.addedByConversationId, ids), eq(juniorReviewItems.visibility, "private"), or(ne(juniorReviewItems.status, "open"), isNull(juniorReviewItems.automationId))));
1335
+ }
1309
1336
  await executor.db().update(juniorConversations).set({
1310
1337
  transcriptPurgedAt: new Date(args.nowMs),
1311
1338
  ...scrubMetadata ? {
@@ -1776,8 +1803,8 @@ async function refreshCards(services, user, itemId) {
1776
1803
  }
1777
1804
  /**
1778
1805
  * Do one person action from a Slack card. The thread of the card gets the
1779
- * action as Slack input from the person, like an answer to
1780
- * `requestUserInput`. The other linked Conversations get messages from
1806
+ * action as Slack input from the person, like a typed reply. The other
1807
+ * linked Conversations get messages from
1781
1808
  * `actOnReviewItem`. An expected failure, such as an item that is already
1782
1809
  * closed, goes to the person as an ephemeral message.
1783
1810
  */
@@ -1789,6 +1816,10 @@ async function act(args) {
1789
1816
  ...target,
1790
1817
  itemId: args.itemId
1791
1818
  }) ?? `slack:${target.channelId}:${target.threadTs}`;
1819
+ const delivery = {
1820
+ queue: services.queue,
1821
+ show: createSlackReviewItemShow(() => services.adapter)
1822
+ };
1792
1823
  let item;
1793
1824
  try {
1794
1825
  const current = await readReviewItemForUser(actor.user, args.itemId);
@@ -1796,9 +1827,8 @@ async function act(args) {
1796
1827
  action: args.action,
1797
1828
  exceptConversationId: conversationId,
1798
1829
  firstCloseOnly: true,
1799
- getSlackAdapter: () => services.adapter,
1830
+ delivery,
1800
1831
  id: current.id,
1801
- queue: services.queue,
1802
1832
  user: actor.user,
1803
1833
  ...args.answer ? { answer: args.answer(current) } : void 0
1804
1834
  });
@@ -1824,11 +1854,11 @@ async function act(args) {
1824
1854
  }));
1825
1855
  } catch (error) {
1826
1856
  logException(error, "review_item.slack_input.persist.failed", { "app.review_item.id": item.id });
1827
- await sendReviewItemMessages({
1857
+ await deliverReviewItemChange({
1828
1858
  change,
1859
+ delivery,
1829
1860
  item,
1830
- nowMs: Date.now(),
1831
- queue: services.queue
1861
+ nowMs: Date.now()
1832
1862
  });
1833
1863
  }
1834
1864
  }
@@ -1972,139 +2002,8 @@ async function handleAppHomeDisconnect(args) {
1972
2002
  });
1973
2003
  }
1974
2004
  /**
1975
- * Save the first answer to the open request of a Slack thread as Slack input
1976
- * from the person who answered. The input text is the formatted answer, so
1977
- * the model reads one format on every surface. Later answers to the same
1978
- * request do nothing. A stale request, such as one that a newer request
1979
- * replaced, also does nothing.
1980
- */
1981
- async function answerSlackUserInput(args) {
1982
- const userId = requireSlackPayloadUserId(args.payload.user?.id, "Slack user input payload");
1983
- const { channelId, messageTs } = args;
1984
- const open = await getOpenSlackUserInput(args.state, {
1985
- channelId,
1986
- threadTs: args.threadTs
1987
- });
1988
- if (!open || open.messageTs !== messageTs) return;
1989
- const answer = args.answer(open);
1990
- if (isEmptyUserInputAnswer(answer)) return;
1991
- const userTeam = args.payload.user?.team_id;
1992
- if (!await isSlackWorkspaceMember({
1993
- user: userId,
1994
- user_team: userTeam
1995
- }, args.state)) return;
1996
- if (!await args.isAuthorAllowed(userId)) return;
1997
- if (!await claimSlackUserInput(args.state, {
1998
- channelId,
1999
- claimedBy: userId,
2000
- messageTs
2001
- })) return;
2002
- const message = buildSlackInteractionInput({
2003
- adapter: args.adapter,
2004
- channelId,
2005
- inputTs: args.inputTs,
2006
- messageId: args.messageId,
2007
- messageTs,
2008
- payload: args.payload,
2009
- text: formatUserInputAnswer(open.request, answer),
2010
- threadTs: args.threadTs,
2011
- userId
2012
- });
2013
- try {
2014
- await args.persistMessage(message);
2015
- } catch (error) {
2016
- await releaseSlackUserInput(args.state, {
2017
- channelId,
2018
- messageTs
2019
- });
2020
- throw error;
2021
- }
2022
- await closeSlackUserInput({
2023
- note: slackUserInputAnswerNote({
2024
- answer,
2025
- request: open.request,
2026
- who: slackMention(userId)
2027
- }),
2028
- open
2029
- });
2030
- }
2031
- /** Read the request message and thread of a block action. */
2032
- function blockActionTarget(payload) {
2033
- const channelId = parseSlackChannelId(payload.channel?.id);
2034
- const messageTs = parseSlackMessageTs(payload.message?.ts);
2035
- if (!channelId || !messageTs) throw new Error("Slack user input payload is incomplete");
2036
- return {
2037
- channelId,
2038
- messageTs,
2039
- threadTs: parseSlackMessageTs(payload.message?.thread_ts) ?? messageTs
2040
- };
2041
- }
2042
- /** Answer a one-click request with the clicked choice. */
2043
- async function handleUserInputChoice(args) {
2044
- const target = blockActionTarget(args.payload);
2045
- const actionTs = parseSlackMessageTs(args.action.action_ts);
2046
- const choice = args.action.value?.trim();
2047
- if (!actionTs || !choice) throw new Error("Slack user input click payload is incomplete");
2048
- await answerSlackUserInput({
2049
- ...target,
2050
- adapter: args.adapter,
2051
- answer: (open) => {
2052
- const field = buttonUserInputField(open.request);
2053
- return normalizeUserInputAnswer(open.request, {
2054
- requestId: open.requestId,
2055
- values: field ? { [field.id]: [choice] } : {}
2056
- });
2057
- },
2058
- inputTs: actionTs,
2059
- messageId: `slack-user-input-answer:${actionTs}`,
2060
- payload: args.payload,
2061
- isAuthorAllowed: args.isAuthorAllowed,
2062
- persistMessage: args.persistMessage,
2063
- state: args.state
2064
- });
2065
- }
2066
- /** Open the answer form of the open request for the person who clicked. */
2067
- async function handleUserInputOpenForm(args) {
2068
- const target = blockActionTarget(args.payload);
2069
- const triggerId = args.payload.trigger_id;
2070
- if (!triggerId) throw new Error("Slack user input form payload is missing a trigger id");
2071
- const open = await getOpenSlackUserInput(args.state, target);
2072
- if (!open || open.messageTs !== target.messageTs) return;
2073
- await openSlackModal({
2074
- triggerId,
2075
- view: buildSlackUserInputModal(open.request, target)
2076
- });
2077
- }
2078
- /** Answer a request with the values of its submitted form. */
2079
- async function handleUserInputSubmission(args) {
2080
- const view = args.payload.view;
2081
- const formTarget = parseSlackUserInputFormTarget(view?.private_metadata);
2082
- const channelId = parseSlackChannelId(formTarget?.channelId);
2083
- const messageTs = parseSlackMessageTs(formTarget?.messageTs);
2084
- const threadTs = parseSlackMessageTs(formTarget?.threadTs);
2085
- if (!view?.id || !channelId || !messageTs || !threadTs) throw new Error("Slack user input form submission is incomplete");
2086
- const inputTs = slackMessageTsFromMs(Date.now());
2087
- await answerSlackUserInput({
2088
- adapter: args.adapter,
2089
- answer: (open) => parseSlackUserInputSubmission({
2090
- request: open.request,
2091
- requestId: open.requestId,
2092
- values: view.state?.values ?? {}
2093
- }),
2094
- channelId,
2095
- inputTs,
2096
- messageId: `slack-user-input-answer:${view.id}`,
2097
- messageTs,
2098
- payload: args.payload,
2099
- isAuthorAllowed: args.isAuthorAllowed,
2100
- persistMessage: args.persistMessage,
2101
- state: args.state,
2102
- threadTs
2103
- });
2104
- }
2105
- /**
2106
- * Handle Slack interactions from App Home, user input requests, and Review
2107
- * item cards: block actions and submitted forms.
2005
+ * Handle Slack interactions from App Home and Review item cards: block
2006
+ * actions and submitted forms.
2108
2007
  */
2109
2008
  async function handleSlackInteractivePayload(args) {
2110
2009
  const spanAttributes = { userId: args.payload.user?.id?.trim() || void 0 };
@@ -2115,10 +2014,6 @@ async function handleSlackInteractivePayload(args) {
2115
2014
  }));
2116
2015
  return;
2117
2016
  }
2118
- if (args.payload.type === "view_submission" && args.payload.view?.callback_id === "junior_user_input") {
2119
- await withSpan("chat.slack_user_input_submit", "chat.slack_user_input_submit", spanAttributes, () => handleUserInputSubmission(args));
2120
- return;
2121
- }
2122
2017
  if (args.payload.type !== "block_actions") return;
2123
2018
  for (const action of args.payload.actions ?? []) {
2124
2019
  const click = parseSlackReviewItemClick(action);
@@ -2131,18 +2026,6 @@ async function handleSlackInteractivePayload(args) {
2131
2026
  }));
2132
2027
  return;
2133
2028
  }
2134
- const kind = slackUserInputAction(action.action_id);
2135
- if (kind === "choice") {
2136
- await withSpan("chat.slack_user_input_click", "chat.slack_user_input_click", spanAttributes, () => handleUserInputChoice({
2137
- ...args,
2138
- action
2139
- }));
2140
- return;
2141
- }
2142
- if (kind === "open_form") {
2143
- await withSpan("chat.slack_user_input_open_form", "chat.slack_user_input_open_form", spanAttributes, () => handleUserInputOpenForm(args));
2144
- return;
2145
- }
2146
2029
  }
2147
2030
  const disconnect = args.payload.actions?.find((candidate) => candidate.action_id === "app_home_disconnect");
2148
2031
  const provider = disconnect?.selected_option?.value ?? disconnect?.value;
@@ -2644,6 +2527,17 @@ async function buildThread(args) {
2644
2527
  function shouldIgnoreMessage(message) {
2645
2528
  return message.author.isMe === true || !parseActorUserId(message.author.userId);
2646
2529
  }
2530
+ /**
2531
+ * Resolve the Slack author Identity at ingress and bind its id to the message.
2532
+ * Ingress does no profile lookup. The worker adds the profile names later.
2533
+ * Bot authors wait for their own bot Identity, so they get no id here.
2534
+ */
2535
+ async function bindSlackAuthorIdentity(message, installation) {
2536
+ const teamId = installation.teamId;
2537
+ const userId = parseActorUserId(message.author.userId);
2538
+ if (!teamId || !userId || message.author.isBot === true) return;
2539
+ bindMessageAuthorIdentityId(message, await resolveActorIdentityId(getSqlExecutor(), createSlackActor(teamId, userId, null)));
2540
+ }
2647
2541
  function shouldPersistBeforeAck(body) {
2648
2542
  return body.event?.type === "app_mention" || body.event?.type === "message";
2649
2543
  }
@@ -2742,6 +2636,7 @@ async function handleSlackThreadStop(args) {
2742
2636
  conversationId,
2743
2637
  state: args.state
2744
2638
  });
2639
+ await bindSlackAuthorIdentity(args.message, args.installation);
2745
2640
  const content = parseContent(args.message);
2746
2641
  const conversation = coerceThreadConversationState(void 0);
2747
2642
  recordSkippedConversationMessage({
@@ -2848,13 +2743,15 @@ async function routeParsedMessage(args) {
2848
2743
  });
2849
2744
  return;
2850
2745
  }
2851
- if (route === "mention" && !await isSlackAuthorDomainAllowed({
2746
+ const isAuthorDomainAllowed = () => isSlackAuthorDomainAllowed({
2852
2747
  allowedBotUserIds: args.allowedBotUserIds,
2853
2748
  allowedDomains: args.allowedDomains,
2854
2749
  state: args.state,
2855
2750
  teamId: args.installation.teamId,
2856
2751
  user: args.event.user
2857
- })) return;
2752
+ });
2753
+ if (route === "mention" && !await isAuthorDomainAllowed()) return;
2754
+ await bindSlackAuthorIdentity(message, args.installation);
2858
2755
  const conversationId = await resolveSlackConversationId({
2859
2756
  canonicalThreadId,
2860
2757
  conversationStore: args.conversationStore,
@@ -2886,22 +2783,34 @@ async function routeParsedMessage(args) {
2886
2783
  route,
2887
2784
  state: args.state
2888
2785
  });
2889
- if (route !== "mention") {
2786
+ const closeAnswered = async () => {
2787
+ if (message.author.isBot === true) return;
2788
+ await closeReviewItemsAnsweredByReply({
2789
+ ...route === "subscribed" ? { canAnswer: isAuthorDomainAllowed } : void 0,
2790
+ conversationId,
2791
+ delivery: {
2792
+ queue: args.queue,
2793
+ show: createSlackReviewItemShow(() => args.adapter)
2794
+ },
2795
+ resolveUser: async () => {
2796
+ const teamId = args.installation.teamId;
2797
+ const userId = parseActorUserId(message.author.userId);
2798
+ if (!teamId || !userId) return void 0;
2799
+ return (await readActorIdentity(createSlackActor(teamId, userId, null)))?.user;
2800
+ },
2801
+ text: stripLeadingBotMention(parseContent(message).topLevelText, {
2802
+ botUserId: args.adapter.botUserId,
2803
+ stripLeadingSlackMentionToken: true
2804
+ })
2805
+ });
2806
+ };
2807
+ try {
2890
2808
  await persist();
2891
- return;
2809
+ } catch (error) {
2810
+ if (error instanceof SlackEventPersistenceError && error.saved) args.runAfterUnlock(closeAnswered);
2811
+ throw error;
2892
2812
  }
2893
- await persistSlackUserInputReply({
2894
- channelId: args.event.channel,
2895
- claimedBy: message.author.userId,
2896
- isSaved: (error) => error instanceof SlackEventPersistenceError && error.saved,
2897
- note: (request) => slackUserInputAnswerNote({
2898
- request,
2899
- who: slackMention(message.author.userId)
2900
- }),
2901
- persist,
2902
- state: args.state,
2903
- threadTs: args.event.thread_ts
2904
- });
2813
+ args.runAfterUnlock(closeAnswered);
2905
2814
  }
2906
2815
  async function handleSlackEvent(args) {
2907
2816
  const event = args.body.event;
@@ -2979,6 +2888,7 @@ async function handleSlackEvent(args) {
2979
2888
  setSpanAttributes({ "app.slack.membership": member ? "verified" : "unverified" });
2980
2889
  if (!member) return;
2981
2890
  const message = adapter.parseMessage(event);
2891
+ let afterUnlock;
2982
2892
  if (!(await withLock(state, `slack:ingress:${normalizeMessageThreadId(message).threadId}`, () => routeParsedMessage({
2983
2893
  adapter,
2984
2894
  event,
@@ -2989,11 +2899,14 @@ async function handleSlackEvent(args) {
2989
2899
  receivedAtMs,
2990
2900
  allowedBotUserIds: args.services.allowedBotUserIds ?? [],
2991
2901
  allowedDomains: args.services.allowedDomains ?? [],
2902
+ runAfterUnlock: (task) => {
2903
+ afterUnlock = task;
2904
+ },
2992
2905
  state
2993
2906
  }), {
2994
2907
  keepAlive: true,
2995
2908
  waitMs: 1e4
2996
- })).acquired) throw new Error("Could not acquire Slack ingress lock");
2909
+ }).finally(() => afterUnlock?.())).acquired) throw new Error("Could not acquire Slack ingress lock");
2997
2910
  }
2998
2911
  }
2999
2912
  }));
@@ -3005,6 +2918,7 @@ async function handleSlackEvent(args) {
3005
2918
  */
3006
2919
  async function persistSlackMentionWithLock(args) {
3007
2920
  const { message, threadId } = normalizeMessageThreadId(args.message);
2921
+ await bindSlackAuthorIdentity(message, args.installation);
3008
2922
  try {
3009
2923
  if (!(await withLock(args.state, `slack:ingress:${threadId}`, () => persistSlackMessage({
3010
2924
  adapter: args.adapter,
@@ -6223,6 +6137,7 @@ function createBetterAuth(config) {
6223
6137
  hd: hostedDomain,
6224
6138
  prompt: "select_account",
6225
6139
  disableIdTokenSignIn: true,
6140
+ overrideUserInfoOnSignIn: true,
6226
6141
  async getUserInfo(token) {
6227
6142
  if (!token.idToken) return null;
6228
6143
  const claims = readGoogleClaims(token.idToken);
@@ -6232,7 +6147,7 @@ function createBetterAuth(config) {
6232
6147
  user: {
6233
6148
  email: claims.email,
6234
6149
  emailVerified: claims.email_verified === true,
6235
- image: claims.picture,
6150
+ image: claims.picture ?? null,
6236
6151
  name: claims.name
6237
6152
  },
6238
6153
  data: claims
@@ -6264,7 +6179,8 @@ function createBetterAuth(config) {
6264
6179
  await recordGoogleSignIn(getSqlExecutor(), {
6265
6180
  email,
6266
6181
  subject: google.accountId,
6267
- displayName: created.user.name || void 0
6182
+ displayName: created.user.name || void 0,
6183
+ avatarUrl: parseAvatarUrl(created.user.image, GOOGLE_IDENTITY_PROVIDER)
6268
6184
  });
6269
6185
  }) }
6270
6186
  });
@@ -6663,7 +6579,10 @@ async function createApp(options) {
6663
6579
  validatePluginRegistrations(configuredPlugins?.registrations ?? []);
6664
6580
  validatePluginEgressCredentialHooks(configuredPlugins?.registrations ?? []);
6665
6581
  }
6666
- pluginRoutes = getPluginRoutes({ events });
6582
+ pluginRoutes = getPluginRoutes({
6583
+ events,
6584
+ showReviewItem: createSlackReviewItemShow(getProductionSlackAdapter)
6585
+ });
6667
6586
  if (dashboard && !dashboard.disabled) pluginApiRoutes = getPluginApiRoutes();
6668
6587
  } catch (error) {
6669
6588
  restoreRuntimeConfig$1();
@@ -6681,6 +6600,7 @@ async function createApp(options) {
6681
6600
  attachmentStorage,
6682
6601
  bindMessageAgent: (request) => bindMessageAgent(request, { queue: conversationWorkQueue }),
6683
6602
  bindSpawnAgent: (request) => bindSpawnAgent(request, { queue: conversationWorkQueue }),
6603
+ conversationWorkQueue,
6684
6604
  tracePropagation
6685
6605
  });
6686
6606
  const runtimeServiceOverrides = {