@sentry/junior 0.267.0 → 0.269.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 (95) hide show
  1. package/README.md +2 -9
  2. package/dist/{actor-DZSokpwj.js → actor-CP9K2Idu.js} +2 -1
  3. package/dist/{adapter-BybMEezj.js → adapter-2-CG25be.js} +3 -51
  4. package/dist/{admin-DOs1_EiW.js → admin-DSs8S5Uy.js} +1 -1
  5. package/dist/{agent-invocations-CxKldAeB.js → agent-invocations-C1RNOCs8.js} +2 -0
  6. package/dist/{agent-runner-DgNATN4D.js → agent-runner-CrDrPUtY.js} +3411 -1640
  7. package/dist/api/schema.d.ts +2 -5630
  8. package/dist/api/schema.js +7 -7
  9. package/dist/api.d.ts +3 -1
  10. package/dist/api.js +268 -287
  11. package/dist/{app-DAB3fzyp.d.ts → app-BrMMzjYm.d.ts} +10 -3
  12. package/dist/app.d.ts +1 -1
  13. package/dist/app.js +371 -223
  14. package/dist/{automation-CmeFBSEh.js → automation-p87hg_AV.js} +74 -74
  15. package/dist/{briefs-CWKjka7v.js → briefs-PtODdLNu.js} +4 -4
  16. package/dist/{catalog-runtime-cMlAI5LY.js → catalog-runtime-BsoSmTM0.js} +1 -1
  17. package/dist/cli/chat.js +16 -26
  18. package/dist/cli/check.js +3 -3
  19. package/dist/cli/main.js +5 -3
  20. package/dist/cli/plugins.js +4 -4
  21. package/dist/cli/snapshot-create.js +4 -4
  22. package/dist/cli/upgrade.d.ts +1 -1
  23. package/dist/cli/upgrade.js +3 -3
  24. package/dist/{client-BjgbMawj.js → client-Cqf4TboL.js} +20 -15
  25. package/dist/{config-CdB6yJj5.js → config-CPsE4T5L.js} +2 -2
  26. package/dist/{connections-RE_65jzK.js → connections-upFXLmhG.js} +10 -11
  27. package/dist/{conversation-DSo310Ps.js → conversation-CTpD_PGk.js} +7 -84
  28. package/dist/{conversation-privacy-BzgJC5k0.js → conversation-privacy-D6zJc8ff.js} +1 -1
  29. package/dist/{credential-sync-DhEGEpgq.js → credential-sync-CS_6IC-f.js} +30 -34
  30. package/dist/{credentialed-CIGwoLU2.js → credentialed-BU-OW7HP.js} +577 -74
  31. package/dist/{store-B8CABbmR.d.ts → db-BzOCzVb1.d.ts} +17 -7
  32. package/dist/{executor-VYrx_K4w.js → executor-CNS7ONt-.js} +78 -4
  33. package/dist/instrumentation.js +2 -2
  34. package/dist/{assistant-reply-CT7VcXQe.js → interruption-marker-g6Xup3Fk.js} +8 -2
  35. package/dist/{job-queue-C0BZSa7r.js → job-queue-DI-k-Bbk.js} +2 -2
  36. package/dist/{list-1XQP-o6K.js → list-CGoQdXTp.js} +429 -1401
  37. package/dist/locks-D-0h111u.js +48 -0
  38. package/dist/{logging-DuZ1A4ab.js → logging-n7knse-O.js} +1 -1
  39. package/dist/{history-C84mlAwO.js → media-85PDJxO_.js} +83 -1
  40. package/dist/{message-NKSbbnA6.js → message-BpaWd8TT.js} +4 -4
  41. package/dist/nitro.d.ts +1 -1
  42. package/dist/nitro.js +3 -3
  43. package/dist/{oauth-callback-server-qAHLPtml.js → oauth-callback-server-CpGmEw_i.js} +2 -2
  44. package/dist/{prompt-BW9jFsqZ.js → prompt-BlQB0QQt.js} +1 -1
  45. package/dist/{registry-FQutO926.js → registry-By36_xsm.js} +2 -2
  46. package/dist/reporting-schema-CZREhYc-.js +104 -0
  47. package/dist/reporting-window-CVarfId9.js +255 -0
  48. package/dist/{resolve-Bk4yeuHy.js → resolve-CUIBcdPd.js} +3 -3
  49. package/dist/{result-B9e9ATOU.js → result-BemsOMOO.js} +31 -12
  50. package/dist/{runner-C3S2ObH-.js → runner-BVok7PAA.js} +12 -11
  51. package/dist/{sandbox-egress-signals-DqpGzzMB.js → sandbox-egress-signals-BSUWQI95.js} +1 -1
  52. package/dist/{schema-X7Fj4fv1.js → schema-ChnFo5f2.js} +98 -6
  53. package/dist/schema-jK4-1u_H.d.ts +5927 -0
  54. package/dist/{service-account-Do30HUNv.js → service-account-DHvlLnZw.js} +4 -3
  55. package/dist/{service-account-BQasl-qq.js → service-account-hMmESDcr.js} +3 -3
  56. package/dist/{session-stop-DkOjt46_.js → session-stop-BQW_iFcd.js} +499 -23
  57. package/dist/{skills-CQHrwfOa.js → skills-DmJJIuLF.js} +2 -2
  58. package/dist/{spawn-BHuqN14f.js → spawn-ChCm46i-.js} +2 -2
  59. package/dist/{store-6EetVP-m.js → store-1DVhoKOL.js} +4 -4
  60. package/dist/{store-DvNZIsCr.js → store-DCo2n5iJ.js} +3 -3
  61. package/dist/{task-queue-B0DLgd2P.js → task-queue-HMC4QjFm.js} +3 -3
  62. package/dist/task-runner-cA6yjn_E.js +269 -0
  63. package/dist/{thread-state-DRmdJ2QN.js → thread-state-CHy8LS0C.js} +8 -18
  64. package/dist/{turn-failure-response-G11cs2gE.js → turn-failure-response-Dr7erLWs.js} +11 -16
  65. package/dist/{turn-lifecycle-OzLIwvi1.js → turn-lifecycle-bf2fIYi_.js} +1 -1
  66. package/dist/{tasks-0ilmuCux.js → turn-session-routing-BqO0qXLk.js} +959 -44
  67. package/dist/{validation-CxEmt1id.js → validation-DHR1ivfh.js} +1 -1
  68. package/dist/{version-Bapedn4A.js → version-CXCHLgWm.js} +1 -1
  69. package/dist/version.js +1 -1
  70. package/dist/{viewer-DrN3oC2X.js → viewer-DSbD6DF6.js} +503 -241
  71. package/dist/{work-DUQoNcqP.js → work-BE_qTYGi.js} +17 -36
  72. package/dist/{worker-D1l4Ugk0.js → worker-Cm9_sWXg.js} +15 -7
  73. package/migrations/0065_user_customization.sql +1 -0
  74. package/migrations/0066_review_items.sql +53 -0
  75. package/migrations/0067_review_item_dedupe_tenant.sql +2 -0
  76. package/migrations/0068_review_item_slack_cards.sql +10 -0
  77. package/migrations/0069_system_identity.sql +25 -0
  78. package/migrations/0070_review_item_foreign_keys.sql +5 -0
  79. package/migrations/AGENTS.md +17 -0
  80. package/migrations/meta/0065_snapshot.json +3511 -0
  81. package/migrations/meta/0066_snapshot.json +4099 -0
  82. package/migrations/meta/0067_snapshot.json +3921 -0
  83. package/migrations/meta/0068_snapshot.json +4176 -0
  84. package/migrations/meta/0069_snapshot.json +3979 -0
  85. package/migrations/meta/0070_snapshot.json +3997 -0
  86. package/migrations/meta/_journal.json +42 -0
  87. package/package.json +5 -5
  88. package/dist/db-Bg-zC3r5.d.ts +0 -5
  89. package/dist/history-BgI33Kie.d.ts +0 -78
  90. package/dist/images-CecjXAAz.js +0 -64
  91. package/dist/task-runner-B-PD_JOj.js +0 -1074
  92. package/dist/turn-session-routing-Dyut9l7Y.js +0 -76
  93. package/dist/user-input-request-BDFBdF8r.js +0 -116
  94. package/dist/web-message-id-CJSUiksE.js +0 -236
  95. package/migrations/README.md +0 -30
