@sentry/junior 0.233.0 → 0.234.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 (53) hide show
  1. package/dist/{agent-hooks-DATy_Hnt.js → agent-hooks-BcH6E48y.js} +6 -6
  2. package/dist/{agent-runner-BKOtZjez.js → agent-runner-DUkGlK89.js} +221 -766
  3. package/dist/api/schema.d.ts +463 -2
  4. package/dist/api/schema.js +3 -3
  5. package/dist/api.js +229 -18
  6. package/dist/app.js +30 -20
  7. package/dist/{briefs-ClOTHmQ-.js → briefs-lyAQbDxJ.js} +2 -2
  8. package/dist/{catalog-runtime-xFtmw3oA.js → catalog-runtime-BSgsPVnr.js} +1 -1
  9. package/dist/{checkpoint-zkEB448J.js → checkpoint-BNfXlq_1.js} +6 -6
  10. package/dist/cli/chat.js +13 -13
  11. package/dist/cli/check.js +3 -3
  12. package/dist/cli/main.js +1 -1
  13. package/dist/cli/plugins.js +3 -3
  14. package/dist/cli/snapshot-create.js +3 -3
  15. package/dist/cli/upgrade.js +3 -3
  16. package/dist/{client-CJUZHY9Y.js → client-BX5lJRqW.js} +2 -2
  17. package/dist/{config-XtycpE-i.js → config-DuCzUoCo.js} +2 -2
  18. package/dist/{conversation-privacy-B30pEcsR.js → conversation-privacy-CSxvdSoV.js} +1 -1
  19. package/dist/{credential-sync-vufd6gwK.js → credential-sync-BO4DfH9a.js} +13 -13
  20. package/dist/{executor-BGDb_cM-.js → executor--jWf-Nnm.js} +1 -1
  21. package/dist/{images-zuEwjVKU.js → images-BaL19wFC.js} +2 -2
  22. package/dist/instrumentation.js +2 -2
  23. package/dist/{job-queue-C5JaRRcE.js → job-queue-cwHVOwVZ.js} +1 -1
  24. package/dist/{logging-BS563NYn.js → logging-Cox1Mgcv.js} +1 -1
  25. package/dist/nitro.js +3 -3
  26. package/dist/{oauth-authorization-DF2dSmNh.js → oauth-authorization-CC8a1JKP.js} +1 -1
  27. package/dist/{oauth-callback-server-CW9COQ9L.js → oauth-callback-server-Z7QSt416.js} +2 -2
  28. package/dist/{pending-auth-8Kmti8S3.js → pending-auth-DQhC3eSR.js} +1 -1
  29. package/dist/{profile-C4_njQYA.js → profile-BdApelHS.js} +4 -4
  30. package/dist/{registry-BhiLWAY6.js → registry-DiY6B8CN.js} +1 -1
  31. package/dist/{resolve-ZDwJ6a3N.js → resolve-VpJoiDpc.js} +2 -2
  32. package/dist/{runner-D1xeORYM.js → runner-BIMegnPE.js} +8 -8
  33. package/dist/{sandbox-egress-signals-Dx1PzQpy.js → sandbox-egress-signals-Cbtxe492.js} +1 -1
  34. package/dist/{schema-DuGfOm4u.js → schema-CxwnlTDN.js} +3 -116
  35. package/dist/{skills-CN-ye6on.js → skills-WttpPJUy.js} +2 -2
  36. package/dist/{spawn-B8KYOBcU.js → spawn-DhfMKt4y.js} +2 -2
  37. package/dist/{task-queue-DPaZtxld.js → task-queue-CZqUNJD0.js} +3 -3
  38. package/dist/{task-runner-D23tSETM.js → task-runner-BZaqoUCT.js} +15 -12
  39. package/dist/{thread-state-BbxSiDa9.js → thread-state-8tXZhu0y.js} +5 -5
  40. package/dist/{turn-failure-response-c8irQDMB.js → turn-failure-response-DFJ9L9NQ.js} +7 -7
  41. package/dist/{turn-lifecycle-DSVG3u_p.js → turn-lifecycle-WbpTUQ_r.js} +1 -1
  42. package/dist/{turn-session-routing-B2hNxu_N.js → turn-session-routing--EhI76rH.js} +1 -1
  43. package/dist/types-Du-HbEun.js +621 -0
  44. package/dist/{validation-BrLB5qbC.js → validation-0F9IgG3b.js} +1 -1
  45. package/dist/{version-B2rspCmP.js → version-A7-RRBOE.js} +1 -1
  46. package/dist/version.js +1 -1
  47. package/dist/{web-authorization-CVSTvY_D.js → web-authorization-BJggXofy.js} +6 -6
  48. package/dist/{web-input-zUQoZMZw.js → web-input-B-siN5Dr.js} +210 -162
  49. package/dist/web-message-id-CVVCTWUb.js +464 -0
  50. package/dist/{work-BXbJVOZI.js → work-CNc0ejGG.js} +7 -7
  51. package/dist/{worker-ClkQ9S9C.js → worker-BHbqpUAu.js} +5 -5
  52. package/package.json +4 -4
  53. package/dist/web-message-id-xPI_EFSC.js +0 -239