package/dist/api.js CHANGED
@@ -1,29 +1,28 @@
1
- import { D as AutomationConflictError, E as sameDefinitionValue, O as automationRevision, S as automationDefinition, T as readAutomationVersion, a as saveScheduledAutomation, j as automationEventCatalog, k as requireAutomationRevision, v as saveEventAutomation, y as setEventAutomationStatus } from "./tasks-0ilmuCux.js";
2
- import { p as escapeXml } from "./client-BjgbMawj.js";
3
- import { m as logInfo, p as logException } from "./logging-DuZ1A4ab.js";
4
- import { A as resolveRootConversationId, O as agentTurnUsageSchema, a as resolveViewerUser, f as getConversationStore, k as hasAgentTurnUsage, m as getSqlExecutor, p as getDb, s as updateViewerDisplayName, t as findUserByEmail } from "./viewer-DrN3oC2X.js";
5
- import { c as juniorIdentities, d as juniorDestinations, l as juniorUsers, s as juniorConversations } from "./agent-invocations-CxKldAeB.js";
6
- import { g as juniorApiTokens, h as juniorConversationEvents, m as juniorConversationMetrics, u as juniorConversationParticipants, v as juniorCodeChanges, y as juniorCodeRepositories } from "./executor-VYrx_K4w.js";
7
- import { n as pluginCatalogRuntime } from "./catalog-runtime-cMlAI5LY.js";
8
- import { I as webUserInputAnswerNote, K as editEventAutomation, L as parseSlackThreadId, O as persistSlackUserInputReply, S as readLiveAttachment, U as editScheduledAutomation, X as resolveTaskOutcomes, Z as listOwnedWatches, at as conversationSubtreeColumns, it as conversationSubtree, m as readStats, nt as listChildAgents, q as AutomationEditError } from "./agent-runner-DgNATN4D.js";
9
- import { C as listWorkspaces, E as WorkspaceValidationError, Et as workspaceRepoCheckoutPath, Gn as readConversationEventPage, Kn as buildSentryConversationUrl, M as hash, Nn as createPluginLogger, Pn as readConversationAccessFromSql, T as updateWorkspace, Wn as readLatestConversationBrief, ar as createPluginCache, b as deleteWorkspace, er as listConversationAnnotations, ir as lookupSlackUser, j as create, n as createUserTokenStore, p as getPlugins, un as runWithWorkspaceTeamId, w as listWorkspacesByRepository, wt as SANDBOX_RUNTIME, x as getWorkspace, y as createWorkspace } from "./credentialed-CIGwoLU2.js";
10
- import { i as getStateAdapter } from "./adapter-BybMEezj.js";
11
- import { t as getFirstRunAtMs } from "./cadence-R7Em4RjE.js";
12
- import { A as createConversationMessageBodySchema, G as INPUT_IMAGE_TYPES, M as forkConversationResponseSchema, N as steerConversationPendingMessagesBodySchema, P as steerConversationPendingMessagesResponseSchema, W as readMessageAttachments, _ as conversationParamsSchema, a as cancelConversationPendingMessagesBodySchema, c as conversationAttachmentParamsSchema, d as conversationDetailReportSchema, g as conversationFeedSchema, h as conversationFeedQuerySchema, i as archiveConversationResponseSchema, j as forkConversationBodySchema, k as createConversationBodySchema, m as conversationEventsQuerySchema, o as cancelConversationPendingMessagesResponseSchema, p as conversationEventPageSchema, r as archiveConversationBodySchema, t as acceptedConversationMessageSchema, u as conversationDetailQuerySchema, x as conversationPendingMessagesReportSchema } from "./conversation-DSo310Ps.js";
13
- import { h as getChildAgentLabel } from "./store-6EetVP-m.js";
14
- import { d as getEventCatalog } from "./session-stop-DkOjt46_.js";
15
- import { s as getSandboxResources, t as getCachedSnapshot } from "./resolve-Bk4yeuHy.js";
16
- import { a as getVercelConversationWorkQueue } from "./job-queue-C0BZSa7r.js";
17
- import { E as steerWebPendingMessages, a as cancelHumanFacingPendingMessages, g as getConversationWorkState, h as getConversation } from "./store-DvNZIsCr.js";
18
- import { n as finishServiceAccountSignIn, o as serviceAccountPlugins, r as getServiceAccountStatus, s as startServiceAccountSignIn, t as disconnectServiceAccount } from "./service-account-Do30HUNv.js";
19
- import { F as weekdaySchema, M as ScheduleIntentError, N as compileScheduleIntent, _ as automationSummarySchema, b as automationVersionListSchema, c as automationLifecycleSchema, d as automationParamsSchema, f as automationRunListSchema, g as automationSchedulePreviewSchema, h as automationScheduleIntentSchema, i as automationExecutionListSchema, l as automationListQuerySchema, n as automationEditSchema, r as automationEventCatalogSchema, t as automationEditErrorSchema, u as automationListSchema, v as automationUpdateSchema, x as automationVersionParamsSchema, y as automationVersionActivateSchema } from "./automation-CmeFBSEh.js";
20
- import { C as skillReportsSchema, a as fillUtcHours, b as pluginsSchema, c as sumUtcHoursIntoSixHours, d as trailingUtcSixHourWindow, f as utcDayKey, h as pluginOperationalReportFeedSchema, i as fillUtcDays, l as trailingUtcDayWindow, m as healthReportSchema, n as DAY_MS$1, o as fillUtcSixHours, p as utcHourKey, r as HOUR_MS$1, s as startOfUtcHour, t as webMessageId, u as trailingUtcHourWindow, x as runtimeInfoReportSchema } from "./web-message-id-CJSUiksE.js";
21
- import { A as readViewerAutomationRuns, D as deleteViewerTask, E as ViewerTaskNotFoundError, H as clearSlackPendingReactions, L as isAllowedSignInEmail, M as readViewerAutomationVersions, N as readViewerAutomations, O as readConversationSourceTask, P as resolveViewerTaskCandidate, _ as appendAndEnqueueWebMessage, a as resolveMentions, c as readConversationAuxiliaryCostsFromSql, d as notCopiedByFork, et as getAttachmentStorage, f as childAgentTotalsReport, g as resolveSlackTeamDomains, h as conversationSummaryFromStoredConversation, i as attachConversationMentions, it as readHealthReport, j as readViewerAutomationSummary, k as readViewerAutomationExecutions, l as ConversationForkError, m as conversationEventHistory, n as readConversationRecordFromSql, o as readFirstHumanMessageTexts, p as readConversationTreeMetricsFromSql, q as stopConversationTurn, r as readConversationParticipants, s as listConversationSidebarAnnotations, t as readConversationFeed, u as forkConversation, w as getProductionSlackAdapter, x as webActorFromEmail, y as createAndEnqueueConversation } from "./list-1XQP-o6K.js";
22
- import { F as conversationAggregateColumns, I as conversationRangeColumns, M as readAutomationTitlesByConversationId, P as conversationActiveDaysColumn } from "./task-runner-B-PD_JOj.js";
23
- import { d as legacyWebMailboxMetadataSchema } from "./result-B9e9ATOU.js";
24
- import { a as startConnection, l as getWebAuthorization, n as isConnectableProvider, r as listConnections, t as disconnectConnection, u as htmlCallbackResponse } from "./connections-RE_65jzK.js";
25
- import { t as decodeInputImages } from "./images-CecjXAAz.js";
26
- import { A as activityHours$1, C as personParamsSchema, D as locationDirectoryReportSchema, E as locationDetailReportSchema, H as codePersonReportSchema, I as disconnectConnectionResponseSchema, L as startConnectionResponseSchema, N as connectionListSchema, O as locationParamsSchema, P as connectionParamsSchema, Q as apiErrorSchema, S as actorProfileReportSchema, U as codeRepositoryParamsSchema, V as codeOverviewReportSchema, W as codeRepositoryReportSchema, X as stopConversationTurnResponseSchema, Y as conversationChildAgentsReportSchema, Z as conversationStatsReportSchema, _ as personalTokenListSchema, a as workspaceBodySchema, b as revokePersonalTokenResponseSchema, d as serviceAccountListSchema, f as serviceAccountParamsSchema, g as createdPersonalTokenSchema, h as createPersonalTokenBodySchema, i as deleteWorkspaceResponseSchema, j as activitySixHours$1, k as activityDays$1, l as workspaceSchema, m as startServiceAccountSignInResponseSchema, n as statsReportSchema, o as workspaceListSchema, q as conversationWatchesReportSchema, s as workspaceParamsSchema, u as disconnectServiceAccountResponseSchema, w as personalSpendReportSchema, x as actorDirectoryReportSchema, y as personalTokenParamsSchema } from "./schema-X7Fj4fv1.js";
1
+ import { F as conversationRangeColumns, N as conversationActiveDaysColumn, P as conversationAggregateColumns, Ur as isExperimentalFeatureEnabled, ct as AutomationConflictError, ft as automationEventCatalog, j as readAutomationTitlesByConversationId } from "./turn-session-routing-BqO0qXLk.js";
2
+ import { p as escapeXml } from "./client-Cqf4TboL.js";
3
+ import { m as logInfo, p as logException } from "./logging-n7knse-O.js";
4
+ import { C as getSqlExecutor, J as resolveRootConversationId, K as agentTurnUsageSchema, S as getDb, c as readViewerAvatarUrl, d as updateViewerDisplayName, l as resolveViewerUser, m as readAvatarImage, q as hasAgentTurnUsage, t as findUserByEmail, x as getConversationStore } from "./viewer-DSbD6DF6.js";
5
+ import { c as juniorIdentities, d as juniorDestinations, l as juniorUsers, s as juniorConversations } from "./agent-invocations-C1RNOCs8.js";
6
+ import { C as juniorCodeRepositories, S as juniorCodeChanges, b as juniorApiTokens, m as juniorConversationParticipants, v as juniorConversationMetrics, y as juniorConversationEvents } from "./executor-CNS7ONt-.js";
7
+ import { t as INPUT_IMAGE_TYPES } from "./media-85PDJxO_.js";
8
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-BsoSmTM0.js";
9
+ import { $ as listOwnedWatches, B as changeViewerAutomationLifecycle, Dt as readUserCustomization, G as readConversationSourceTask, H as readViewerAutomationEdit, J as readViewerAutomationSummary, K as readViewerAutomationExecutions, Ot as saveUserCustomization, St as conversationSubtreeColumns, U as updateViewerAutomation, V as deleteViewerTask, W as ViewerTaskNotFoundError, X as readViewerAutomations, Y as readViewerAutomationVersions, Z as AutomationEditError, at as createAndEnqueueConversation, ct as webActorFromEmail, ft as readLiveAttachment, m as readStats, nt as acceptsWebMessages, q as readViewerAutomationRuns, rt as appendAndEnqueueWebMessage, ut as decodeInputImages, x as createSlackReviewItemShow, xt as conversationSubtree, yt as listChildAgents, z as activateViewerAutomationVersion } from "./agent-runner-CrDrPUtY.js";
10
+ import { $t as workspaceRepoCheckoutPath, Ar as lookupSlackUser, D as listWaitingConversationIds, Er as listConversationAnnotations, F as isOnlyAssignee, G as deleteWorkspace, J as listWorkspaces, K as getWorkspace, M as canActOnReviewItem, O as searchReviewItems, W as createWorkspace, X as updateWorkspace, Y as listWorkspacesByRepository, Z as WorkspaceValidationError, Zt as SANDBOX_RUNTIME, _r as readConversationEventPage, ar as createPluginLogger, gr as readLatestConversationBrief, jr as createPluginCache, n as createUserTokenStore, nt as create, or as readConversationAccessFromSql, p as getPlugins, rt as hash, vr as buildSentryConversationUrl, x as countReviewItemsNeedingUser, z as reviewItemReaderForUser } from "./credentialed-BU-OW7HP.js";
11
+ import { r as getStateAdapter } from "./adapter-2-CG25be.js";
12
+ import { A as createConversationMessageBodySchema, M as forkConversationResponseSchema, N as steerConversationPendingMessagesBodySchema, P as steerConversationPendingMessagesResponseSchema, W as readMessageAttachments, _ as conversationParamsSchema, a as cancelConversationPendingMessagesBodySchema, c as conversationAttachmentParamsSchema, d as conversationDetailReportSchema, g as conversationFeedSchema, h as conversationFeedQuerySchema, i as archiveConversationResponseSchema, j as forkConversationBodySchema, k as createConversationBodySchema, m as conversationEventsQuerySchema, o as cancelConversationPendingMessagesResponseSchema, p as conversationEventPageSchema, r as archiveConversationBodySchema, t as acceptedConversationMessageSchema, u as conversationDetailQuerySchema, x as conversationPendingMessagesReportSchema } from "./conversation-CTpD_PGk.js";
13
+ import { h as getChildAgentLabel } from "./store-1DVhoKOL.js";
14
+ import { d as getEventCatalog } from "./session-stop-BQW_iFcd.js";
15
+ import { a as fillUtcSixHours, c as trailingUtcDayWindow, d as utcDayKey, f as utcHourKey, i as fillUtcHours, l as trailingUtcHourWindow, n as HOUR_MS$1, o as startOfUtcHour, r as fillUtcDays, s as sumUtcHoursIntoSixHours, t as DAY_MS$1, u as trailingUtcSixHourWindow, x as userCustomizationSchema, y as webMessageId } from "./reporting-window-CVarfId9.js";
16
+ import { s as getSandboxResources, t as getCachedSnapshot } from "./resolve-CUIBcdPd.js";
17
+ import { a as getVercelConversationWorkQueue } from "./job-queue-DI-k-Bbk.js";
18
+ import { E as steerWebPendingMessages, a as cancelHumanFacingPendingMessages, g as getConversationWorkState, h as getConversation } from "./store-DCo2n5iJ.js";
19
+ import { n as finishServiceAccountSignIn, o as serviceAccountPlugins, r as getServiceAccountStatus, s as startServiceAccountSignIn, t as disconnectServiceAccount } from "./service-account-DHvlLnZw.js";
20
+ import { N as ScheduleIntentError, P as compileScheduleIntent, _ as automationSummarySchema, b as automationVersionListSchema, c as automationLifecycleSchema, d as automationParamsSchema, f as automationRunListSchema, g as automationSchedulePreviewSchema, h as automationScheduleIntentSchema, i as automationExecutionListSchema, l as automationListQuerySchema, n as automationEditSchema, r as automationEventCatalogSchema, t as automationEditErrorSchema, u as automationListSchema, v as automationUpdateSchema, x as automationVersionParamsSchema, y as automationVersionActivateSchema } from "./automation-p87hg_AV.js";
21
+ import { c as runtimeInfoReportSchema, n as pluginOperationalReportFeedSchema, s as pluginsSchema, t as healthReportSchema, u as skillReportsSchema } from "./reporting-schema-CZREhYc-.js";
22
+ import { B as actOnReviewItem, C as isAllowedSignInEmail, H as readReviewItemForUser, J as readHealthReport, N as stopConversationTurn, O as clearSlackPendingReactions, V as closeReviewItemsAnsweredByReply, W as getAttachmentStorage, a as resolveMentions, c as readConversationAuxiliaryCostsFromSql, d as notCopiedByFork, f as childAgentTotalsReport, g as resolveSlackTeamDomains, h as conversationSummaryFromStoredConversation, i as attachConversationMentions, l as ConversationForkError, m as conversationEventHistory, n as readConversationRecordFromSql, o as readFirstHumanMessageTexts, p as readConversationTreeMetricsFromSql, r as readConversationParticipants, s as listConversationSidebarAnnotations, t as readConversationFeed, u as forkConversation, y as getProductionSlackAdapter, z as ReviewItemActionError } from "./list-CGoQdXTp.js";
23
+ import { d as legacyWebMailboxMetadataSchema } from "./result-BemsOMOO.js";
24
+ import { a as startConnection, l as getWebAuthorization, n as isConnectableProvider, r as listConnections, t as disconnectConnection, u as htmlCallbackResponse } from "./connections-upFXLmhG.js";
25
+ import { A as avatarParamsSchema, C as createdPersonalTokenSchema, D as revokePersonalTokenResponseSchema, E as personalTokenParamsSchema, F as locationDirectoryReportSchema, G as startConnectionResponseSchema, H as connectionParamsSchema, I as locationParamsSchema, L as activityDays$1, M as personalSpendReportSchema, O as actorDirectoryReportSchema, P as locationDetailReportSchema, Q as codeRepositoryReportSchema, R as activityHours$1, S as createPersonalTokenBodySchema, V as connectionListSchema, W as disconnectConnectionResponseSchema, X as codePersonReportSchema, Y as codeOverviewReportSchema, Z as codeRepositoryParamsSchema, _ as disconnectServiceAccountResponseSchema, a as workspaceBodySchema, at as conversationStatsReportSchema, d as reviewItemCountSchema, f as reviewItemListQuerySchema, g as reviewItemWaitingConversationsSchema, h as reviewItemSchema, i as deleteWorkspaceResponseSchema, it as stopConversationTurnResponseSchema, j as personParamsSchema, k as actorProfileReportSchema, l as workspaceSchema, m as reviewItemParamsSchema, n as statsReportSchema, o as workspaceListSchema, ot as apiErrorSchema, p as reviewItemListSchema, rt as conversationChildAgentsReportSchema, s as workspaceParamsSchema, tt as conversationWatchesReportSchema, u as reviewItemActionSchema, v as serviceAccountListSchema, w as personalTokenListSchema, x as startServiceAccountSignInResponseSchema, y as serviceAccountParamsSchema, z as activitySixHours$1 } from "./schema-ChnFo5f2.js";
27
26
  import { Hono } from "hono";
28
27
  import path from "node:path";
29
28
  import { z } from "zod";
@@ -257,8 +256,7 @@ async function createConversationForViewer(viewer, body, services) {
257
256
  async function appendConversationMessageForViewer(viewer, conversationId, body, services) {
258
257
  const conversation = await getConversationStore().get({ conversationId });
259
258
  if (!conversation) throwApiError(404, "Conversation not found.");
260
- const destinationPlatform = conversation.destination?.platform;
261
- if (!(destinationPlatform === "local" && conversationId.startsWith("local:web:") || destinationPlatform === "slack")) throwApiError(409, "Conversation does not accept web messages.");
259
+ if (!acceptsWebMessages(conversationId, conversation.destination)) throwApiError(409, "Conversation does not accept web messages.");
262
260
  if (!(await readConversationAccessFromSql(getDb(), [conversationId], viewer)).get(conversationId)?.isParticipant) throwApiError(403, "Only conversation participants can add messages.");
263
261
  const images = parseImages(body.images);
264
262
  const actor = actorFromViewer(viewer);
@@ -273,31 +271,34 @@ async function appendConversationMessageForViewer(viewer, conversationId, body,
273
271
  attachmentStorage: services.attachmentStorage,
274
272
  queue: services.queue
275
273
  });
276
- const destination = conversation.destination;
274
+ const closeAnswered = () => closeReviewItemsAnsweredByReply({
275
+ conversationId,
276
+ delivery: {
277
+ queue: services.queue,
278
+ show: createSlackReviewItemShow(getProductionSlackAdapter)
279
+ },
280
+ resolveUser: async () => viewer,
281
+ text: body.message
282
+ });
277
283
  try {
278
- if (destination?.platform !== "slack") return await append();
279
- return await runWithWorkspaceTeamId(destination.teamId, async () => {
284
+ let accepted;
285
+ try {
286
+ accepted = await append();
287
+ } catch (error) {
280
288
  const state = getStateAdapter();
281
289
  await state.connect();
282
- return persistSlackUserInputReply({
283
- channelId: destination.channelId,
284
- claimedBy: viewer.email,
285
- isSaved: async () => {
286
- const [messageId, work] = await Promise.all([webMessageId({
287
- conversationId,
288
- idempotencyKey: body.idempotencyKey
289
- }), getConversationWorkState({
290
- conversationId,
291
- state
292
- })]);
293
- return work?.execution.inboundMessageIds.includes(messageId) === true;
294
- },
295
- note: () => webUserInputAnswerNote(viewer.displayName ?? viewer.email),
296
- persist: append,
297
- state,
298
- threadTs: conversation.location?.threadTs ?? parseSlackThreadId(conversationId)?.threadTs
299
- });
300
- });
290
+ const [messageId, work] = await Promise.all([webMessageId({
291
+ conversationId,
292
+ idempotencyKey: body.idempotencyKey
293
+ }), getConversationWorkState({
294
+ conversationId,
295
+ state
296
+ })]);
297
+ if (work?.execution.inboundMessageIds.includes(messageId)) await closeAnswered();
298
+ throw error;
299
+ }
300
+ await closeAnswered();
301
+ return accepted;
301
302
  } catch (error) {
302
303
  throwApiError(500, "Unable to append message.", error);
303
304
  }
@@ -2695,7 +2696,7 @@ async function readPeoplePluginReports(args) {
2695
2696
  reports: [],
2696
2697
  source: "plugins"
2697
2698
  });