@@ -1,26 +1,27 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
2
- import { b as getGatewayApiKey, c as hasCompactedConversationContext, d as unwrapCurrentInstruction, f as escapeXml, g as getProviderErrorAttributes, h as findProviderError, i as completeText, l as isCompactionSummaryText, m as createProviderError, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as ProviderError, r as completeObject, s as COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as renderCurrentInstruction, v as isProviderRetryError, x as resolveGatewayCredential, y as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-CJUZHY9Y.js";
3
- import { C as withLogContext, F as normalizeIdentityEmail, I as isRecord$3, L as toOptionalNumber, R as toOptionalString, a as extractGenAiUsageSummary, b as setTags, c as getLogContextAttributesForSpan, d as logException, f as logInfo, g as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as normalizeGenAiFinishReason, p as logWarn, s as getLogContextAttributes, u as logError, v as setSpanAttributes, w as withSpan, x as summarizeMessageText, y as setSpanStatus } from "./logging-BS563NYn.js";
2
+ import { b as getGatewayApiKey, c as hasCompactedConversationContext, d as unwrapCurrentInstruction, f as escapeXml, g as getProviderErrorAttributes, h as findProviderError, i as completeText, l as isCompactionSummaryText, m as createProviderError, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as ProviderError, r as completeObject, s as COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as renderCurrentInstruction, v as isProviderRetryError, x as resolveGatewayCredential, y as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-BX5lJRqW.js";
3
+ import { C as withLogContext, F as normalizeIdentityEmail, I as isRecord$3, L as toOptionalNumber, R as toOptionalString, a as extractGenAiUsageSummary, b as setTags, c as getLogContextAttributesForSpan, d as logException, f as logInfo, g as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as normalizeGenAiFinishReason, p as logWarn, s as getLogContextAttributes, u as logError, v as setSpanAttributes, w as withSpan, x as summarizeMessageText, y as setSpanStatus } from "./logging-Cox1Mgcv.js";
4
4
  import { m as startInactiveSpan, n as captureMessage, v as withActiveSpan } from "./sentry-CgWZM_kV.js";
5
- import { a as toCanonicalInputMessage, c as toGenAiPayloadMetadata, i as runWithConversationPrivacy, l as toGenAiPayloadTraceAttributes, o as toCanonicalOutputMessage, r as resolveConversationPrivacy, s as toGenAiMessagesTraceAttributes, t as canExposeConversationPayload } from "./conversation-privacy-B30pEcsR.js";
6
- import { a as getChatConfig, h as normalizeSlackEmojiName, n as botConfig } from "./config-XtycpE-i.js";
5
+ import { a as toCanonicalInputMessage, c as toGenAiPayloadMetadata, i as runWithConversationPrivacy, l as toGenAiPayloadTraceAttributes, o as toCanonicalOutputMessage, r as resolveConversationPrivacy, s as toGenAiMessagesTraceAttributes, t as canExposeConversationPayload } from "./conversation-privacy-CSxvdSoV.js";
6
+ import { a as getChatConfig, h as normalizeSlackEmojiName, n as botConfig } from "./config-DuCzUoCo.js";
7
7
  import { a as formatModelProfiles, c as profileConfig, i as formatModelProfile, l as TURN_REASONING_LEVELS, n as ModelProfileNotConfiguredError, o as modelIdForProfile, s as modelProfileSchema } from "./model-profile-BwU8mqwD.js";
8
8
  import { b as parseSlackMessageTs, d as parseStoredSlackActor, g as parseSlackUserId, h as parseSlackTeamId, i as credentialUserSubjectId, l as isUserActor, m as parseSlackChannelReferenceId, n as credentialContextSchema, p as parseSlackChannelId, t as credentialContextForActor } from "./context-0Et9iVSB.js";
9
- import { $t as getConversationStore, A as tryWorkspaceRepoCheckoutPath, B as downloadPrivateSlackFile, C as invalidateReadySnapshot, Ct as createPluginLogger, D as SANDBOX_RUNTIME, E as setWorkspaceSnapshotBuild, G as isDmChannel$1, Ht as saveObjectAnnotations, J as withSlackRetries, K as normalizeSlackConversationId, M as resolveChannelCapabilities, O as deleteWorkspaceSnapshotBuilders, Q as readActorIdentity, Qt as getConversationMessageSearchStore, Rt as matchSlackAttachments, S as WorkspaceValidationError, T as setWorkspaceSnapshot, U as getSlackClient, Ut as createPluginAnnotations, V as getFilePermalink, W as isConversationScopedChannel, Zt as getConversationEventStore, _ as deleteWorkspace, at as STOP_WATCHING_TOOL_NAME, b as listWorkspaces, bn as sameDestination$1, c as getPluginTools, cn as addAgentTurnUsage, dt as deliverWatch, en as getDb, fn as hasAgentTurnUsage, ft as findMatchingWatches, g as createWorkspace, gt as getDashboardConversationLink, ht as JUNIOR_THREAD_STATE_TTL_MS, it as RESOURCE_WATCH_TOOL_SOURCE, j as workspaceRepoCheckoutPath, k as getWorkspaceSnapshotBuilder, l as getPluginUserPromptContributions, lt as createTimerWatch, n as applyPluginFormatMarkdown, nt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, ot as cancelSubscriptions, pt as listWatches, r as createPluginHookRunner, rt as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, s as getPluginSystemPromptContributions, st as cancelWatch, tn as getSqlExecutor, tt as getSlackToolContext, u as getPlugins, ut as createWatch, v as getWorkspace, vn as parseDestination, vt as getDashboardTaskLink, w as loadSnapshotsForProfile, x as updateWorkspace, y as getWorkspaceByName, z as SlackActionError } from "./agent-hooks-DATy_Hnt.js";
9
+ import { $t as getConversationStore, A as tryWorkspaceRepoCheckoutPath, B as downloadPrivateSlackFile, C as invalidateReadySnapshot, Ct as createPluginLogger, D as SANDBOX_RUNTIME, E as setWorkspaceSnapshotBuild, G as isDmChannel$1, Ht as saveObjectAnnotations, J as withSlackRetries, K as normalizeSlackConversationId, M as resolveChannelCapabilities, O as deleteWorkspaceSnapshotBuilders, Q as readActorIdentity, Qt as getConversationMessageSearchStore, Rt as matchSlackAttachments, S as WorkspaceValidationError, T as setWorkspaceSnapshot, U as getSlackClient, Ut as createPluginAnnotations, V as getFilePermalink, W as isConversationScopedChannel, Zt as getConversationEventStore, _ as deleteWorkspace, at as STOP_WATCHING_TOOL_NAME, b as listWorkspaces, bn as sameDestination$1, c as getPluginTools, cn as addAgentTurnUsage, dt as deliverWatch, en as getDb, fn as hasAgentTurnUsage, ft as findMatchingWatches, g as createWorkspace, gt as getDashboardConversationLink, ht as JUNIOR_THREAD_STATE_TTL_MS, it as RESOURCE_WATCH_TOOL_SOURCE, j as workspaceRepoCheckoutPath, k as getWorkspaceSnapshotBuilder, l as getPluginUserPromptContributions, lt as createTimerWatch, n as applyPluginFormatMarkdown, nt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, ot as cancelSubscriptions, pt as listWatches, r as createPluginHookRunner, rt as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, s as getPluginSystemPromptContributions, st as cancelWatch, tn as getSqlExecutor, tt as getSlackToolContext, u as getPlugins, ut as createWatch, v as getWorkspace, vn as parseDestination, vt as getDashboardTaskLink, w as loadSnapshotsForProfile, x as updateWorkspace, y as getWorkspaceByName, z as SlackActionError } from "./agent-hooks-BcH6E48y.js";
10
10
  import { n as juniorDestinations } from "./destinations-BeBiJeEM.js";
11
- import { D as juniorIdentities, E as juniorConversations, a as juniorSchedulerRuns, c as juniorStats, d as AGENT_INVOCATION_MAILBOX_STATUSES, g as juniorConversationBriefs, k as juniorArtifacts, l as juniorEventAutomations, o as juniorSchedulerTasks, w as juniorAttachments, x as juniorConversationAnnotations } from "./executor-BGDb_cM-.js";
11
+ import { D as juniorIdentities, E as juniorConversations, a as juniorSchedulerRuns, c as juniorStats, d as AGENT_INVOCATION_MAILBOX_STATUSES, g as juniorConversationBriefs, k as juniorArtifacts, l as juniorEventAutomations, o as juniorSchedulerTasks, w as juniorAttachments, x as juniorConversationAnnotations } from "./executor--jWf-Nnm.js";
12
12
  import { F as briefLinkSchema, G as KNOWN_CONVERSATION_EVENT_TYPES, I as briefOutcomeStatusSchema, L as conversationBriefSchema, N as isVisionImageMediaType, U as removedCardSchema, et as contextProvenance, nt as instructionProvenanceFor, rt as sameActorIdentity, tt as instructionActors } from "./conversation-CPjHYOV5.js";
13
13
  import { a as listReferenceFiles, c as soulPathCandidates, l as worldPathCandidates } from "./package-discovery-7a9YqLhE.js";
14
- import { a as resolveAuthTokenPlaceholder, c as fetchWithBoundedOAuthErrorBodies, d as CredentialUnavailableError, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, o as resolvePluginCommandEnv, s as OAuthProviderError } from "./registry-BhiLWAY6.js";
15
- import { n as pluginCatalogRuntime } from "./catalog-runtime-xFtmw3oA.js";
16
- import { a as parseSkillInvocation, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-CN-ye6on.js";
17
- import { $ as fallbackShortTitle, C as isToolResultError, D as stripRuntimeTurnContext, E as retainRuntimeTurnContext, F as loadTurnRoute, G as recordToolExecutionStarted, H as recordGuardianActionReviewed, I as openConversationProjection, K as recordTurnRoute, L as recordAgentsInstructionsUpdated, M as loadConnectedMcpProviders, N as loadConversationProjection, O as trimTrailingAssistantMessages, R as recordAttachmentsDelivered, S as isContinuablePiBoundary, T as normalizeToolNameFromResult, U as recordMcpProviderConnected, V as recordAuthorizationRequested, _ as getTerminalAssistantMessages, _t as piMessageFromHistoryItem, d as TurnSliceLimitExceededError, et as generateShortTitle, f as assertTurnToolCallLimit, g as getPiMessageRole, gt as historyItemFromPiMessage, h as extractAssistantText, ht as getAgentContextInputLimitTokens, k as TURN_CONTEXT_TAG, m as isTurnExecutionLimitExceededError, mt as getAgentContextCompactionTriggerTokens, n as loadTurnCheckpoint, pt as estimateTextTokens, r as saveTurnCheckpoint, t as continuableMessages, tt as resolveTaskTitle, v as getUserMessageInstructionText, w as isToolResultMessage, x as isAssistantMessage, y as hasRuntimeTurnContext } from "./checkpoint-zkEB448J.js";
18
- import { A as SANDBOX_DATA_ROOT, C as getDefaultRedisStateAdapterFor, D as fenceLock, E as acquireActiveLock, F as sandboxSkillFile, I as sandboxSkillPathResolution, M as SANDBOX_SKILLS_ROOT, N as SANDBOX_WORKSPACE_ROOT, O as withLock, P as sandboxSkillDir, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildNonInteractiveShellScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, j as SANDBOX_REPOS_ROOT, k as sleep$2, l as isSandboxMissingError, m as WorkspaceSnapshotNotReadyError, n as hash, o as isAlreadyExistsError, p as wrapSandboxSetupError, r as isStale, s as isSandboxApiTransientError, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand, y as buildCommandScript } from "./profile-C4_njQYA.js";
19
- import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-8Kmti8S3.js";
20
- import { a as NO_REPLY_MARKER, c as CooperativeTurnYieldError, i as sanitizeAssistantText, l as TurnInputCommitLostError, n as decideReply, o as isNoReplyMarker, p as isTurnInputCommitLostError, r as getAssistantReplyText, t as authorizationId } from "./oauth-authorization-DF2dSmNh.js";
14
+ import { a as resolveAuthTokenPlaceholder, c as fetchWithBoundedOAuthErrorBodies, d as CredentialUnavailableError, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, o as resolvePluginCommandEnv, s as OAuthProviderError } from "./registry-DiY6B8CN.js";
15
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-BSgsPVnr.js";
16
+ import { a as parseSkillInvocation, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-WttpPJUy.js";
17
+ import { $ as fallbackShortTitle, C as isToolResultError, D as stripRuntimeTurnContext, E as retainRuntimeTurnContext, F as loadTurnRoute, G as recordToolExecutionStarted, H as recordGuardianActionReviewed, I as openConversationProjection, K as recordTurnRoute, L as recordAgentsInstructionsUpdated, M as loadConnectedMcpProviders, N as loadConversationProjection, O as trimTrailingAssistantMessages, R as recordAttachmentsDelivered, S as isContinuablePiBoundary, T as normalizeToolNameFromResult, U as recordMcpProviderConnected, V as recordAuthorizationRequested, _ as getTerminalAssistantMessages, d as TurnSliceLimitExceededError, et as resolveTaskTitle, f as assertTurnToolCallLimit, ft as estimateTextTokens, g as getPiMessageRole, gt as piMessageFromHistoryItem, h as extractAssistantText, ht as historyItemFromPiMessage, k as TURN_CONTEXT_TAG, m as isTurnExecutionLimitExceededError, mt as getAgentContextInputLimitTokens, n as loadTurnCheckpoint, pt as getAgentContextCompactionTriggerTokens, r as saveTurnCheckpoint, t as continuableMessages, v as getUserMessageInstructionText, w as isToolResultMessage, x as isAssistantMessage, y as hasRuntimeTurnContext } from "./checkpoint-BNfXlq_1.js";
18
+ import { A as SANDBOX_DATA_ROOT, C as getDefaultRedisStateAdapterFor, D as fenceLock, E as acquireActiveLock, F as sandboxSkillFile, I as sandboxSkillPathResolution, M as SANDBOX_SKILLS_ROOT, N as SANDBOX_WORKSPACE_ROOT, O as withLock, P as sandboxSkillDir, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildNonInteractiveShellScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, j as SANDBOX_REPOS_ROOT, k as sleep$2, l as isSandboxMissingError, m as WorkspaceSnapshotNotReadyError, n as hash, o as isAlreadyExistsError, p as wrapSandboxSetupError, r as isStale, s as isSandboxApiTransientError, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand, y as buildCommandScript } from "./profile-BdApelHS.js";
19
+ import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-DQhC3eSR.js";
20
+ import { a as NO_REPLY_MARKER, c as CooperativeTurnYieldError, i as sanitizeAssistantText, l as TurnInputCommitLostError, n as decideReply, o as isNoReplyMarker, p as isTurnInputCommitLostError, r as getAssistantReplyText, t as authorizationId } from "./oauth-authorization-CC8a1JKP.js";
21
21
  import { r as EVENT_AUTHOR_ID } from "./prompt-3D0sSbTC.js";
22
- import { a as createSandboxSession, c as postinstall, d as getSandboxResources, i as bindSandboxFileSystem, l as setSnapshotSpanAttributes, n as isMissingError, o as stopSession, r as resolve$1, s as dependencies } from "./resolve-ZDwJ6a3N.js";
23
- import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-C5JaRRcE.js";
22
+ import { a as createSandboxSession, c as postinstall, d as getSandboxResources, i as bindSandboxFileSystem, l as setSnapshotSpanAttributes, n as isMissingError, o as stopSession, r as resolve$1, s as dependencies } from "./resolve-VpJoiDpc.js";
23
+ import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-cwHVOwVZ.js";
24
+ import { a as automationTitleSchema, c as ScheduleIntentError, g as taskOutcomeInputSchema, i as automationInstructionSchema, l as compileScheduleIntent, m as eventAutomationSchema, n as scheduledAutomationSchema, p as getZonedDateTimeParts, r as scheduledRunSchema, t as SCHEDULED_AUTOMATION_SYSTEM_ACTOR, u as scheduleIntentSchema } from "./types-Du-HbEun.js";
24
25
  import { n as privateTraceResultAttributes } from "./private-trace-result-BLvBjy_e.js";
25
26
  import { streamSimple } from "@earendil-works/pi-ai/compat";
26
27
  import { createGatewayProvider } from "@ai-sdk/gateway";
@@ -31,7 +32,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
31
32
  import { z } from "zod";
32
33
  import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
33
34
  import { and, asc, desc, eq, gt, gte, inArray, isNotNull, isNull, lt, lte, ne, notExists, notInArray, or, sql } from "drizzle-orm";
34
- import { EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, actorSchema, actorUserIdSchema, destinationSchema, destinationVisibilitySchema, eventMatchSchema, eventMatches, eventSchema, eventTypeSchema, missingToolAnnotationKeys, normalizeEventIdentifier, objectTypeSchema, ownedObjectAnnotationSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialResultSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginStoredTokensSchema, slackDestinationSchema, sourceSchema, stableEventMatchKey, taskOutcomeSchema, watchResultSchema } from "@sentry/junior-plugin-api";
35
+ import { EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, actorSchema, destinationSchema, eventMatchSchema, eventMatches, eventSchema, missingToolAnnotationKeys, normalizeEventIdentifier, objectTypeSchema, ownedObjectAnnotationSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialResultSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginStoredTokensSchema, slackDestinationSchema, sourceSchema, stableEventMatchKey, taskOutcomeSchema, watchResultSchema } from "@sentry/junior-plugin-api";
35
36
  import { alias } from "drizzle-orm/pg-core";
36
37
  import { Agent, estimateContextTokens } from "@earendil-works/pi-agent-core";
37
38
  import fs from "node:fs/promises";
@@ -10252,37 +10253,28 @@ function createEventTools(context, catalog) {
10252
10253
  stopWatchingResources: createStopWatchingResourcesTool(context)
10253
10254
  };
10254
10255
  }
10255
- /** Validate the persisted Slack creator identity for an event automation. */
10256
- const eventAutomationPrincipalSchema = z.object({
10257
- slackUserId: actorUserIdSchema,
10258
- fullName: z.string().optional(),
10259
- userName: z.string().optional()
10260
- }).strict();
10261
- /** Validate one persisted event-automation selector and its presentation metadata. */
10262
- const eventAutomationTriggerSchema = z.object({
10263
- events: z.array(eventTypeSchema).min(1),
10264
- label: z.string().min(1),
10265
- match: eventMatchSchema.optional(),
10266
- namespace: z.string().min(1),
10267
- identifier: z.string().min(1).max(300),
10268
- resourceType: z.string().min(1)
10269
- }).strict();
10270
- /** Event automations target a Slack channel or DM, never a message thread. */
10271
- const eventAutomationDestinationSchema = slackDestinationSchema.omit({ threadTs: true });
10272
- const eventAutomationOutcomeSchema = taskOutcomeSchema.extend({ destination: eventAutomationDestinationSchema });
10273
- /** Validate one persisted event automation. */
10274
- const eventAutomationSchema = z.object({
10275
- id: z.string().min(1),
10276
- createdAtMs: z.number().finite(),
10277
- createdBy: eventAutomationPrincipalSchema,
10278
- credentialMode: z.enum(["system", "creator"]),
10279
- destination: eventAutomationDestinationSchema,
10280
- destinationVisibility: destinationVisibilitySchema,
10281
- /** Explicit visible effects after successful work. An empty list is silent. */
10282
- outcomes: z.array(eventAutomationOutcomeSchema).max(5),
10283
- task: z.object({ text: z.string().min(1) }).strict(),
10284
- trigger: eventAutomationTriggerSchema
10285
- }).strict();
10256
+ //#endregion
10257
+ //#region src/chat/automations/revision.ts
10258
+ /** Storage revisions prevent stale edits from replacing newer values. */
10259
+ var AutomationConflictError = class extends ToolInputError {
10260
+ constructor() {
10261
+ super("This Automation changed after it was loaded. Reload it before saving.");
10262
+ this.name = "AutomationConflictError";
10263
+ }
10264
+ };
10265
+ function canonicalJson$1(value) {
10266
+ if (Array.isArray(value)) return value.map(canonicalJson$1);
10267
+ if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => [key, canonicalJson$1(child)]));
10268
+ return value;
10269
+ }
10270
+ /** Identify the stored values being edited, including lifecycle and creator authority. */
10271
+ function automationRevision(task) {
10272
+ return createHash("sha256").update(JSON.stringify(canonicalJson$1(task))).digest("hex");
10273
+ }
10274
+ /** Reject a stale edit while the storage owner holds the write lock. */
10275
+ function requireAutomationRevision(task, revision) {
10276
+ if (!task || automationRevision(task) !== revision) throw new AutomationConflictError();
10277
+ }
10286
10278
  //#endregion
10287
10279
  //#region src/chat/event-automations/store.ts
10288
10280
  const retainedEventAutomationSchema = eventAutomationSchema.extend({
@@ -10294,7 +10286,8 @@ function eventAutomationJsonPayload(task) {
10294
10286
  const { status: _status, title: _title, ...payload } = task;
10295
10287
  return payload;
10296
10288
  }
10297
- function parseTask(row) {
10289
+ /** Decode a retained event Automation with its SQL-backed fields. */
10290
+ function parseEventAutomationRow(row) {
10298
10291
  const raw = row.task && typeof row.task === "object" ? { ...row.task } : row.task;
10299
10292
  if (raw && typeof raw === "object" && "title" in raw) delete raw.title;
10300
10293
  if (raw && typeof raw === "object" && !("outcomes" in raw) && "destination" in raw) raw.outcomes = [{
@@ -10314,7 +10307,7 @@ function parseTask(row) {
10314
10307
  destination
10315
10308
  };
10316
10309
  }),
10317
- status: row.status === "deleted" ? "deleted" : "active",
10310
+ status: row.status ?? "active",
10318
10311
  ...title ? { title } : void 0
10319
10312
  };
10320
10313
  }
@@ -10328,7 +10321,7 @@ async function getEventAutomation(db, id) {
10328
10321
  task: juniorEventAutomations.task,
10329
10322
  title: juniorEventAutomations.title
10330
10323
  }).from(juniorEventAutomations).where(eq(juniorEventAutomations.id, id)).limit(1);
10331
- return rows[0] ? parseTask(rows[0]) : void 0;
10324
+ return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10332
10325
  }
10333
10326
  /** Create one retry-stable event automation, or revive a deleted row with the new payload. */
10334
10327
  async function createEventAutomation(db, task) {
@@ -10363,14 +10356,19 @@ async function createEventAutomation(db, task) {
10363
10356
  task: juniorEventAutomations.task,
10364
10357
  title: juniorEventAutomations.title
10365
10358
  });
10366
- return rows[0] ? parseTask(rows[0]) : await getEventAutomation(db, parsed.id) ?? {
10359
+ return rows[0] ? parseEventAutomationRow(rows[0]) : await getEventAutomation(db, parsed.id) ?? {
10367
10360
  ...parsed,
10368
10361
  status: "active",
10369
10362
  ...title ? { title } : void 0
10370
10363
  };
10371
10364
  }
10372
10365
  /** Replace an existing non-deleted event automation. */
10373
- async function saveEventAutomation(db, task) {
10366
+ async function saveEventAutomation(db, task, expectedRevision) {
10367
+ if (expectedRevision !== void 0) return db.transaction(async (tx) => {
10368
+ const rows = await tx.select().from(juniorEventAutomations).where(eq(juniorEventAutomations.id, task.id)).for("update");
10369
+ requireAutomationRevision(rows[0] ? parseEventAutomationRow(rows[0]) : void 0, expectedRevision);
10370
+ return saveEventAutomation(tx, task);
10371
+ });
10374
10372
  const parsed = eventAutomationSchema.parse(eventAutomationJsonPayload(task));
10375
10373
  const title = task.title?.trim() || null;
10376
10374
  const rows = await db.update(juniorEventAutomations).set({
@@ -10383,7 +10381,7 @@ async function saveEventAutomation(db, task) {
10383
10381
  task: juniorEventAutomations.task,
10384
10382
  title: juniorEventAutomations.title
10385
10383
  });
10386
- return rows[0] ? parseTask(rows[0]) : void 0;
10384
+ return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10387
10385
  }
10388
10386
  /** Mark one existing event automation deleted while retaining the row for history. */
10389
10387
  async function deleteEventAutomation(db, id) {
@@ -10392,7 +10390,7 @@ async function deleteEventAutomation(db, id) {
10392
10390
  task: juniorEventAutomations.task,
10393
10391
  title: juniorEventAutomations.title
10394
10392
  });
10395
- return rows[0] ? parseTask(rows[0]) : void 0;
10393
+ return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10396
10394
  }
10397
10395
  /** List live event automations in one Slack workspace. */
10398
10396
  async function listEventAutomationsForTeam(db, teamId) {
@@ -10400,7 +10398,7 @@ async function listEventAutomationsForTeam(db, teamId) {
10400
10398
  status: juniorEventAutomations.status,
10401
10399
  task: juniorEventAutomations.task,
10402
10400
  title: juniorEventAutomations.title
10403
- }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, teamId), activeEventAutomationWhere())).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id))).map(parseTask);
10401
+ }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, teamId), activeEventAutomationWhere())).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id))).map(parseEventAutomationRow);
10404
10402
  }
10405
10403
  function viewerSlackIdentities(user) {
10406
10404
  return user.identities.filter((identity) => identity.provider === "slack" && Boolean(identity.providerTenantId) && Boolean(identity.providerSubjectId));
@@ -10409,17 +10407,6 @@ function viewerSlackIdentities(user) {
10409
10407
  function eventAutomationBelongsToUser(task, user) {
10410
10408
  return viewerSlackIdentities(user).some((identity) => identity.providerTenantId === task.destination.teamId && identity.providerSubjectId === task.createdBy.slackUserId);
10411
10409
  }
10412
- /** List a bounded newest-first page of live event automations created by one user. */
10413
- async function listEventAutomationsCreatedBy(db, user, limit, query) {
10414
- const identities = viewerSlackIdentities(user);
10415
- const ownership = or(...identities.map((identity) => and(eq(juniorEventAutomations.teamId, identity.providerTenantId), sql`${juniorEventAutomations.task}->'createdBy'->>'slackUserId' = ${identity.providerSubjectId}`)));
10416
- if (!ownership) return [];
10417
- return (await db.select({
10418
- status: juniorEventAutomations.status,
10419
- task: juniorEventAutomations.task,
10420
- title: juniorEventAutomations.title
10421
- }).from(juniorEventAutomations).where(and(ownership, activeEventAutomationWhere(), query ? sql`strpos(lower(coalesce(${juniorEventAutomations.title}, ${juniorEventAutomations.task}->'task'->>'text')), ${query}) > 0` : void 0)).orderBy(desc(juniorEventAutomations.createdAtMs), desc(juniorEventAutomations.id)).limit(limit)).map(parseTask);
10422
- }
10423
10410
  /**
10424
10411
  * List deleted event automations created by one user, newest first.
10425
10412
  * Used only to keep historical runs after the live automation list drops the row.
@@ -10432,16 +10419,7 @@ async function listDeletedEventAutomationsCreatedBy(db, user, limit) {
10432
10419
  status: juniorEventAutomations.status,
10433
10420
  task: juniorEventAutomations.task,
10434
10421
  title: juniorEventAutomations.title
10435
- }).from(juniorEventAutomations).where(and(ownership, eq(juniorEventAutomations.status, "deleted"))).orderBy(desc(juniorEventAutomations.createdAtMs), desc(juniorEventAutomations.id)).limit(limit)).map(parseTask);
10436
- }
10437
- /** List live event automations whose current Slack destination is public. */
10438
- async function listPublicEventAutomationsForTeams(db, teamIds, limit, query) {
10439
- if (teamIds.length === 0) return [];
10440
- return (await db.select({
10441
- status: juniorEventAutomations.status,
10442
- task: juniorEventAutomations.task,
10443
- title: juniorEventAutomations.title
10444
- }).from(juniorEventAutomations).innerJoin(juniorDestinations, and(eq(juniorDestinations.provider, "slack"), eq(juniorDestinations.providerTenantId, juniorEventAutomations.teamId), sql`${juniorDestinations.providerDestinationId} = ${juniorEventAutomations.task}->'destination'->>'channelId'`)).where(and(inArray(juniorEventAutomations.teamId, teamIds), activeEventAutomationWhere(), query ? sql`strpos(lower(coalesce(${juniorEventAutomations.title}, ${juniorEventAutomations.task}->'task'->>'text')), ${query}) > 0` : void 0, eq(juniorDestinations.visibility, "public"))).orderBy(desc(juniorEventAutomations.createdAtMs), desc(juniorEventAutomations.id)).limit(limit)).map(parseTask);
10422
+ }).from(juniorEventAutomations).where(and(ownership, eq(juniorEventAutomations.status, "deleted"))).orderBy(desc(juniorEventAutomations.createdAtMs), desc(juniorEventAutomations.id)).limit(limit)).map(parseEventAutomationRow);
10445
10423
  }
10446
10424
  /**
10447
10425
  * Collect match keys from live event automations for these identifiers and event types.
@@ -10455,10 +10433,10 @@ async function collectEventAutomationMatchKeys(db, input) {
10455
10433
  status: juniorEventAutomations.status,
10456
10434
  task: juniorEventAutomations.task,
10457
10435
  title: juniorEventAutomations.title
10458
- }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, input.teamId), eq(juniorEventAutomations.namespace, input.namespace), inArray(juniorEventAutomations.identifier, identifiers), activeEventAutomationWhere())).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id));
10436
+ }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, input.teamId), eq(juniorEventAutomations.namespace, input.namespace), inArray(juniorEventAutomations.identifier, identifiers), eq(juniorEventAutomations.status, "active"))).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id));
10459
10437
  const keys = /* @__PURE__ */ new Set();
10460
10438
  for (const row of rows) {
10461
- const task = parseTask(row);
10439
+ const task = parseEventAutomationRow(row);
10462
10440
  if (!task.trigger.events.some((eventType) => eventTypes.has(eventType))) continue;
10463
10441
  for (const key of Object.keys(task.trigger.match ?? {})) keys.add(key);
10464
10442
  }
@@ -10470,16 +10448,24 @@ async function findMatchingEventAutomations(db, event, teamId) {
10470
10448
  status: juniorEventAutomations.status,
10471
10449
  task: juniorEventAutomations.task,
10472
10450
  title: juniorEventAutomations.title
10473
- }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, teamId), eq(juniorEventAutomations.namespace, event.namespace), eq(juniorEventAutomations.identifier, event.identifier), activeEventAutomationWhere())).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id))).map(parseTask).filter((task) => task.trigger.events.includes(event.eventType) && eventMatches(task.trigger.match, event.data));
10451
+ }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, teamId), eq(juniorEventAutomations.namespace, event.namespace), eq(juniorEventAutomations.identifier, event.identifier), eq(juniorEventAutomations.status, "active"))).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id))).map(parseEventAutomationRow).filter((task) => task.trigger.events.includes(event.eventType) && eventMatches(task.trigger.match, event.data));
10452
+ }
10453
+ /** Change lifecycle under the same row lock as edits, without changing credentials. */
10454
+ async function setEventAutomationStatus(db, id, status, revision) {
10455
+ return db.transaction(async (tx) => {
10456
+ const rows = await tx.select().from(juniorEventAutomations).where(eq(juniorEventAutomations.id, id)).for("update");
10457
+ const current = rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10458
+ requireAutomationRevision(current, revision);
10459
+ if (!current || current.status === "deleted") throw new Error("Automation no longer exists.");
10460
+ await tx.update(juniorEventAutomations).set({ status }).where(eq(juniorEventAutomations.id, id));
10461
+ return {
10462
+ ...current,
10463
+ status
10464
+ };
10465
+ });
10474
10466
  }
10475
10467
  //#endregion
10476
10468
  //#region src/chat/task-outcomes.ts
10477
- const taskMessageDestinationInputSchema = z.enum(["current_conversation", "task_creator"]).describe("Where to send the message. Use current_conversation for posts, digests, summaries, and channel reminders. Use task_creator only when the user asks for a direct reminder or notification.");
10478
- /** Input accepted by task authoring tools before a user becomes a DM Destination. */
10479
- const taskOutcomeInputSchema = z.object({
10480
- action: z.literal("send_message"),
10481
- destination: taskMessageDestinationInputSchema
10482
- }).strict();
10483
10469
  /** Resolve explicit message outcomes to the Slack Destinations stored on an Automation. */