2698
- const { getPluginProfileReports } = await import("./credentialed-CIGwoLU2.js").then((n) => n.a);
2699
+ const { getPluginProfileReports } = await import("./credentialed-BU-OW7HP.js").then((n) => n.a);
2699
2700
  return pluginOperationalReportFeedSchema.parse({
2700
2701
  generatedAt: new Date(nowMs).toISOString(),
2701
2702
  reports: await getPluginProfileReports({
@@ -2904,6 +2905,23 @@ function spendWindow(nowMs) {
2904
2905
  thirtyDayStart
2905
2906
  };
2906
2907
  }
2908
+ /**
2909
+ * Read a cheap change marker for one viewer's spend window.
2910
+ *
2911
+ * Writes that record Conversation metrics also move `updated_at` forward, so
2912
+ * the marker changes when spend can change. The spend cache TTL bounds changes
2913
+ * that the marker misses, such as a day that leaves the window.
2914
+ */
2915
+ async function readPersonalSpendVersion(email, nowMs = Date.now()) {
2916
+ const normalizedEmail = normalizeEmail$1(email);
2917
+ if (!normalizedEmail) return "";
2918
+ const { end, thirtyDayStart } = spendWindow(nowMs);
2919
+ const [row] = await getDb().select({
2920
+ conversations: sql`count(*)::int`,
2921
+ updatedAt: sql`max(${juniorConversations.updatedAt})::text`
2922
+ }).from(juniorConversations).innerJoin(juniorIdentities, eq(juniorIdentities.id, juniorConversations.actorIdentityId)).innerJoin(juniorUsers, eq(juniorUsers.id, juniorIdentities.userId)).where(and(verifiedActorWhere(normalizedEmail), gte(juniorConversations.lastActivityAt, thirtyDayStart), lte(juniorConversations.lastActivityAt, end)));
2923
+ return `${row?.conversations ?? 0}:${row?.updatedAt ?? ""}`;
2924
+ }
2907
2925
  /** Read one viewer's rolling model spend with one bounded aggregate query. */
2908
2926
  async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
2909
2927
  const normalizedEmail = normalizeEmail$1(email);
@@ -2936,19 +2954,27 @@ async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
2936
2954
  }
2937
2955
  // src/api/people/spend.ts
2938
2956
  const PERSONAL_SPEND_CACHE_TTL_MS = 3e5;
2939
- /** Create an app-scoped personal-spend reader with a five-minute cache. */
2957
+ /**
2958
+ * Create an app-scoped personal-spend reader.
2959
+ *
2960
+ * A cached report stays valid for five minutes, or until the viewer's spend
2961
+ * version changes. The dashboard can poll often and still see a finished Turn
2962
+ * without a full aggregate query on every poll.
2963
+ */
2940
2964
  function createPersonalSpendReader() {
2941
2965
  const cache = /* @__PURE__ */ new Map();
2942
2966
  return async function readPersonalSpend(email) {
2943
2967
  const normalizedEmail = email.trim().toLowerCase();
2944
2968
  const nowMs = Date.now();
2969
+ const version = await readPersonalSpendVersion(normalizedEmail, nowMs);
2945
2970
  const cached = cache.get(normalizedEmail);
2946
- if (cached && cached.expiresAtMs > nowMs) return cached.report;
2971
+ if (cached && cached.expiresAtMs > nowMs && cached.version === version) return cached.report;
2947
2972
  cache.delete(normalizedEmail);
2948
2973
  const report = readPersonalSpendFromSql(normalizedEmail, nowMs);
2949
2974
  const entry = {
2950
2975
  expiresAtMs: nowMs + PERSONAL_SPEND_CACHE_TTL_MS,
2951
- report
2976
+ report,
2977
+ version
2952
2978
  };
2953
2979
  cache.set(normalizedEmail, entry);
2954
2980
  try {
@@ -2964,6 +2990,17 @@ function createPersonalSpendReader() {
2964
2990
  function createPeopleRoutes() {
2965
2991
  const app = new Hono();
2966
2992
  const readPersonalSpend = createPersonalSpendReader();
2993
+ app.get("/avatars/:identityId", requireViewer, validateRequest("param", avatarParamsSchema, "Invalid route parameters."), async (context) => {
2994
+ const { identityId } = context.req.valid("param");
2995
+ const image = await readAvatarImage(getDb(), getStateAdapter(), identityId);
2996
+ if (!image) throwApiError(404, "Avatar not found.");
2997
+ return new Response(Buffer.from(image.data, "base64"), { headers: {
2998
+ "cache-control": "private, max-age=86400",
2999
+ "content-security-policy": "default-src 'none'; sandbox",
3000
+ "content-type": image.contentType,
3001
+ "x-content-type-options": "nosniff"
3002
+ } });
3003
+ });
2967
3004
  app.get("/me/spend", requireViewer, async (context) => {
2968
3005
  const viewer = context.get("viewer");
2969
3006
  return jsonResponse(personalSpendReportSchema, await readPersonalSpend(viewer.email));
@@ -3207,233 +3244,6 @@ function createUserPageRoutes() {
3207
3244
  });
3208
3245
  return app;
3209
3246
  }
3210
- // src/chat/automations/edit.ts
3211
- /**
3212
- * Web edits. Owners and public Destination readers can edit. Creator-only
3213
- * rules still apply, and lifecycle actions stay creator-only.
3214
- */
3215
- /** Owners and public Destination readers can edit. Others get not found. */
3216
- async function requireEditableAutomation(user, id) {
3217
- const candidate = await resolveViewerTaskCandidate(user, id);
3218
- if (!candidate) throw new ViewerTaskNotFoundError();
3219
- return candidate;
3220
- }
3221
- /** Lifecycle actions are creator-only. Others get not found. */
3222
- async function requireOwnedAutomation(user, id) {
3223
- const candidate = await requireEditableAutomation(user, id);
3224
- if (!candidate.ownedByViewer) throw new ViewerTaskNotFoundError();
3225
- return candidate;
3226
- }
3227
- /** Record the viewer's Slack identity in the Automation workspace as the editor. */
3228
- function viewerEditor(user, automation) {
3229
- if (automation.ownedByViewer) return automation.task.createdBy;
3230
- const identity = user.identities.find((candidate) => candidate.provider === "slack" && candidate.providerTenantId === automation.task.destination.teamId);
3231
- if (!identity) return void 0;
3232
- const editor = { slackUserId: identity.providerSubjectId };
3233
- if (identity.displayName) editor.fullName = identity.displayName;
3234
- if (identity.handle) editor.userName = identity.handle;
3235
- return editor;
3236
- }
3237
- function editView(automation, ownedByViewer) {
3238
- const { task } = automation;
3239
- const common = {
3240
- ownedByViewer,
3241
- id: task.id,
3242
- revision: automationRevision(task),
3243
- title: task.title ?? null,
3244
- instruction: task.task.text,
3245
- credentialMode: task.credentialMode,
3246
- outcomes: task.outcomes,
3247
- destination: task.destination,
3248
- createdBy: task.createdBy
3249
- };
3250
- if (automation.kind === "scheduled") {
3251
- const status = automation.task.status;
3252
- if (status === "deleted") throw new ViewerTaskNotFoundError();
3253
- return {
3254
- ...common,
3255
- kind: "scheduled",
3256
- status,
3257
- schedule: automation.task.schedule,
3258
- nextRunAtMs: automation.task.nextRunAtMs
3259
- };
3260
- }
3261
- return {
3262
- ...common,
3263
- kind: "event",
3264
- status: automation.task.status === "deleted" ? "active" : automation.task.status,
3265
- trigger: automation.task.trigger
3266
- };
3267
- }
3268
- /** Load exact editable values by ID, independent of list filters. */
3269
- async function readViewerAutomationEdit(user, id) {
3270
- const automation = await requireEditableAutomation(user, id);
3271
- return editView(automation, automation.ownedByViewer);
3272
- }
3273
- /** Save a partial edit against the read revision, without dispatching work. */
3274
- async function updateViewerAutomation(user, id, input) {
3275
- const current = await requireEditableAutomation(user, id);
3276
- if (input.kind !== current.kind) throw new AutomationEditError("The trigger type cannot change.", "kind");
3277
- requireAutomationRevision(current.task, input.revision);
3278
- return saveViewerEdit(user, current, input);
3279
- }
3280
- /** `restored` carries version values that edit input cannot express, such as a cleared title. */
3281
- async function saveViewerEdit(user, current, input, restored) {
3282
- const isCreator = current.ownedByViewer;
3283
- const editedBy = viewerEditor(user, current);
3284
- if (input.kind === "scheduled" && current.kind === "scheduled") {
3285
- const next = await editScheduledAutomation(current.task, input, isCreator, Date.now());
3286
- return editView({
3287
- kind: "scheduled",
3288
- task: await saveScheduledAutomation(getDb(), restored ? {
3289
- ...next,
3290
- ...restored
3291
- } : next, input.revision, editedBy)
3292
- }, isCreator);
3293
- }
3294
- if (input.kind === "event" && current.kind === "event") {
3295
- const next = await editEventAutomation(current.task, input, isCreator, getEventCatalog());
3296
- const task = await saveEventAutomation(getDb(), restored ? {
3297
- ...next,
3298
- title: restored.title
3299
- } : next, input.revision, editedBy);
3300
- if (!task) throw new ViewerTaskNotFoundError();
3301
- return editView({
3302
- kind: "event",
3303
- task
3304
- }, isCreator);
3305
- }
3306
- throw new ViewerTaskNotFoundError();
3307
- }
3308
- function scheduleIntent(schedule) {
3309
- const recurrence = schedule.recurrence;
3310
- if (schedule.kind !== "recurring" || !recurrence) throw new AutomationEditError("A one-time Schedule cannot be restored. Set a new time in the editor.", "schedule");
3311
- return {
3312
- kind: "recurring",
3313
- frequency: recurrence.frequency,
3314
- interval: recurrence.interval,
3315
- time: `${String(recurrence.time.hour).padStart(2, "0")}:${String(recurrence.time.minute).padStart(2, "0")}`,
3316
- weekdays: recurrence.weekdays?.map((day) => weekdaySchema.options[day]),
3317
- dayOfMonth: recurrence.dayOfMonth,
3318
- month: recurrence.month,
3319
- startDate: recurrence.startDate,
3320
- timezone: schedule.timezone
3321
- };
3322
- }
3323
- /**
3324
- * Turn saved outcomes back into edit input. Messages to the Automation
3325
- * Destination or the creator DM are always allowed again. Other stored
3326
- * Destinations must still be on the Automation.
3327
- */
3328
- async function restorableOutcomes(current, outcomes) {
3329
- const { task } = current;
3330
- let creatorDm;
3331
- const restored = [];
3332
- for (const outcome of outcomes) {
3333
- if (sameDefinitionValue(outcome.destination, task.destination)) {
3334
- restored.push({
3335
- action: outcome.action,
3336
- destination: "current_conversation"
3337
- });
3338
- continue;
3339
- }
3340
- if (current.ownedByViewer && !task.outcomes.some((stored) => sameDefinitionValue(stored, outcome))) {
3341
- creatorDm ??= (await resolveTaskOutcomes([{
3342
- action: "send_message",
3343
- destination: "task_creator"
3344
- }], task.destination, task.createdBy.slackUserId))[0].destination;
3345
- if (sameDefinitionValue(outcome.destination, creatorDm)) {
3346
- restored.push({
3347
- action: outcome.action,
3348
- destination: "task_creator"
3349
- });
3350
- continue;
3351
- }
3352
- }
3353
- restored.push(outcome);
3354
- }
3355
- return restored;
3356
- }
3357
- /**
3358
- * Make a saved version active. This saves its definition as a new version
3359
- * through the same edit rules, so history is never rewritten.
3360
- */
3361
- async function activateViewerAutomationVersion(user, id, input) {
3362
- const current = await requireEditableAutomation(user, id);
3363
- requireAutomationRevision(current.task, input.revision);
3364
- const saved = await readAutomationVersion(getDb(), id, input.version);
3365
- if (!saved) throw new AutomationEditError("This version does not exist.", "version");
3366
- const { definition } = saved;
3367
- if (sameDefinitionValue(definition, automationDefinition(current.task))) return editView(current, current.ownedByViewer);
3368
- if (!sameDefinitionValue(definition.destination, current.task.destination)) throw new AutomationEditError("This version delivers to another Destination. Move the automation from Slack instead.", "destination");
3369
- const fields = {};
3370
- if (definition.instruction !== current.task.task.text) fields.instruction = definition.instruction;
3371
- if (definition.credentialMode !== current.task.credentialMode) fields.credentialMode = definition.credentialMode;
3372
- if (!sameDefinitionValue(definition.outcomes, current.task.outcomes)) fields.outcomes = await restorableOutcomes(current, definition.outcomes);
3373
- const title = definition.title ?? void 0;
3374
- if (saved.kind === "scheduled" && current.kind === "scheduled") {
3375
- const update = {
3376
- kind: "scheduled",
3377
- revision: input.revision,
3378
- ...fields
3379
- };
3380
- const restored = { title };
3381
- const { schedule } = saved.definition;
3382
- if (!sameDefinitionValue(schedule, current.task.schedule)) {
3383
- update.schedule = scheduleIntent(schedule);
3384
- restored.schedule = schedule;
3385
- }
3386
- return saveViewerEdit(user, current, update, restored);
3387
- }
3388
- if (saved.kind === "event" && current.kind === "event") {
3389
- const update = {
3390
- kind: "event",
3391
- revision: input.revision,
3392
- ...fields
3393
- };
3394
- if (!sameDefinitionValue(saved.definition.trigger, current.task.trigger)) update.trigger = saved.definition.trigger;
3395
- return saveViewerEdit(user, current, update, { title });
3396
- }
3397
- throw new ViewerTaskNotFoundError();
3398
- }
3399
- /** Pause or resume future triggers. Already-claimed work can finish. */
3400
- async function changeViewerAutomationLifecycle(user, id, input) {
3401
- const current = await requireOwnedAutomation(user, id);
3402
- requireAutomationRevision(current.task, input.revision);
3403
- const status = current.task.status;
3404
- if (status === "completed") throw new AutomationEditError("Completed Automations cannot be restarted.");
3405
- if (input.action === "pause" && status === "paused") return editView(current, true);
3406
- if (input.action === "resume" && status !== "paused" && status !== "blocked") throw new AutomationEditError("Only paused or blocked Automations can be resumed.");
3407
- if (current.kind === "event") return editView({
3408
- kind: "event",
3409
- task: await setEventAutomationStatus(getDb(), id, input.action === "pause" ? "paused" : "active", input.revision)
3410
- }, true);
3411
- const nowMs = Date.now();
3412
- const next = {
3413
- ...current.task,
3414
- updatedAtMs: nowMs,
3415
- runNowAtMs: void 0
3416
- };
3417
- if (input.action === "pause") {
3418
- next.status = "paused";
3419
- if (status === "blocked") next.statusReason ??= "A requirement blocked this Automation. Inspect its executions before resuming.";
3420
- } else {
3421
- next.status = status === "paused" && next.statusReason ? "blocked" : "active";
3422
- if (next.status === "active") {
3423
- next.nextRunAtMs = next.schedule.recurrence ? getFirstRunAtMs({
3424
- afterMs: nowMs,
3425
- recurrence: next.schedule.recurrence,
3426
- timezone: next.schedule.timezone
3427
- }) : next.nextRunAtMs;
3428
- if (!next.nextRunAtMs || next.nextRunAtMs <= nowMs) throw new AutomationEditError("This Schedule has no future occurrence. Set a future Schedule before resuming.", "schedule");
3429
- next.statusReason = void 0;
3430
- }
3431
- }
3432
- return editView({
3433
- kind: "scheduled",
3434
- task: await saveScheduledAutomation(getDb(), next, input.revision)
3435
- }, true);
3436
- }
3437
3247
  // src/chat/automations/editor.ts
3438
3248
  /** Read-only editor support. Core owns schedules; plugins own Event choices. */
3439
3249
  /**
@@ -3611,6 +3421,171 @@ function createAutomationRoutes() {
3611
3421
  });
3612
3422
  return app;
3613
3423
  }
3424
+ // src/api/user-customization/routes.ts
3425
+ /**
3426
+ * Create routes that read and replace the viewer's customization. They return
3427
+ * 404 unless the app enables the `user-customization` experiment.
3428
+ */
3429
+ function createUserCustomizationRoutes() {
3430
+ const app = new Hono();
3431
+ app.use("*", async (_context, next) => {
3432
+ if (!isExperimentalFeatureEnabled("user-customization")) throwApiError(404, "Resource not found.");
3433
+ await next();
3434
+ });
3435
+ app.get("/", requireViewer, async (context) => {
3436
+ const viewer = context.get("viewer");
3437
+ return jsonResponse(userCustomizationSchema, { customization: await readUserCustomization(viewer.id) ?? "" });
3438
+ });
3439
+ app.put("/", requireViewer, validateRequest("json", userCustomizationSchema, "Invalid request body."), async (context) => {
3440
+ const viewer = context.get("viewer");
3441
+ const { customization } = context.req.valid("json");
3442
+ if (!await saveUserCustomization(viewer.id, customization)) throwApiError(404, "User not found.");
3443
+ return jsonResponse(userCustomizationSchema, { customization });
3444
+ });
3445
+ return app;
3446
+ }
3447
+ // src/api/review-items/routes.ts
3448
+ const ARCHIVED_LIMIT = 50;
3449
+ const cursorSchema = z.object({
3450
+ conversationId: z.string().min(1).optional(),
3451
+ id: z.string().min(1),
3452
+ query: z.string().min(1).optional(),
3453
+ updatedAtMs: z.number().int(),
3454
+ version: z.literal(1)
3455
+ }).strict();
3456
+ /**
3457
+ * Encode the last open item of a page as the cursor of the next page. The
3458
+ * cursor names its list, so it cannot page through a different list.
3459
+ */
3460
+ function encodeCursor(item, filters) {
3461
+ return Buffer.from(JSON.stringify({
3462
+ ...filters,
3463
+ id: item.id,
3464
+ updatedAtMs: item.updatedAt.getTime(),
3465
+ version: 1
3466
+ }), "utf8").toString("base64url");
3467
+ }
3468
+ /** Decode a cursor of the same list, or return undefined. */
3469
+ function decodeCursor(cursor, filters) {
3470
+ try {
3471
+ const parsed = cursorSchema.parse(JSON.parse(Buffer.from(cursor, "base64url").toString("utf8")));
3472
+ if (parsed.conversationId !== filters.conversationId || parsed.query !== filters.query) return;
3473
+ return {
3474
+ id: parsed.id,
3475
+ updatedAt: new Date(parsed.updatedAtMs)
3476
+ };
3477
+ } catch {
3478
+ return;
3479
+ }
3480
+ }
3481
+ const ERROR_STATUS = {
3482
+ conflict: 409,
3483
+ forbidden: 403,
3484
+ invalid: 400,
3485
+ not_found: 404
3486
+ };
3487
+ /** Build the API payload of one Review item for its viewer. */
3488
+ function reviewItemPayload(item, viewer) {
3489
+ return {
3490
+ addedByConversationId: item.addedByConversationId,
3491
+ assignedToEveryone: item.assignedToEveryone,
3492
+ assignees: item.assignees,
3493
+ body: item.body,
3494
+ canAct: canActOnReviewItem(item, viewer.id),
3495
+ canTake: canActOnReviewItem(item, viewer.id) && !isOnlyAssignee(item, viewer.id),
3496
+ conversationIds: item.conversationIds,
3497
+ createdAt: item.createdAt.toISOString(),
3498
+ id: item.id,
3499
+ kind: item.kind,
3500
+ status: item.status,
3501
+ title: item.title,
3502
+ updatedAt: item.updatedAt.toISOString(),
3503
+ visibility: item.visibility,
3504
+ ...item.answer ? { answer: item.answer } : void 0,
3505
+ ...item.automationId ? { automationId: item.automationId } : void 0,
3506
+ ...item.closeReason ? { closeReason: item.closeReason } : void 0,
3507
+ ...item.closedAt ? { closedAt: item.closedAt.toISOString() } : void 0,
3508
+ ...item.closedBy ? { closedBy: item.closedBy } : void 0,
3509
+ ...item.request ? { request: item.request } : void 0,
3510
+ ...item.subject ? { subject: item.subject } : void 0
3511
+ };
3512
+ }
3513
+ function actionErrorResponse(error) {
3514
+ if (error instanceof ReviewItemActionError) return jsonResponse(apiErrorSchema, { error: error.message }, { status: ERROR_STATUS[error.code] });
3515
+ throw error;
3516
+ }
3517
+ /** Create the authenticated review desk routes. */
3518
+ function createReviewItemRoutes(services) {
3519
+ const app = new Hono();
3520
+ app.get("/", requireViewer, validateRequest("query", reviewItemListQuerySchema, "Invalid review item query."), async (context) => {
3521
+ const viewer = context.get("viewer");
3522
+ const query = context.req.valid("query");
3523
+ const filters = {
3524
+ ...query.conversationId ? { conversationId: query.conversationId } : void 0,
3525
+ ...query.q ? { query: query.q } : void 0
3526
+ };
3527
+ const after = query.cursor ? decodeCursor(query.cursor, filters) : void 0;
3528
+ if (query.cursor && !after) return jsonResponse(apiErrorSchema, { error: "Invalid review item cursor." }, { status: 400 });
3529
+ const db = getDb();
3530
+ const reader = reviewItemReaderForUser(viewer);
3531
+ const open = await searchReviewItems(db, reader, {
3532
+ ...filters,
3533
+ limit: query.limit + 1,
3534
+ statuses: ["open"],
3535
+ ...after ? { after } : void 0
3536
+ });
3537
+ const page = open.slice(0, query.limit);
3538
+ const last = page.at(-1);
3539
+ const archived = filters.query && !after ? await searchReviewItems(db, reader, {
3540
+ ...filters,
3541
+ limit: 51,
3542
+ statuses: ["done", "dismissed"]
3543
+ }) : [];
3544
+ return jsonResponse(reviewItemListSchema, {
3545
+ items: [...page, ...archived.slice(0, ARCHIVED_LIMIT)].map((item) => reviewItemPayload(item, viewer)),
3546
+ ...archived.length > ARCHIVED_LIMIT ? { moreArchived: true } : void 0,
3547
+ ...open.length > query.limit && last ? { nextCursor: encodeCursor(last, filters) } : void 0
3548
+ });
3549
+ });
3550
+ app.get("/count", requireViewer, async (context) => {
3551
+ const viewer = context.get("viewer");
3552
+ return jsonResponse(reviewItemCountSchema, { needsViewer: await countReviewItemsNeedingUser(getDb(), viewer.id) });
3553
+ });
3554
+ app.get("/waiting-conversations", requireViewer, async (context) => {
3555
+ const viewer = context.get("viewer");
3556
+ return jsonResponse(reviewItemWaitingConversationsSchema, { conversationIds: await listWaitingConversationIds(getDb(), viewer.id) });
3557
+ });
3558
+ app.get("/:id", requireViewer, validateRequest("param", reviewItemParamsSchema, "Invalid review item."), async (context) => {
3559
+ const viewer = context.get("viewer");
3560
+ try {
3561
+ const item = await readReviewItemForUser(viewer, context.req.valid("param").id);
3562
+ return jsonResponse(reviewItemSchema, reviewItemPayload(item, viewer));
3563
+ } catch (error) {
3564
+ return actionErrorResponse(error);
3565
+ }
3566
+ });
3567
+ app.post("/:id/actions", requireViewer, validateRequest("param", reviewItemParamsSchema, "Invalid review item."), validateRequest("json", reviewItemActionSchema, "Invalid action."), async (context) => {
3568
+ const viewer = context.get("viewer");
3569
+ const body = context.req.valid("json");
3570
+ const { id } = context.req.valid("param");
3571
+ try {
3572
+ const item = await actOnReviewItem({
3573
+ action: body.action,
3574
+ delivery: services.delivery,
3575
+ id,
3576
+ user: viewer,
3577
+ ...body.action === "submit" ? { answer: {
3578
+ ...body.answer,
3579
+ requestId: id
3580
+ } } : void 0
3581
+ });
3582
+ return jsonResponse(reviewItemSchema, reviewItemPayload(item, viewer));
3583
+ } catch (error) {
3584
+ return actionErrorResponse(error);
3585
+ }
3586
+ });
3587
+ return app;
3588
+ }
3614
3589
  // src/api/workspaces/routes.ts
3615
3590
  function snapshotView(workspace) {
3616
3591
  const recorded = workspace.snapshot;
@@ -3735,7 +3710,7 @@ function readDescriptionText(home) {
3735
3710
  }
3736
3711
  /** Read discovered skill names for authenticated runtime diagnostics. */
3737
3712
  async function readSkillReports() {
3738
- const { discoverSkills } = await import("./skills-CQHrwfOa.js").then((n) => n.o);
3713
+ const { discoverSkills } = await import("./skills-DmJJIuLF.js").then((n) => n.o);
3739
3714
  const skills = await discoverSkills();
3740
3715
  return skillReportsSchema.parse(skills.map((skill) => ({
3741
3716
  name: skill.name,
@@ -3744,7 +3719,7 @@ async function readSkillReports() {
3744
3719
  }
3745
3720
  /** Read safe configured plugin metadata for authenticated runtime diagnostics. */
3746
3721
  async function readPlugins() {
3747
- const { pluginCatalogRuntime } = await import("./catalog-runtime-cMlAI5LY.js").then((n) => n.t);
3722
+ const { pluginCatalogRuntime } = await import("./catalog-runtime-BsoSmTM0.js").then((n) => n.t);
3748
3723
  return pluginsSchema.parse(pluginCatalogRuntime.getProviders().map((plugin) => ({
3749
3724
  configKeys: plugin.manifest.configKeys ?? [],
3750
3725
  description: plugin.manifest.description,
@@ -3756,7 +3731,7 @@ async function readPlugins() {
3756
3731
  async function readRuntimeInfoReport() {
3757
3732
  const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
3758
3733
  import("./package-discovery-DJBompdd.js").then((n) => n.r),
3759
- import("./catalog-runtime-cMlAI5LY.js").then((n) => n.t),
3734
+ import("./catalog-runtime-BsoSmTM0.js").then((n) => n.t),
3760
3735
  readPlugins(),
3761
3736
  readSkillReports()
3762
3737
  ]);
@@ -3773,7 +3748,7 @@ async function readRuntimeInfoReport() {
3773
3748
  /** Read sanitized operational summaries contributed by plugins. */
3774
3749
  async function readPluginOperationalReportFeed() {
3775
3750
  const nowMs = Date.now();
3776
- const { getPluginOperationalReports } = await import("./credentialed-CIGwoLU2.js").then((n) => n.a);
3751
+ const { getPluginOperationalReports } = await import("./credentialed-BU-OW7HP.js").then((n) => n.a);
3777
3752
  return pluginOperationalReportFeedSchema.parse({
3778
3753
  source: "plugins",
3779
3754
  generatedAt: new Date(nowMs).toISOString(),
@@ -3790,10 +3765,15 @@ function createJuniorApi(options = {}) {
3790
3765
  app.get("/api/skills", async () => jsonResponse(skillReportsSchema, await readSkillReports()));
3791
3766
  app.get("/api/plugin-reports", async () => jsonResponse(pluginOperationalReportFeedSchema, await readPluginOperationalReportFeed()));
3792
3767
  app.get("/api/stats", async () => jsonResponse(statsReportSchema, await readStatsReport()));
3768
+ const queue = options.conversationWorkQueue ?? getVercelConversationWorkQueue();
3793
3769
  app.route("/api/conversations", createConversationRoutes({
3794
3770
  attachmentStorage: getAttachmentStorage(),
3795
- queue: options.conversationWorkQueue ?? getVercelConversationWorkQueue()
3771
+ queue
3796
3772
  }));
3773
+ app.route("/api/review-items", createReviewItemRoutes({ delivery: {
3774
+ queue,
3775
+ show: createSlackReviewItemShow(getProductionSlackAdapter)
3776
+ } }));
3797
3777
  app.route("/api/code", createCodeRoutes());
3798
3778
  app.route("/api/connections", createConnectionRoutes());
3799
3779
  app.route("/api/personal-tokens", createPersonalTokenRoutes());
@@ -3801,6 +3781,7 @@ function createJuniorApi(options = {}) {
3801
3781
  app.route("/api/people", createPeopleRoutes());
3802
3782
  app.route("/api/locations", createLocationRoutes());
3803
3783
  app.route("/api/user-pages", createUserPageRoutes());
3784
+ app.route("/api/user-customization", createUserCustomizationRoutes());
3804
3785
  app.route("/api/automations", createAutomationRoutes());
3805
3786
  app.route("/api/workspaces", createWorkspaceRoutes());
3806
3787
  app.notFound(() => jsonResponse(apiErrorSchema, { error: "Resource not found." }, { status: 404 }));
@@ -3814,4 +3795,4 @@ function createJuniorApi(options = {}) {
3814
3795
  });
3815
3796
  return app;
3816
3797
  }
3817
- export { authenticatePersonalToken, createJuniorApi, isAllowedSignInEmail, jsonResponse, resolveViewerUser, updateViewerDisplayName };
3798
+ export { authenticatePersonalToken, createJuniorApi, isAllowedSignInEmail, jsonResponse, readViewerAvatarUrl, resolveViewerUser, updateViewerDisplayName };