10484
10470
  async function resolveTaskOutcomes(outcomes, currentDestination, creatorSlackUserId) {
10485
10471
  if (outcomes === void 0) return [];
@@ -10527,6 +10513,11 @@ function moveTaskOutcomes(outcomes, currentDestination, nextDestination) {
10527
10513
  //#region src/chat/event-automations/tool-support.ts
10528
10514
  const compactEventAutomationResultSchema = z.object({
10529
10515
  id: z.string().min(1),
10516
+ status: z.enum([
10517
+ "active",
10518
+ "paused",
10519
+ "deleted"
10520
+ ]),
10530
10521
  title: z.string().min(1).nullable(),
10531
10522
  dashboardUrl: z.string().url().nullable(),
10532
10523
  instruction: z.string().min(1),
@@ -10626,6 +10617,7 @@ function eventAutomationTriggerAvailable(task, catalog) {
10626
10617
  function compactEventAutomation(task, catalog, requesterSlackUserId) {
10627
10618
  return compactEventAutomationResultSchema.parse({
10628
10619
  id: task.id,
10620
+ status: task.status,
10629
10621
  title: task.title?.trim() || null,
10630
10622
  dashboardUrl: getDashboardTaskLink(task.id) ?? null,
10631
10623
  instruction: task.task.text,
@@ -10829,13 +10821,78 @@ function createListEventAutomationsTool(context, catalog) {
10829
10821
  });
10830
10822
  }
10831
10823
  //#endregion
10832
- //#region src/chat/tools/update-event-automation.ts
10833
- /** Return whether an edit changes the task's executable event source. */
10824
+ //#region src/chat/automations/edit-rules.ts
10825
+ /** Shared edit rules. Transport access checks run before these rules. */
10826
+ var AutomationEditError = class extends ToolInputError {
10827
+ field;
10828
+ constructor(message, field) {
10829
+ super(message);
10830
+ this.field = field;
10831
+ this.name = "AutomationEditError";
10832
+ }
10833
+ };
10834
+ /** Apply shared title, instruction, outcome, and creator credential rules. */
10835
+ async function editAutomationFields(current, input, isCreator, changesExecution) {
10836
+ const kind = "schedule" in current ? "scheduled" : "event";
10837
+ if (input.credentialMode === "creator" && !isCreator) throw new AutomationEditError(`Only the ${kind} automation creator can enable creator credential use.`, "credentialMode");
10838
+ if (input.outcomes !== void 0 && !isCreator) throw new AutomationEditError(`Only the ${kind} automation creator can change message destinations.`, "outcomes");
10839
+ let outcomes = current.outcomes;
10840
+ if (input.outcomes !== void 0) {
10841
+ for (const outcome of input.outcomes) if (typeof outcome.destination !== "string" && !current.outcomes.some((stored) => isDeepStrictEqual(stored, outcome))) throw new AutomationEditError("Use the current Destination or the creator for a new message outcome.", "outcomes");
10842
+ outcomes = [];
10843
+ for (const outcome of input.outcomes) if (typeof outcome.destination === "string") outcomes.push(...await resolveTaskOutcomes([{
10844
+ action: outcome.action,
10845
+ destination: outcome.destination
10846
+ }], current.destination, current.createdBy.slackUserId));
10847
+ else outcomes.push({
10848
+ action: outcome.action,
10849
+ destination: outcome.destination
10850
+ });
10851
+ }
10852
+ return {
10853
+ title: input.title ?? current.title,
10854
+ task: { text: input.instruction ?? current.task.text },
10855
+ credentialMode: changesExecution && !isCreator ? "system" : input.credentialMode ?? current.credentialMode,
10856
+ outcomes
10857
+ };
10858
+ }
10859
+ //#endregion
10860
+ //#region src/chat/event-automations/edit.ts
10834
10861
  function changesEventAutomationTrigger(current, next) {
10835
10862
  const currentEvents = [...current.events].sort();
10836
10863
  const nextEvents = [...next.events].sort();
10837
10864
  return current.namespace !== next.namespace || current.identifier !== next.identifier || currentEvents.length !== nextEvents.length || currentEvents.some((event, index) => event !== nextEvents[index]) || stableEventMatchKey(current.match) !== stableEventMatchKey(next.match);
10838
10865
  }
10866
+ /** Build a validated edit while retaining an unchanged, possibly unavailable trigger. */
10867
+ async function editEventAutomation(current, input, isCreator, catalog) {
10868
+ let trigger = current.trigger;
10869
+ if (input.trigger !== void 0) {
10870
+ if (changesEventAutomationTrigger(current.trigger, input.trigger) || current.trigger.resourceType !== input.trigger.resourceType) try {
10871
+ const match = requireSupportedEventAutomationTrigger(catalog, input.trigger);
10872
+ trigger = {
10873
+ ...input.trigger,
10874
+ identifier: normalizeCatalogEventIdentifier(catalog, input.trigger.namespace, input.trigger.identifier),
10875
+ events: [...new Set(input.trigger.events)],
10876
+ match
10877
+ };
10878
+ } catch (error) {
10879
+ if (error instanceof ToolInputError) throw new AutomationEditError(error.message, "trigger");
10880
+ throw error;
10881
+ }
10882
+ else trigger = {
10883
+ ...current.trigger,
10884
+ label: input.trigger.label
10885
+ };
10886
+ }
10887
+ const changesExecution = input.instruction !== void 0 && input.instruction !== current.task.text || changesEventAutomationTrigger(current.trigger, trigger);
10888
+ return {
10889
+ ...current,
10890
+ ...await editAutomationFields(current, input, isCreator, changesExecution),
10891
+ trigger
10892
+ };
10893
+ }
10894
+ //#endregion
10895
+ //#region src/chat/tools/update-event-automation.ts
10839
10896
  /** Create the core tool that updates an event automation. */
10840
10897
  function createUpdateEventAutomationTool(context, catalog) {
10841
10898
  return zodTool({
@@ -10850,7 +10907,8 @@ function createUpdateEventAutomationTool(context, catalog) {
10850
10907
  description: "Update the instruction, registered trigger, or credential use for an event automation.",
10851
10908
  inputSchema: z.object({
10852
10909
  automationId: z.string().min(1),
10853
- instruction: z.string().trim().min(1).max(4e3).nullable().optional(),
10910
+ title: automationTitleSchema.optional(),
10911
+ instruction: automationInstructionSchema.nullable().optional(),
10854
10912
  trigger: registeredEventAutomationTriggerSchema(catalog).nullable().optional(),
10855
10913
  outcomes: z.array(taskOutcomeInputSchema).max(5).nullable().describe("Replacement messages to send after successful work. Use an empty list to send nothing. Omit or use null to leave unchanged.").optional(),
10856
10914
  credentialMode: z.enum(["system", "creator"]).nullable().describe("Set creator to make the task's original creator credentials available, or system to disable them. Creator always means the task's createdBy actor, never the current requester. Only that original creator may enable creator mode. Omit or use null to leave unchanged.").optional()
@@ -10866,43 +10924,19 @@ function createUpdateEventAutomationTool(context, catalog) {
10866
10924
  };
10867
10925
  },
10868
10926
  outputSchema: eventAutomationToolResultSchema,
10869
- async execute(input, options) {
10927
+ async execute(input) {
10870
10928
  const current = await writableEventAutomation(context, input.automationId);
10871
- const match = input.trigger ? requireSupportedEventAutomationTrigger(catalog, input.trigger) : void 0;
10872
10929
  const { actor } = requireEventAutomationSlackContext(context);
10873
10930
  const isCreator = actor.userId === current.createdBy.slackUserId;
10874
- if (input.credentialMode === "creator" && !isCreator) throw new ToolInputError("Only the event automation creator can enable creator credential use.");
10875
- if (input.outcomes != null && !isCreator) throw new ToolInputError("Only the event automation creator can change message destinations.");
10876
- if (input.instruction === void 0 && input.trigger === void 0 && input.outcomes == null && input.credentialMode == null) throw new ToolInputError("Event automation update requires a change.");
10877
- const nextTrigger = input.trigger ? {
10878
- namespace: input.trigger.namespace,
10879
- identifier: normalizeCatalogEventIdentifier(catalog, input.trigger.namespace, input.trigger.identifier),
10880
- resourceType: input.trigger.resourceType,
10881
- label: input.trigger.label,
10882
- events: [...new Set(input.trigger.events)],
10883
- ...match ? { match } : void 0
10884
- } : current.trigger;
10885
- const nextInstruction = input.instruction != null ? input.instruction : current.task.text;
10886
- const instructionChanged = nextInstruction !== current.task.text;
10887
- const changesExecution = instructionChanged || changesEventAutomationTrigger(current.trigger, nextTrigger);
10888
- const next = {
10889
- ...current,
10890
- credentialMode: changesExecution && !isCreator ? "system" : input.credentialMode ?? current.credentialMode,
10891
- outcomes: input.outcomes == null ? current.outcomes : await resolveTaskOutcomes(input.outcomes, current.destination, current.createdBy.slackUserId),
10892
- task: { text: nextInstruction },
10893
- trigger: nextTrigger
10894
- };
10895
- if (instructionChanged) {
10896
- const title = await generateShortTitle({
10897
- signal: options.signal,
10898
- completeText,
10899
- kind: "task",
10900
- sourceText: nextInstruction
10901
- });
10902
- if (title) next.title = title;
10903
- else delete next.title;
10904
- }
10905
- const saved = await saveEventAutomation(getDb(), next);
10931
+ if (input.title === void 0 && input.instruction === void 0 && input.trigger === void 0 && input.outcomes == null && input.credentialMode == null) throw new ToolInputError("Event automation update requires a change.");
10932
+ const next = await editEventAutomation(current, {
10933
+ title: input.title,
10934
+ instruction: input.instruction ?? void 0,
10935
+ trigger: input.trigger ?? void 0,
10936
+ outcomes: input.outcomes ?? void 0,
10937
+ credentialMode: input.credentialMode ?? void 0
10938
+ }, isCreator, catalog);
10939
+ const saved = await saveEventAutomation(getDb(), next, automationRevision(current));
10906
10940
  if (!saved) throw new ToolInputError("Event automation was not found.");
10907
10941
  return eventAutomationToolResult(context.conversationId, saved, catalog, actor.userId);
10908
10942
  }
@@ -10921,113 +10955,6 @@ function createEventAutomationTools(context, catalog) {
10921
10955
  };
10922
10956
  }
10923
10957
  //#endregion
10924
- //#region src/chat/scheduled-automations/types.ts
10925
- /** Durable scheduled-automation domain types owned by Junior core. */
10926
- const scheduledAutomationStatusSchema = z.enum([
10927
- "active",
10928
- "blocked",
10929
- "completed",
10930
- "deleted"
10931
- ]);
10932
- const scheduledAutomationCredentialModeSchema = z.enum(["system", "creator"]);
10933
- const scheduledRunStatusSchema = z.enum([
10934
- "pending",
10935
- "running",
10936
- "completed",
10937
- "failed",
10938
- "blocked",
10939
- "skipped"
10940
- ]);
10941
- const scheduledAutomationPrincipalSchema = z.object({
10942
- slackUserId: actorUserIdSchema,
10943
- fullName: z.string().optional(),
10944
- userName: z.string().optional()
10945
- }).strict();
10946
- const scheduledAutomationRecurrenceSchema = z.object({
10947
- dayOfMonth: z.number().optional(),
10948
- frequency: z.enum([
10949
- "daily",
10950
- "weekly",
10951
- "monthly",
10952
- "yearly"
10953
- ]),
10954
- interval: z.number(),
10955
- month: z.number().optional(),
10956
- startDate: z.string(),
10957
- time: z.object({
10958
- hour: z.number(),
10959
- minute: z.number()
10960
- }).strict(),
10961
- weekdays: z.array(z.number()).optional()
10962
- }).strict();
10963
- const scheduledAutomationScheduleSchema = z.object({
10964
- description: z.string(),
10965
- kind: z.enum(["one_off", "recurring"]),
10966
- recurrence: scheduledAutomationRecurrenceSchema.optional(),
10967
- timezone: z.string()
10968
- }).strict();
10969
- const scheduledAutomationExecutionActorSchema = z.object({
10970
- platform: z.literal("system"),
10971
- name: z.string()
10972
- }).strict();
10973
- /** Scheduled automations target a Slack conversation, never one message thread. */
10974
- const scheduledAutomationDestinationSchema = slackDestinationSchema.omit({ threadTs: true });
10975
- const scheduledAutomationOutcomeSchema = z.object({
10976
- action: z.literal("send_message"),
10977
- destination: scheduledAutomationDestinationSchema
10978
- }).strict();
10979
- /** Validate the current scheduled-automation domain shape. */
10980
- const scheduledAutomationSchema = z.object({
10981
- id: z.string(),
10982
- conversationAccess: z.object({
10983
- audience: z.enum([
10984
- "direct",
10985
- "group",
10986
- "channel"
10987
- ]),
10988
- visibility: z.enum(["private", "public"])
10989
- }).strict(),
10990
- createdAtMs: z.number(),
10991
- createdBy: scheduledAutomationPrincipalSchema,
10992
- /** Authoritative provider identity that created the task. */
10993
- creatorIdentityId: z.string(),
10994
- /** Selects system credentials or task-bound creator credential delegation. */
10995
- credentialMode: scheduledAutomationCredentialModeSchema,
10996
- destination: scheduledAutomationDestinationSchema,
10997
- executionActor: scheduledAutomationExecutionActorSchema.optional(),
10998
- lastRunAtMs: z.number().optional(),
10999
- nextRunAtMs: z.number().optional(),
11000
- originalRequest: z.string().optional(),
11001
- runNowAtMs: z.number().optional(),
11002
- schedule: scheduledAutomationScheduleSchema,
11003
- status: scheduledAutomationStatusSchema,
11004
- statusReason: z.string().optional(),
11005
- /** Explicit visible effects after successful work. An empty list is silent. */
11006
- outcomes: z.array(scheduledAutomationOutcomeSchema).max(5),
11007
- task: z.object({ text: z.string() }).strict(),
11008
- /** SQL-backed short display title generated from the task instruction. */
11009
- title: z.string().optional(),
11010
- updatedAtMs: z.number()
11011
- }).strict();
11012
- /** Validate the current scheduled-run domain shape. */
11013
- const scheduledRunSchema = z.object({
11014
- id: z.string(),
11015
- attempt: z.number(),
11016
- claimedAtMs: z.number(),
11017
- completedAtMs: z.number().optional(),
11018
- dispatchId: z.string().optional(),
11019
- errorMessage: z.string().optional(),
11020
- resultMessageTs: z.string().optional(),
11021
- scheduledForMs: z.number(),
11022
- startedAtMs: z.number().optional(),
11023
- status: scheduledRunStatusSchema,
11024
- taskId: z.string()
11025
- }).strict();
11026
- const SCHEDULED_AUTOMATION_SYSTEM_ACTOR = Object.freeze({
11027
- platform: "system",
11028
- name: "scheduled-automation"
11029
- });
11030
- //#endregion
11031
10958
  //#region src/chat/scheduled-automations/tasks.ts
11032
10959
  const SCHEDULER_KEY_PREFIX = "junior:scheduler";
11033
10960
  const retainedScheduledAutomationSchema = scheduledAutomationSchema.omit({
@@ -11036,13 +10963,6 @@ const retainedScheduledAutomationSchema = scheduledAutomationSchema.omit({
11036
10963
  }).extend({
11037
10964
  destination: slackDestinationSchema,
11038
10965
  outcomes: z.array(taskOutcomeSchema).max(5),
11039
- status: z.enum([
11040
- "active",
11041
- "blocked",
11042
- "completed",
11043
- "deleted",
11044
- "paused"
11045
- ]),
11046
10966
  version: z.number().optional()
11047
10967
  }).strict();
11048
10968
  /** Decode a retained scheduler task row and reject invalid routing context. */
@@ -11082,15 +11002,6 @@ function parseScheduledAutomationRow(row) {
11082
11002
  if (creatorIdentityId === void 0) return void 0;
11083
11003
  const fallbackTitle = row.title === null ? z.string().safeParse(legacyTitle) : void 0;
11084
11004
  const title = (row.title !== null ? row.title : fallbackTitle?.success ? fallbackTitle.data : void 0)?.trim() || void 0;
11085
- if (status === "paused") {
11086
- const { nextRunAtMs: _nextRunAtMs, runNowAtMs: _runNowAtMs, ...retained } = task;
11087
- return {
11088
- ...retained,
11089
- creatorIdentityId,
11090
- status: "deleted",
11091
- ...title ? { title } : void 0
11092
- };
11093
- }
11094
11005
  return {
11095
11006
  ...task,
11096
11007
  creatorIdentityId,
@@ -11169,7 +11080,7 @@ async function readListedScheduledAutomations(db, teamId) {
11169
11080
  creatorIdentityId: juniorSchedulerTasks.creatorIdentityId,
11170
11081
  record: juniorSchedulerTasks.record,
11171
11082
  title: juniorSchedulerTasks.title
11172
- }).from(juniorSchedulerTasks).where(and(notInArray(juniorSchedulerTasks.status, ["deleted", "paused"]), teamId === void 0 ? void 0 : eq(juniorSchedulerTasks.teamId, teamId))).orderBy(asc(juniorSchedulerTasks.createdAtMs), asc(juniorSchedulerTasks.id))).map(parseScheduledAutomationRow).filter(isListedScheduledAutomation);
11083
+ }).from(juniorSchedulerTasks).where(and(notInArray(juniorSchedulerTasks.status, ["deleted"]), teamId === void 0 ? void 0 : eq(juniorSchedulerTasks.teamId, teamId))).orderBy(asc(juniorSchedulerTasks.createdAtMs), asc(juniorSchedulerTasks.id))).map(parseScheduledAutomationRow).filter(isListedScheduledAutomation);
11173
11084
  }
11174
11085
  /** List decoded scheduled automations in stable creation order. */
11175
11086
  async function listScheduledAutomations(db) {
@@ -11213,10 +11124,11 @@ async function createScheduledAutomation(db, task) {
11213
11124
  });
11214
11125
  }
11215
11126
  /** Save a scheduled automation and clear its blocked occurrence on reactivation. */
11216
- async function saveScheduledAutomation(db, task) {
11127
+ async function saveScheduledAutomation(db, task, expectedRevision) {
11217
11128
  const next = requireStoredTask(task);
11218
11129
  await withScheduledAutomationLock(db, task.id, async (tx) => {
11219
11130
  const current = await readScheduledAutomation(tx, task.id);
11131
+ if (expectedRevision !== void 0) requireAutomationRevision(current, expectedRevision);
11220
11132
  await writeScheduledAutomation(tx, next, current);
11221
11133
  });
11222
11134
  return next;
@@ -11225,472 +11137,6 @@ async function saveScheduledAutomation(db, task) {
11225
11137
  async function saveScheduledAutomationInLock(db, task, current) {
11226
11138
  await writeScheduledAutomation(db, requireStoredTask(task), current);
11227
11139
  }
11228
- /** List scheduled automations whose current Slack destination is public. */
11229
- async function listPublicScheduledAutomationsForTeams(db, teamIds, input) {
11230
- if (teamIds.length === 0) return [];
11231
- return (await db.select({
11232
- creatorIdentityId: juniorSchedulerTasks.creatorIdentityId,
11233
- record: juniorSchedulerTasks.record,
11234
- title: juniorSchedulerTasks.title
11235
- }).from(juniorSchedulerTasks).innerJoin(juniorDestinations, and(eq(juniorDestinations.provider, "slack"), eq(juniorDestinations.providerTenantId, juniorSchedulerTasks.teamId), sql`${juniorDestinations.providerDestinationId} = ${juniorSchedulerTasks.record}->'destination'->>'channelId'`)).where(and(inArray(juniorSchedulerTasks.teamId, teamIds), notInArray(juniorSchedulerTasks.status, [
11236
- "completed",
11237
- "deleted",
11238
- "paused"
11239
- ]), input.query ? sql`strpos(lower(coalesce(${juniorSchedulerTasks.title}, ${juniorSchedulerTasks.record}->'task'->>'text')), ${input.query}) > 0` : void 0, eq(juniorDestinations.visibility, "public"))).orderBy(desc(juniorSchedulerTasks.createdAtMs), desc(juniorSchedulerTasks.id)).limit(input.limit)).map(parseScheduledAutomationRow).filter(isListedScheduledAutomation);
11240
- }
11241
- //#endregion
11242
- //#region src/chat/scheduled-automations/cadence.ts
11243
- const FORMATTERS = /* @__PURE__ */ new Map();
11244
- function getFormatter(timezone) {
11245
- const existing = FORMATTERS.get(timezone);
11246
- if (existing) return existing;
11247
- const formatter = new Intl.DateTimeFormat("en-US", {
11248
- timeZone: timezone,
11249
- hour12: false,
11250
- year: "numeric",
11251
- month: "2-digit",
11252
- day: "2-digit",
11253
- hour: "2-digit",
11254
- minute: "2-digit",
11255
- second: "2-digit"
11256
- });
11257
- FORMATTERS.set(timezone, formatter);
11258
- return formatter;
11259
- }
11260
- function normalizeHour(hour) {
11261
- return hour === 24 ? 0 : hour;
11262
- }
11263
- function getLocalDateWeekday(date) {
11264
- return new Date(Date.UTC(date.year, date.month - 1, date.day)).getUTCDay();
11265
- }
11266
- function getWeekStart(date) {
11267
- return addDays(date, -((getLocalDateWeekday(date) + 6) % 7));
11268
- }
11269
- /** Resolve a UTC timestamp into calendar parts for a named time zone. */
11270
- function getZonedDateTimeParts(timestampMs, timezone) {
11271
- const parts = getFormatter(timezone).formatToParts(new Date(timestampMs));
11272
- const values = new Map(parts.map((part) => [part.type, part.value]));
11273
- const year = Number(values.get("year"));
11274
- const month = Number(values.get("month"));
11275
- const day = Number(values.get("day"));
11276
- return {
11277
- year,
11278
- month,
11279
- day,
11280
- hour: normalizeHour(Number(values.get("hour"))),
11281
- minute: Number(values.get("minute")),
11282
- second: Number(values.get("second")),
11283
- weekday: getLocalDateWeekday({
11284
- year,
11285
- month,
11286
- day
11287
- })
11288
- };
11289
- }
11290
- function getTimeZoneOffsetMs(timestampMs, timezone) {
11291
- const parts = getZonedDateTimeParts(timestampMs, timezone);
11292
- return Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second) - timestampMs;
11293
- }
11294
- function localDateTimeToTimestampMs(args) {
11295
- const localAsUtcMs = Date.UTC(args.date.year, args.date.month - 1, args.date.day, args.time.hour, args.time.minute, 0);
11296
- const offsets = /* @__PURE__ */ new Set();
11297
- for (const probeDeltaMs of [
11298
- -1296e5,
11299
- -432e5,
11300
- 0,
11301
- 432e5,
11302
- 1296e5
11303
- ]) offsets.add(getTimeZoneOffsetMs(localAsUtcMs + probeDeltaMs, args.timezone));
11304
- const matches = [...offsets].map((offsetMs) => localAsUtcMs - offsetMs).filter((timestampMs) => {
11305
- const parts = getZonedDateTimeParts(timestampMs, args.timezone);
11306
- return parts.year === args.date.year && parts.month === args.date.month && parts.day === args.date.day && parts.hour === args.time.hour && parts.minute === args.time.minute;
11307
- });
11308
- if (matches.length === 0) return;
11309
- return Math.min(...matches);
11310
- }
11311
- /** Resolve local time, rejecting DST gaps and choosing the earlier instant in a fold. */
11312
- function resolveLocalScheduleAtMs(args) {
11313
- const date = parseLocalDate(args.date);
11314
- if (!date) return;
11315
- return localDateTimeToTimestampMs({
11316
- date,
11317
- time: args.time,
11318
- timezone: args.timezone
11319
- });
11320
- }
11321
- function daysBetween(left, right) {
11322
- return Math.floor((Date.UTC(right.year, right.month - 1, right.day) - Date.UTC(left.year, left.month - 1, left.day)) / 864e5);
11323
- }
11324
- function weeklyRecurrenceMatchesDate(date, start, recurrence) {
11325
- if (compareDate(date, start) < 0) return false;
11326
- return normalizeWeekdays(recurrence.weekdays).includes(getLocalDateWeekday(date)) && Math.floor(daysBetween(getWeekStart(start), getWeekStart(date)) / 7) % recurrence.interval === 0;
11327
- }
11328
- function greatestCommonDivisor(left, right) {
11329
- let a = Math.abs(left);
11330
- let b = Math.abs(right);
11331
- while (b !== 0) [a, b] = [b, a % b];
11332
- return a;
11333
- }
11334
- function findNextRunAtMs(args) {
11335
- const start = parseLocalDate(args.recurrence.startDate);
11336
- const interval = args.recurrence.interval;
11337
- if (!start || !Number.isInteger(interval) || interval <= 0) return;
11338
- const searchFrom = compareDate(args.searchFrom, start) < 0 ? start : args.searchFrom;
11339
- if (args.recurrence.frequency === "daily") {
11340
- const offsetDays = daysBetween(start, searchFrom);
11341
- let candidateDate = addDays(start, Math.ceil(offsetDays / interval) * interval);
11342
- const gregorianCycleDays = 146097;
11343
- const candidateCount = gregorianCycleDays / greatestCommonDivisor(gregorianCycleDays, interval);
11344
- for (let attempts = 0; attempts < candidateCount; attempts += 1) {
11345
- const candidate = buildCandidate({
11346
- date: candidateDate,
11347
- recurrence: args.recurrence,
11348
- timezone: args.timezone
11349
- });
11350
- if (candidate !== void 0 && candidate > args.afterMs) return candidate;
11351
- candidateDate = addDays(candidateDate, interval);
11352
- }
11353
- return;
11354
- }
11355
- if (args.recurrence.frequency === "weekly") {
11356
- if (normalizeWeekdays(args.recurrence.weekdays).length === 0) return;
11357
- let candidateDate = searchFrom;
11358
- const gregorianCycleDays = 146097;
11359
- const cadenceDays = interval * 7;
11360
- const searchDays = gregorianCycleDays * cadenceDays / greatestCommonDivisor(gregorianCycleDays, cadenceDays);
11361
- for (let attempts = 0; attempts < searchDays; attempts += 1) {
11362
- if (weeklyRecurrenceMatchesDate(candidateDate, start, args.recurrence)) {
11363
- const candidate = buildCandidate({
11364
- date: candidateDate,
11365
- recurrence: args.recurrence,
11366
- timezone: args.timezone
11367
- });
11368
- if (candidate !== void 0 && candidate > args.afterMs) return candidate;
11369
- }
11370
- candidateDate = addDays(candidateDate, 1);
11371
- }
11372
- return;
11373
- }
11374
- if (args.recurrence.frequency === "monthly") {
11375
- const startMonth = start.year * 12 + start.month - 1;
11376
- const searchMonth = searchFrom.year * 12 + searchFrom.month - 1;
11377
- let candidateMonth = startMonth + Math.ceil((searchMonth - startMonth) / interval) * interval;
11378
- const gregorianCycleMonths = 4800;
11379
- const candidateCount = gregorianCycleMonths / greatestCommonDivisor(gregorianCycleMonths, interval);
11380
- for (let attempts = 0; attempts < candidateCount; attempts += 1) {
11381
- const candidateDate = {
11382
- year: Math.floor(candidateMonth / 12),
11383
- month: candidateMonth % 12 + 1,
11384
- day: args.recurrence.dayOfMonth ?? 0
11385
- };
11386
- if (compareDate(candidateDate, searchFrom) >= 0) {
11387
- const candidate = buildCandidate({
11388
- date: candidateDate,
11389
- recurrence: args.recurrence,
11390
- timezone: args.timezone
11391
- });
11392
- if (candidate !== void 0 && candidate > args.afterMs) return candidate;
11393
- }
11394
- candidateMonth += interval;
11395
- }
11396
- return;
11397
- }
11398
- let candidateYear = start.year + Math.ceil((searchFrom.year - start.year) / interval) * interval;
11399
- const candidateCount = 400 / greatestCommonDivisor(400, interval);
11400
- for (let attempts = 0; attempts < candidateCount; attempts += 1) {
11401
- const candidateDate = {
11402
- year: candidateYear,
11403
- month: args.recurrence.month ?? 0,
11404
- day: args.recurrence.dayOfMonth ?? 0
11405
- };
11406
- if (compareDate(candidateDate, searchFrom) >= 0) {
11407
- const candidate = buildCandidate({
11408
- date: candidateDate,
11409
- recurrence: args.recurrence,
11410
- timezone: args.timezone
11411
- });
11412
- if (candidate !== void 0 && candidate > args.afterMs) return candidate;
11413
- }
11414
- candidateYear += interval;
11415
- }
11416
- }
11417
- /** Compute the first recurring calendar occurrence strictly after a timestamp. */
11418
- function getFirstRunAtMs(args) {
11419
- return findNextRunAtMs({
11420
- ...args,
11421
- searchFrom: getLocalDate(args.afterMs, args.timezone)
11422
- });
11423
- }
11424
- function compareDate(left, right) {
11425
- return Date.UTC(left.year, left.month - 1, left.day) - Date.UTC(right.year, right.month - 1, right.day);
11426
- }
11427
- function addDays(date, days) {
11428
- const next = new Date(Date.UTC(date.year, date.month - 1, date.day + days));
11429
- return {
11430
- year: next.getUTCFullYear(),
11431
- month: next.getUTCMonth() + 1,
11432
- day: next.getUTCDate()
11433
- };
11434
- }
11435
- function daysInMonth(year, month) {
11436
- return new Date(Date.UTC(year, month, 0)).getUTCDate();
11437
- }
11438
- function parseLocalDate(value) {
11439
- const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
11440
- if (!match) return;
11441
- const year = Number(match[1]);
11442
- const month = Number(match[2]);
11443
- const day = Number(match[3]);
11444
- if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day) || month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month)) return;
11445
- return {
11446
- year,
11447
- month,
11448
- day
11449
- };
11450
- }
11451
- function getLocalDate(timestampMs, timezone) {
11452
- const parts = getZonedDateTimeParts(timestampMs, timezone);
11453
- return {
11454
- year: parts.year,
11455
- month: parts.month,
11456
- day: parts.day
11457
- };
11458
- }
11459
- function normalizeWeekdays(values) {
11460
- return [...new Set((values ?? []).filter((value) => value >= 0 && value <= 6))].sort((a, b) => a - b);
11461
- }
11462
- function buildCandidate(args) {
11463
- return localDateTimeToTimestampMs({
11464
- date: args.date,
11465
- time: args.recurrence.time,
11466
- timezone: args.timezone
11467
- });
11468
- }
11469
- /** Return the next fire time after a completed run, when the task recurs. */
11470
- function getNextRunAtMs(task, scheduledForMs, afterMs = scheduledForMs) {
11471
- if (task.schedule.kind !== "recurring") return;
11472
- const recurrence = task.schedule.recurrence;
11473
- if (!recurrence || !Number.isFinite(recurrence.interval) || recurrence.interval <= 0) return;
11474
- const timezone = task.schedule.timezone;
11475
- const afterDate = getLocalDate(afterMs, timezone);
11476
- const nextScheduledDate = addDays(getLocalDate(scheduledForMs, timezone), 1);
11477
- return findNextRunAtMs({
11478
- afterMs,
11479
- recurrence,
11480
- searchFrom: compareDate(afterDate, nextScheduledDate) < 0 ? nextScheduledDate : afterDate,
11481
- timezone
11482
- });
11483
- }
11484
- //#endregion
11485
- //#region src/chat/scheduled-automations/schedule-intent.ts
11486
- /**
11487
- * Owns model-facing schedule intent and materializes it against the trusted
11488
- * server clock into the canonical schedule persisted by core.
11489
- */
11490
- const localDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Use a local date in YYYY-MM-DD format.");
11491
- const localTimeSchema = z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "Use local time in HH:MM format.");
11492
- const timezoneSchema = z.string().min(1).max(80).describe("IANA timezone, for example America/Los_Angeles. Omit or use null for the scheduler default.").nullable().optional();
11493
- const weekdaySchema = z.enum([
11494
- "sunday",
11495
- "monday",
11496
- "tuesday",
11497
- "wednesday",
11498
- "thursday",
11499
- "friday",
11500
- "saturday"
11501
- ]);
11502
- const oneOffScheduleIntentSchema = z.object({
11503
- kind: z.literal("one_off").describe("A schedule that runs once."),
11504
- timezone: timezoneSchema,
11505
- timing: z.discriminatedUnion("type", [z.object({
11506
- type: z.literal("after").describe("Run after a relative delay from the server clock."),
11507
- value: z.number().int().positive().max(1e5),
11508
- unit: z.enum([
11509
- "second",
11510
- "minute",
11511
- "hour",
11512
- "day",
11513
- "week"
11514
- ])
11515
- }).strict(), z.object({
11516
- type: z.literal("at").describe("Run at an explicit local calendar date and time."),
11517
- date: localDateSchema.describe("Requested local calendar date in YYYY-MM-DD format."),
11518
- time: localTimeSchema.describe("Requested local wall-clock time in HH:MM format.")
11519
- }).strict()]).describe("Relative delay or explicit local time for the one-off run.")
11520
- }).strict();
11521
- const recurringScheduleIntentSchema = z.object({
11522
- kind: z.literal("recurring").describe("A repeating calendar schedule."),
11523
- frequency: z.enum([
11524
- "daily",
11525
- "weekly",
11526
- "monthly",
11527
- "yearly"
11528
- ]).describe("Recurring tasks can run at most once per day."),
11529
- interval: z.number().int().positive().max(365).describe("Repeat every N frequency units. Defaults to 1.").nullable().optional(),
11530
- time: localTimeSchema.describe("Local wall-clock time for each occurrence in HH:MM format."),
11531
- weekdays: z.array(weekdaySchema).min(1).max(7).describe("Required for weekly schedules.").nullable().optional(),
11532
- dayOfMonth: z.number().int().min(1).max(31).describe("Required for monthly and yearly schedules.").nullable().optional(),
11533
- month: z.number().int().min(1).max(12).describe("Required for yearly schedules, where January is 1.").nullable().optional(),
11534
- startDate: localDateSchema.describe("Optional local calendar date that anchors the recurrence. Omit to start with the next matching occurrence.").nullable().optional(),
11535
- timezone: timezoneSchema
11536
- }).strict().superRefine((schedule, context) => {
11537
- if (schedule.frequency === "weekly" && schedule.weekdays == null) context.addIssue({
11538
- code: "custom",
11539
- message: "Weekly schedules require weekdays.",
11540
- path: ["weekdays"]
11541
- });
11542
- if ((schedule.frequency === "monthly" || schedule.frequency === "yearly") && schedule.dayOfMonth == null) context.addIssue({
11543
- code: "custom",
11544
- message: `${schedule.frequency} schedules require dayOfMonth.`,
11545
- path: ["dayOfMonth"]
11546
- });
11547
- if (schedule.frequency === "yearly" && schedule.month == null) context.addIssue({
11548
- code: "custom",
11549
- message: "Yearly schedules require month.",
11550
- path: ["month"]
11551
- });
11552
- if (schedule.frequency !== "weekly" && schedule.weekdays != null) context.addIssue({
11553
- code: "custom",
11554
- message: "weekdays applies only to weekly schedules.",
11555
- path: ["weekdays"]
11556
- });
11557
- if (schedule.frequency !== "monthly" && schedule.frequency !== "yearly" && schedule.dayOfMonth != null) context.addIssue({
11558
- code: "custom",
11559
- message: "dayOfMonth applies only to monthly or yearly schedules.",
11560
- path: ["dayOfMonth"]
11561
- });
11562
- if (schedule.frequency !== "yearly" && schedule.month != null) context.addIssue({
11563
- code: "custom",
11564
- message: "month applies only to yearly schedules.",
11565
- path: ["month"]
11566
- });
11567
- });
11568
- const scheduleIntentSchema = z.union([oneOffScheduleIntentSchema, recurringScheduleIntentSchema]);
11569
- const WEEKDAY_INDEX = {
11570
- sunday: 0,
11571
- monday: 1,
11572
- tuesday: 2,
11573
- wednesday: 3,
11574
- thursday: 4,
11575
- friday: 5,
11576
- saturday: 6
11577
- };
11578
- const DURATION_MS = {
11579
- second: 1e3,
11580
- minute: 6e4,
11581
- hour: 36e5,
11582
- day: 864e5,
11583
- week: 6048e5
11584
- };
11585
- function parseLocalTime(value) {
11586
- const [hour, minute] = value.split(":").map(Number);
11587
- return {
11588
- hour,
11589
- minute
11590
- };
11591
- }
11592
- function localDateAt(timestampMs, timezone) {
11593
- const parts = getZonedDateTimeParts(timestampMs, timezone);
11594
- return [
11595
- parts.year,
11596
- parts.month,
11597
- parts.day
11598
- ].map((value, index) => index === 0 ? String(value).padStart(4, "0") : String(value).padStart(2, "0")).join("-");
11599
- }
11600
- function isValidTimeZone$1(timezone) {
11601
- try {
11602
- new Intl.DateTimeFormat("en-US", { timeZone: timezone }).format();
11603
- return true;
11604
- } catch {
11605
- return false;
11606
- }
11607
- }
11608
- function plural(value, unit) {
11609
- return value === 1 ? unit : `${unit}s`;
11610
- }
11611
- function formatWeekdays(weekdays) {
11612
- const labels = weekdays.map((weekday) => `${weekday[0].toUpperCase()}${weekday.slice(1)}`);
11613
- if (labels.length < 2) return labels[0] ?? "";
11614
- return `${labels.slice(0, -1).join(", ")} and ${labels.at(-1)}`;
11615
- }
11616
- function recurringDescription(schedule, timezone) {
11617
- const interval = schedule.interval ?? 1;
11618
- const cadenceUnit = {
11619
- daily: "day",
11620
- weekly: "week",
11621
- monthly: "month",
11622
- yearly: "year"
11623
- }[schedule.frequency];
11624
- const cadence = interval === 1 ? cadenceUnit : `${interval} ${cadenceUnit}s`;
11625
- let detail = "";
11626
- if (schedule.frequency === "weekly") detail = ` on ${formatWeekdays(schedule.weekdays)}`;
11627
- else if (schedule.frequency === "monthly") detail = ` on day ${schedule.dayOfMonth}`;
11628
- else if (schedule.frequency === "yearly") detail = ` on ${String(schedule.month).padStart(2, "0")}-${String(schedule.dayOfMonth).padStart(2, "0")}`;
11629
- return `Every ${cadence}${detail} at ${schedule.time} (${timezone})`;
11630
- }
11631
- var ScheduleIntentError = class extends Error {};
11632
- /** Materialize model-interpreted schedule intent against the trusted server clock. */
11633
- function compileScheduleIntent(args) {
11634
- const timezone = args.intent.timezone ?? args.defaultTimezone;
11635
- if (!isValidTimeZone$1(timezone)) throw new ScheduleIntentError("timezone must be a valid IANA time zone.");
11636
- if (args.intent.kind === "one_off") {
11637
- if (args.intent.timing.type === "after") return {
11638
- nextRunAtMs: args.nowMs + args.intent.timing.value * DURATION_MS[args.intent.timing.unit],
11639
- schedule: {
11640
- description: `In ${args.intent.timing.value} ${plural(args.intent.timing.value, args.intent.timing.unit)}`,
11641
- kind: "one_off",
11642
- timezone
11643
- }
11644
- };
11645
- const nextRunAtMs = resolveLocalScheduleAtMs({
11646
- date: args.intent.timing.date,
11647
- time: parseLocalTime(args.intent.timing.time),
11648
- timezone
11649
- });
11650
- if (nextRunAtMs === void 0) throw new ScheduleIntentError("The requested local date or time does not exist in that timezone.");
11651
- if (nextRunAtMs <= args.nowMs) throw new ScheduleIntentError("The requested one-off schedule must be in the future.");
11652
- return {
11653
- nextRunAtMs,
11654
- schedule: {
11655
- description: `Once on ${args.intent.timing.date} at ${args.intent.timing.time} (${timezone})`,
11656
- kind: "one_off",
11657
- timezone
11658
- }
11659
- };
11660
- }
11661
- const recurrence = {
11662
- frequency: args.intent.frequency,
11663
- interval: args.intent.interval ?? 1,
11664
- startDate: args.intent.startDate ?? localDateAt(args.nowMs, timezone),
11665
- time: parseLocalTime(args.intent.time),
11666
- ...args.intent.frequency === "weekly" ? { weekdays: [...new Set(args.intent.weekdays.map((weekday) => WEEKDAY_INDEX[weekday]))].sort((left, right) => left - right) } : void 0,
11667
- ...args.intent.frequency === "monthly" || args.intent.frequency === "yearly" ? { dayOfMonth: args.intent.dayOfMonth ?? void 0 } : void 0,
11668
- ...args.intent.frequency === "yearly" ? { month: args.intent.month ?? void 0 } : void 0
11669
- };
11670
- const searchRecurrence = args.intent.startDate ? recurrence : {
11671
- ...recurrence,
11672
- interval: 1
11673
- };
11674
- const nextRunAtMs = getFirstRunAtMs({
11675
- afterMs: args.nowMs,
11676
- recurrence: searchRecurrence,
11677
- timezone
11678
- });
11679
- if (nextRunAtMs === void 0) throw new ScheduleIntentError("The recurring schedule has no valid future occurrence.");
11680
- const materializedRecurrence = args.intent.startDate ? recurrence : {
11681
- ...recurrence,
11682
- startDate: localDateAt(nextRunAtMs, timezone)
11683
- };
11684
- return {
11685
- nextRunAtMs,
11686
- schedule: {
11687
- description: recurringDescription(args.intent, timezone),
11688
- kind: "recurring",
11689
- recurrence: materializedRecurrence,
11690
- timezone
11691
- }
11692
- };
11693
- }
11694
11140
  //#endregion
11695
11141
  //#region src/chat/scheduled-automations/telemetry.ts
11696
11142
  /** Safe structured telemetry attributes for scheduled-automation lifecycle events. */
@@ -11765,6 +11211,7 @@ const compactTaskResultSchema = z.object({
11765
11211
  status: z.enum([
11766
11212
  "active",
11767
11213
  "blocked",
11214
+ "paused",
11768
11215
  "completed",
11769
11216
  "deleted"
11770
11217
  ]),
@@ -12082,17 +11529,18 @@ function createSlackScheduleDeleteAutomationTool(context) {
12082
11529
  inputSchema: z.object({ automationId: z.string().min(1).describe("ID of the task to delete. Must be from this active Slack conversation.") }),
12083
11530
  outputSchema: scheduleAutomationToolResultSchema.extend({ removedCards: z.array(removedCardSchema) }),
12084
11531
  execute: async ({ automationId }) => {
11532
+ const lookup = await getWritableTask({
11533
+ context,
11534
+ taskId: automationId
11535
+ });
12085
11536
  const next = {
12086
- ...await getWritableTask({
12087
- context,
12088
- taskId: automationId
12089
- }),
11537
+ ...lookup,
12090
11538
  updatedAtMs: Date.now(),
12091
11539
  status: "deleted",
12092
11540
  nextRunAtMs: void 0,
12093
11541
  runNowAtMs: void 0
12094
11542
  };
12095
- await saveScheduledAutomation(getDb(), next);
11543
+ await saveScheduledAutomation(getDb(), next, automationRevision(lookup));
12096
11544
  await createPluginAnnotations({
12097
11545
  conversationId: context.conversationId,
12098
11546
  db: getDb(),
@@ -12226,12 +11674,46 @@ function createSlackScheduleRunAutomationNowTool(context) {
12226
11674
  updatedAtMs: nowMs,
12227
11675
  runNowAtMs: nowMs
12228
11676
  };
12229
- await saveScheduledAutomation(getDb(), next);
11677
+ await saveScheduledAutomation(getDb(), next, automationRevision(lookup));
12230
11678
  return { automation: compactTask(next, context.actor?.userId) };
12231
11679
  }
12232
11680
  });
12233
11681
  }
12234
11682
  //#endregion
11683
+ //#region src/chat/scheduled-automations/edit.ts
11684
+ /** Build an edit without restarting completed work or changing creator identity. */
11685
+ async function editScheduledAutomation(current, input, isCreator, nowMs) {
11686
+ if (current.status === "completed" || current.status === "deleted") throw new AutomationEditError("Completed scheduled automations cannot be updated. Create a new automation instead.");
11687
+ let compiled;
11688
+ if (input.schedule !== void 0) try {
11689
+ compiled = compileScheduleIntent({
11690
+ defaultTimezone: current.schedule.timezone || getDefaultScheduleTimezone(),
11691
+ intent: input.schedule,
11692
+ nowMs
11693
+ });
11694
+ } catch (error) {
11695
+ if (error instanceof ScheduleIntentError) throw new AutomationEditError(error.message, "schedule");
11696
+ throw error;
11697
+ }
11698
+ const nextRunAtMs = compiled?.nextRunAtMs ?? current.nextRunAtMs;
11699
+ if (input.status === "active" && !nextRunAtMs) throw new AutomationEditError("Active scheduled automations require a schedule with a future occurrence.", "schedule");
11700
+ if (current.status === "paused" && input.status !== void 0) throw new AutomationEditError("Use Resume in the Automation settings to resume paused work.", "status");
11701
+ const status = input.status ?? current.status;
11702
+ const changesExecution = input.instruction !== void 0 && input.instruction !== current.task.text;
11703
+ return {
11704
+ ...current,
11705
+ ...await editAutomationFields(current, input, isCreator, changesExecution),
11706
+ updatedAtMs: nowMs,
11707
+ schedule: compiled?.schedule ?? current.schedule,
11708
+ nextRunAtMs,
11709
+ ...compiled !== void 0 || input.status !== void 0 ? {
11710
+ runNowAtMs: status === "active" && !compiled ? current.runNowAtMs : void 0,
11711
+ statusReason: status === "blocked" || status === "paused" ? current.statusReason : void 0
11712
+ } : void 0,
11713
+ status
11714
+ };
11715
+ }
11716
+ //#endregion
12235
11717
  //#region src/chat/scheduled-automations/tools/update.ts
12236
11718
  /** Create a tool that edits a scheduled automation, including moving it here. */
12237
11719
  function createSlackScheduleUpdateAutomationTool(context) {
@@ -12247,7 +11729,8 @@ function createSlackScheduleUpdateAutomationTool(context) {
12247
11729
  executionMode: "sequential",
12248
11730
  inputSchema: z.object({
12249
11731
  automationId: z.string().min(1).describe("Scheduled automation ID returned by slackScheduleListAutomations."),
12250
- instruction: z.string().min(1).max(4e3).optional(),
11732
+ title: automationTitleSchema.optional(),
11733
+ instruction: automationInstructionSchema.optional(),
12251
11734
  schedule: scheduleIntentSchema.describe("Complete replacement schedule. Omit to keep it unchanged.").nullable().optional(),
12252
11735
  outcomes: z.array(taskOutcomeInputSchema).max(5).describe("Replacement messages to send after successful work. Use an empty list to send nothing. Omit to keep unchanged.").optional(),
12253
11736
  status: z.enum(["active", "blocked"]).describe("Set active to resume a blocked task, or blocked to stop dispatch.").optional(),
@@ -12255,7 +11738,7 @@ function createSlackScheduleUpdateAutomationTool(context) {
12255
11738
  credentialMode: z.enum(["system", "creator"]).nullable().describe("Use creator credentials or system credentials. Only the task creator may enable creator mode. Omit to keep unchanged.").optional()
12256
11739
  }).strict(),
12257
11740
  outputSchema: scheduleAutomationToolResultSchema,
12258
- execute: async (input, options) => {
11741
+ execute: async (input) => {
12259
11742
  const activeDestination = requireActiveChannel(context);
12260
11743
  const actor = requireActor(context, activeDestination);
12261
11744
  const db = getDb();
@@ -12277,52 +11760,24 @@ function createSlackScheduleUpdateAutomationTool(context) {
12277
11760
  if ((await db.select({ id: juniorSchedulerRuns.id }).from(juniorSchedulerRuns).where(and(eq(juniorSchedulerRuns.taskId, lookup.id), inArray(juniorSchedulerRuns.status, ["pending", "running"]))).limit(1)).length > 0) throwToolInputError("Scheduled automation cannot be moved while an occurrence is already running. Try again after the current run finishes.");
12278
11761
  }
12279
11762
  const nowMs = context.now?.() ?? Date.now();
12280
- let compiled;
12281
- if (input.schedule) try {
12282
- compiled = compileScheduleIntent({
12283
- defaultTimezone: lookup.schedule.timezone || getDefaultScheduleTimezone(),
12284
- intent: input.schedule,
12285
- nowMs
12286
- });
12287
- } catch (error) {
12288
- if (error instanceof ScheduleIntentError) throwToolInputError(error.message);
12289
- throw error;
12290
- }
12291
- const nextRunAtMs = compiled?.nextRunAtMs ?? lookup.nextRunAtMs;
12292
11763
  const status = normalizeStatus(input.status);
12293
11764
  if (input.status && !status) throwToolInputError("status must be active or blocked.");
12294
- if (status === "active" && !nextRunAtMs) throwToolInputError("Active scheduled automations require a schedule with a future occurrence.");
12295
- const nextStatus = status ?? lookup.status;
12296
- const credentialMode = input.instruction !== void 0 && input.instruction !== lookup.task.text && !isCreator ? "system" : input.credentialMode ?? lookup.credentialMode;
12297
- const nextInstruction = input.instruction !== void 0 ? input.instruction : lookup.task.text;
12298
- const instructionChanged = nextInstruction !== lookup.task.text;
12299
- const nextDestination = changingDestination ? requestedDestination : lookup.destination;
12300
- const next = {
12301
- ...lookup,
12302
- conversationAccess: changingDestination ? getConversationAccess(activeDestination, context.source) : lookup.conversationAccess,
12303
- credentialMode,
12304
- destination: nextDestination,
12305
- updatedAtMs: nowMs,
12306
- nextRunAtMs,
12307
- runNowAtMs: nextStatus === "active" && !compiled ? lookup.runNowAtMs : void 0,
12308
- status: nextStatus,
12309
- statusReason: nextStatus === "blocked" ? lookup.statusReason : void 0,
12310
- schedule: compiled?.schedule ?? lookup.schedule,
12311
- outcomes: input.outcomes === void 0 ? changingDestination ? moveTaskOutcomes(lookup.outcomes, lookup.destination, nextDestination) : lookup.outcomes : await resolveTaskOutcomes(input.outcomes, nextDestination, lookup.createdBy.slackUserId),
12312
- task: { text: nextInstruction }
12313
- };
12314
- if (instructionChanged) {
12315
- const title = await generateShortTitle({
12316
- signal: options.signal,
12317
- completeText,
12318
- kind: "task",
12319
- sourceText: nextInstruction
12320
- });
12321
- if (title) next.title = title;
12322
- else delete next.title;
11765
+ const instructionChanged = input.instruction !== void 0 && input.instruction !== lookup.task.text;
11766
+ const next = await editScheduledAutomation(lookup, {
11767
+ title: input.title,
11768
+ instruction: input.instruction,
11769
+ schedule: input.schedule ?? void 0,
11770
+ status,
11771
+ credentialMode: input.credentialMode ?? void 0,
11772
+ outcomes: changingDestination ? void 0 : input.outcomes
11773
+ }, isCreator, nowMs);
11774
+ if (changingDestination) {
11775
+ next.destination = requestedDestination;
11776
+ next.conversationAccess = getConversationAccess(activeDestination, context.source);
11777
+ next.outcomes = input.outcomes === void 0 ? moveTaskOutcomes(lookup.outcomes, lookup.destination, requestedDestination) : await resolveTaskOutcomes(input.outcomes, requestedDestination, lookup.createdBy.slackUserId);
12323
11778
  }
12324
- if (!changingDestination && !instructionChanged && !compiled && status === void 0 && (input.credentialMode === void 0 || input.credentialMode === null || input.credentialMode === lookup.credentialMode) && input.outcomes === void 0 && moveDestination) return scheduleAutomationToolResult(context.conversationId, lookup, actor.slackUserId);
12325
- const committed = await saveScheduledAutomation(db, next);
11779
+ if (!changingDestination && !instructionChanged && !input.schedule && input.title === void 0 && status === void 0 && (input.credentialMode === void 0 || input.credentialMode === null || input.credentialMode === lookup.credentialMode) && input.outcomes === void 0 && moveDestination) return scheduleAutomationToolResult(context.conversationId, lookup, actor.slackUserId);
11780
+ const committed = await saveScheduledAutomation(db, next, automationRevision(lookup));
12326
11781
  if (changingDestination) logInfo("scheduled_automation.move.completed", scheduledAutomationAttributes(committed));
12327
11782
  return scheduleAutomationToolResult(context.conversationId, committed, actor.slackUserId);
12328
11783
  }
@@ -21935,7 +21390,7 @@ function createAgentRunner(execute, options) {
21935
21390
  } } : void 0
21936
21391
  };
21937
21392
  if (run.instruction.storedAttachments?.length) {
21938
- const { loadInputImages } = await import("./images-zuEwjVKU.js").then((n) => n.n);
21393
+ const { loadInputImages } = await import("./images-BaL19wFC.js").then((n) => n.n);
21939
21394
  const storage = nextRun.environment?.attachmentStorage;
21940
21395
  if (!storage) throw new Error("Attachment storage is unavailable.");
21941
21396
  nextRun.instruction = {
@@ -21986,4 +21441,4 @@ async function runAgentWithTimeout(agentRunner, run, timeoutMs) {
21986
21441
  }
21987
21442
  }
21988
21443
  //#endregion
21989
- export { collectEventAutomationMatchKeys as $, recordFinishedTurnForAutomatedLimit as $t, requestAttachmentDeletion as A, getConfigDefaults as An, deadLetterAttempt as At, isListedScheduledAutomation as B, removeActiveConversation as Bt, readPublicArtifact as C, createUserTokenStore as Cn, cancelHumanFacingPendingMessages as Ct, renderBlockText as D, toolInvocationDestination as Dn, completeConversationStop as Dt, renderAttachmentText as E, actorFromRun as En, clearExpiredConversationLease as Et, resolveSlackChannelIdFromThreadId as F, hasRunnableConversationWork as Ft, readScheduledAutomation as G, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as Gt, listScheduledAutomations as H, requestConversationWork as Ht, listThreadReplies as I, listActiveConversationIds as It, scheduledRunId as J, hasRunnableConversationWork$1 as Jt, saveScheduledAutomation as K, CONVERSATION_WORK_STALE_ENQUEUE_MS as Kt, logScheduledAutomationRunSkipped as L, recordAttemptFailure as Lt, parseSlackThreadId as M, ensureConversationWake as Mt, readSlackRawMessageContext as N, getConversation as Nt, collectAttachmentGarbage as O, AuthorizationFlowDisabledError as On, completeConversationWork as Ot, resolveSlackChannelIdFromMessage as P, getConversationWorkState as Pt, effectiveTaskOutcomes as Q, maybePostAutomatedTurnLimitNotice as Qt, scheduledAutomationRunAttributes as R, recordConversationRetry as Rt, publicArtifactHeaders as S, slackExternalRefIdSchema as Sn, beginConversationResume as St, lookupSlackUserProfile as T, RetryableDeliveryError as Tn, clearConsumedConversationWake as Tt, listScheduledAutomationsForTeam as U, startConversationWork as Ut, listPublicScheduledAutomationsForTeams as V, requestAnotherSlice as Vt, parseScheduledAutomationRow as W, stopConversationWork as Wt, scheduledRunSchema as X, isInvalidConversationRecordError as Xt, withScheduledAutomationLock as Y, isFinalAttempt as Yt, eventAutomationTriggerAvailable as Z, renderTaskInput as Zt, putMcpStoredOAuthCredentials as _, truncateStatusText as _n, getEventCatalog as _t, isExperimentalFeatureEnabled as a, consumeSandboxEgressAuthRequiredSignal as an, listEventAutomationsCreatedBy as at, readStats as b, removeReactionFromMessage as bn, appendAndEnqueueExclusiveInboundMessage as bt, createContextCompactor as c, sandboxEgressSignalsResponseSchema as cn, agentInvocationSchema as ct, deleteMcpAuthSession as d, resolveBaseUrl as dn, AgentInvocationLimitError as dt, resolveSandboxEgressProviderForHost as en, deleteEventAutomation as et, deleteMcpAuthSessionsForUserProvider as f, startOAuthFlow as fn, getMcpProviderErrorAttributes as ft, getMcpStoredOAuthCredentials as g, normalizeSlackStatusText as gn, isEventMailboxMetadata as gt, getMcpAuthSession as h, normalizeSlackReplyMarkdown as hn, EVENT_WAIT_MS as ht, getExperimentalFeatures as i, clearSandboxEgressSignals as in, listDeletedEventAutomationsCreatedBy as it, storeAttachment as j, setConfigDefaults as jn, drainConversationMailbox as jt, readLiveAttachment as k, shouldEmitDevAgentTrace as kn, countPendingConversationMessages as kt, executeCredentialedEgressRequest as l, formatProviderLabel as ln, createAgentInvocationSchema as lt, deleteMcpStoredOAuthCredentials as m, formatSlackLink as mn, ingestEvent as mt, runAgentWithTimeout as n, shouldPropagateSandboxEgressTrace as nn, findMatchingEventAutomations as nt, setExperimentalFeatures as o, consumeSandboxEgressPermissionDeniedSignal as on, listPublicEventAutomationsForTeams as ot, deleteMcpServerSessionId as p, escapeSlackMrkdwnText as pn, processWorkspaceSnapshotJob as pt, saveScheduledAutomationInLock as q, hasConversationStop as qt, experimental_exports as r, SANDBOX_EGRESS_PROXY_PATH as rn, getEventAutomation as rt, executeAgentRun as s, parseSandboxEgressCredentialToken as sn, agentBindingSchema as st, createAgentRunner as t, normalizeSandboxEgressTracePropagationDomains as tn, eventAutomationBelongsToUser as tt, finalizeMcpAuthorization as u, parseOAuthStatePayload as un, AgentInvocationBusyError as ut, PluginCredentialFailureError as v, addReactionToMessage as vn, eventGuidance as vt, unpublishedArtifactHeaders as w, buildSteeringPiMessage as wn, checkInConversationWork as wt, resolvePluginOAuthAccount as x, slackEntitySchema as xn, appendAndEnqueueInboundMessage as xt, latestProgressStatus as y, postSlackMessage as yn, ackMessages as yt, getNextRunAtMs as z, releaseConversationWork as zt };
21444
+ export { deleteEventAutomation as $, isFinalAttempt as $t, requestAttachmentDeletion as A, actorFromRun as An, clearExpiredConversationLease as At, listScheduledAutomations as B, listActiveConversationIds as Bt, readPublicArtifact as C, postSlackMessage as Cn, ackMessages as Ct, renderBlockText as D, createUserTokenStore as Dn, cancelHumanFacingPendingMessages as Dt, renderAttachmentText as E, slackExternalRefIdSchema as En, beginConversationResume as Et, resolveSlackChannelIdFromThreadId as F, setConfigDefaults as Fn, drainConversationMailbox as Ft, saveScheduledAutomationInLock as G, requestAnotherSlice as Gt, parseScheduledAutomationRow as H, recordConversationRetry as Ht, listThreadReplies as I, ensureConversationWake as It, editEventAutomation as J, stopConversationWork as Jt, scheduledRunId as K, requestConversationWork as Kt, editScheduledAutomation as L, getConversation as Lt, parseSlackThreadId as M, AuthorizationFlowDisabledError as Mn, completeConversationWork as Mt, readSlackRawMessageContext as N, shouldEmitDevAgentTrace as Nn, countPendingConversationMessages as Nt, collectAttachmentGarbage as O, buildSteeringPiMessage as On, checkInConversationWork as Ot, resolveSlackChannelIdFromMessage as P, getConfigDefaults as Pn, deadLetterAttempt as Pt, collectEventAutomationMatchKeys as Q, hasRunnableConversationWork$1 as Qt, logScheduledAutomationRunSkipped as R, getConversationWorkState as Rt, publicArtifactHeaders as S, addReactionToMessage as Sn, pluginEventCatalog as St, lookupSlackUserProfile as T, slackEntitySchema as Tn, appendAndEnqueueInboundMessage as Tt, readScheduledAutomation as U, releaseConversationWork as Ut, listScheduledAutomationsForTeam as V, recordAttemptFailure as Vt, saveScheduledAutomation as W, removeActiveConversation as Wt, eventAutomationTriggerAvailable as X, CONVERSATION_WORK_STALE_ENQUEUE_MS as Xt, AutomationEditError as Y, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as Yt, effectiveTaskOutcomes as Z, hasConversationStop as Zt, putMcpStoredOAuthCredentials as _, escapeSlackMrkdwnText as _n, ingestEvent as _t, isExperimentalFeatureEnabled as a, normalizeSandboxEgressTracePropagationDomains as an, saveEventAutomation as at, readStats as b, normalizeSlackStatusText as bn, getEventCatalog as bt, createContextCompactor as c, clearSandboxEgressSignals as cn, automationRevision as ct, deleteMcpAuthSession as d, parseSandboxEgressCredentialToken as dn, agentInvocationSchema as dt, isInvalidConversationRecordError as en, eventAutomationBelongsToUser as et, deleteMcpAuthSessionsForUserProvider as f, sandboxEgressSignalsResponseSchema as fn, createAgentInvocationSchema as ft, getMcpStoredOAuthCredentials as g, startOAuthFlow as gn, processWorkspaceSnapshotJob as gt, getMcpAuthSession as h, resolveBaseUrl as hn, getMcpProviderErrorAttributes as ht, getExperimentalFeatures as i, resolveSandboxEgressProviderForHost as in, parseEventAutomationRow as it, storeAttachment as j, toolInvocationDestination as jn, completeConversationStop as jt, readLiveAttachment as k, RetryableDeliveryError as kn, clearConsumedConversationWake as kt, executeCredentialedEgressRequest as l, consumeSandboxEgressAuthRequiredSignal as ln, requireAutomationRevision as lt, deleteMcpStoredOAuthCredentials as m, parseOAuthStatePayload as mn, AgentInvocationLimitError as mt, runAgentWithTimeout as n, maybePostAutomatedTurnLimitNotice as nn, getEventAutomation as nt, setExperimentalFeatures as o, shouldPropagateSandboxEgressTrace as on, setEventAutomationStatus as ot, deleteMcpServerSessionId as p, formatProviderLabel as pn, AgentInvocationBusyError as pt, withScheduledAutomationLock as q, startConversationWork as qt, experimental_exports as r, recordFinishedTurnForAutomatedLimit as rn, listDeletedEventAutomationsCreatedBy as rt, executeAgentRun as s, SANDBOX_EGRESS_PROXY_PATH as sn, AutomationConflictError as st, createAgentRunner as t, renderTaskInput as tn, findMatchingEventAutomations as tt, finalizeMcpAuthorization as u, consumeSandboxEgressPermissionDeniedSignal as un, agentBindingSchema as ut, PluginCredentialFailureError as v, formatSlackLink as vn, EVENT_WAIT_MS as vt, unpublishedArtifactHeaders as w, removeReactionFromMessage as wn, appendAndEnqueueExclusiveInboundMessage as wt, resolvePluginOAuthAccount as x, truncateStatusText as xn, eventGuidance as xt, latestProgressStatus as y, normalizeSlackReplyMarkdown as yn, isEventMailboxMetadata as yt, scheduledAutomationRunAttributes as z, hasRunnableConversationWork as zt };