@sentry/junior 0.235.0 → 0.237.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 (73) hide show
  1. package/dist/{agent-hooks-DS7k0ZWY.js → agent-hooks-otHGbhBx.js} +20 -9
  2. package/dist/{agent-runner-BlDI1zV2.js → agent-runner-DMAsnPb9.js} +456 -120
  3. package/dist/api/schema.d.ts +223 -2
  4. package/dist/api/schema.js +5 -4
  5. package/dist/api.d.ts +8 -2
  6. package/dist/api.js +404 -47
  7. package/dist/{app-pGsR__aT.d.ts → app-MEd7wbF0.d.ts} +82 -48
  8. package/dist/app.d.ts +3 -3
  9. package/dist/app.js +162 -119
  10. package/dist/{types-Du-HbEun.js → automation-CrQGQ2MT.js} +306 -34
  11. package/dist/{briefs-C3jhszOz.js → briefs-DDA1ugXk.js} +4 -4
  12. package/dist/{catalog-runtime-B9u_3-GW.js → catalog-runtime-DlXuhrmk.js} +1 -1
  13. package/dist/{checkpoint-DLcJ5mKL.js → checkpoint-BlIIiHG5.js} +16 -9
  14. package/dist/cli/chat.d.ts +1 -1
  15. package/dist/cli/chat.js +14 -14
  16. package/dist/cli/check.js +4 -4
  17. package/dist/cli/main.js +1 -1
  18. package/dist/cli/plugins.d.ts +1 -1
  19. package/dist/cli/plugins.js +4 -4
  20. package/dist/cli/snapshot-create.js +3 -3
  21. package/dist/cli/upgrade.d.ts +1 -1
  22. package/dist/cli/upgrade.js +5 -5
  23. package/dist/{client-BSnNHO0R.js → client-CPMbTmJU.js} +2 -2
  24. package/dist/{config-Bmw4xTPK.js → config-CxpPG6nR.js} +57 -17
  25. package/dist/{conversation-C_aYrISI.js → conversation-9Fxa1Zbq.js} +13 -1
  26. package/dist/{conversation-privacy-BV2dtba2.js → conversation-privacy-Dbkdvozu.js} +1 -1
  27. package/dist/{credential-sync-CukzQJ1x.js → credential-sync-D9yGg3q5.js} +14 -14
  28. package/dist/{executor-B9ksWZCv.js → executor-BNxfDS1V.js} +39 -6
  29. package/dist/{images-CEXcQ0Id.js → images-D6Y3FJDQ.js} +3 -3
  30. package/dist/instrumentation.js +2 -2
  31. package/dist/{job-queue-CY1L2YRn.js → job-queue-Dq5_zt_l.js} +1 -1
  32. package/dist/{logging-F--48Q7Q.js → logging-rB_ngE_R.js} +1 -1
  33. package/dist/nitro.d.ts +2 -2
  34. package/dist/nitro.js +5 -5
  35. package/dist/{oauth-authorization-LasSG3Qc.js → oauth-authorization-5T1S1v_1.js} +1 -1
  36. package/dist/{oauth-callback-server-D07ZzVMs.js → oauth-callback-server-Csw7RssK.js} +2 -2
  37. package/dist/{pending-auth-DrG9Mkje.js → pending-auth-moCA2mTc.js} +1 -1
  38. package/dist/{plugins-BT2l4We3.d.ts → plugins-CjfUP5gJ.d.ts} +1 -0
  39. package/dist/{profile-DZ2DUdd1.js → profile-D6apIG2N.js} +4 -4
  40. package/dist/{prompt-BM_5mAU3.js → prompt-Ctwy6hSI.js} +1 -1
  41. package/dist/queue-B5SnqRln.d.ts +25 -0
  42. package/dist/{registry-_JLY0x7b.js → registry-zfTzTHe6.js} +38 -2
  43. package/dist/{resolve-Cuoj3MML.js → resolve-sJtTzuBO.js} +2 -2
  44. package/dist/{runner-BfelmbMv.js → runner-DkCk8cbc.js} +9 -9
  45. package/dist/{sandbox-egress-signals-D5QUIO7Z.js → sandbox-egress-signals-tSQ8OEcw.js} +1 -1
  46. package/dist/{schema-CrdDxGbx.js → schema-C5bgOpRg.js} +3 -2
  47. package/dist/{skills-DAegjk5Y.js → skills-BVpr_Gnv.js} +3 -3
  48. package/dist/{spawn-DCfV7zGK.js → spawn-CJhmyE4E.js} +2 -2
  49. package/dist/{task-queue-GcuFtzor.js → task-queue-BAiZ7_CF.js} +16 -10
  50. package/dist/{task-runner-B0-P_3aq.js → task-runner-Bh8XONXT.js} +9 -9
  51. package/dist/{thread-state-TezcEhuH.js → thread-state-BnQln4jO.js} +5 -5
  52. package/dist/{turn-failure-response-Drhj_-t4.js → turn-failure-response-Ba7_kItn.js} +8 -8
  53. package/dist/{turn-lifecycle-BpIW3zOx.js → turn-lifecycle-D6CTbkb9.js} +1 -1
  54. package/dist/{turn-session-routing-Dg8GDgyc.js → turn-session-routing-DNevs9H7.js} +1 -1
  55. package/dist/{validation-DAkYeKDT.js → validation-BNPhuAvt.js} +2 -3
  56. package/dist/{version-9CB4Z-J4.js → version-EQ4MWuUJ.js} +1 -1
  57. package/dist/version.js +1 -1
  58. package/dist/{web-authorization-Cu33voNg.js → web-authorization-DDt4FZld.js} +6 -6
  59. package/dist/{web-input-B3k0J7WB.js → web-input-C56ivZuH.js} +86 -102
  60. package/dist/web-message-id-xPI_EFSC.js +239 -0
  61. package/dist/{work-PmkvcY9l.js → work-DJ7hb9Ul.js} +7 -7
  62. package/dist/{worker-COcaq2J6.js → worker-DiiV8Lba.js} +5 -5
  63. package/migrations/0045_conversation_forks.sql +3 -0
  64. package/migrations/0046_automation_versions.sql +71 -0
  65. package/migrations/0047_user_timezone.sql +1 -0
  66. package/migrations/meta/0045_snapshot.json +3503 -0
  67. package/migrations/meta/0046_snapshot.json +3707 -0
  68. package/migrations/meta/0047_snapshot.json +3713 -0
  69. package/migrations/meta/_journal.json +22 -1
  70. package/package.json +4 -4
  71. package/dist/web-message-id-CVVCTWUb.js +0 -464
  72. package/dist/{package-discovery-7a9YqLhE.js → package-discovery-BVvSnQBB.js} +1 -1
  73. package/dist/{plugin-module-BKGOXca2.js → plugin-module-CVvEUSMH.js} +1 -1
@@ -1,27 +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-BSnNHO0R.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-F--48Q7Q.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-CPMbTmJU.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-rB_ngE_R.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-BV2dtba2.js";
6
- import { a as getChatConfig, h as normalizeSlackEmojiName, n as botConfig } from "./config-Bmw4xTPK.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-Dbkdvozu.js";
6
+ import { i as getChatConfig, n as botConfig, o as getSlackBotToken, v as normalizeSlackEmojiName } from "./config-CxpPG6nR.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 { $ as readActorIdentity, $t as getConversationMessageSearchStore, A as getWorkspaceSnapshotBuilder, B as SlackActionError, C as WorkspaceValidationError, D as setWorkspaceSnapshotBuild, E as setWorkspaceSnapshot, G as isConversationScopedChannel, H as getFilePermalink, K as isDmChannel$1, M as workspaceRepoCheckoutPath, N as resolveChannelCapabilities, O as SANDBOX_RUNTIME, Qt as getConversationEventStore, S as updateWorkspace, T as loadSnapshotsForProfile, Ut as saveObjectAnnotations, V as downloadPrivateSlackFile, W as getSlackClient, Wt as createPluginAnnotations, Y as withSlackRetries, _ as deleteWorkspace, _t as getDashboardConversationLink, at as RESOURCE_WATCH_TOOL_SOURCE, b as listWorkspaces, c as getPluginTools, ct as cancelWatch, dt as createWatch, en as getConversationStore, ft as deliverWatch, g as createWorkspace, gt as JUNIOR_THREAD_STATE_TTL_MS, it as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, j as tryWorkspaceRepoCheckoutPath, k as deleteWorkspaceSnapshotBuilders, l as getPluginUserPromptContributions, ln as addAgentTurnUsage, mt as listWatches, n as applyPluginFormatMarkdown, nn as getSqlExecutor, nt as getSlackToolContext, ot as STOP_WATCHING_TOOL_NAME, pn as hasAgentTurnUsage, pt as findMatchingWatches, q as normalizeSlackConversationId, r as createPluginHookRunner, rt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, s as getPluginSystemPromptContributions, st as cancelSubscriptions, tn as getDb, u as getPlugins, ut as createTimerWatch, v as getWorkspace, w as invalidateReadySnapshot, wt as createPluginLogger, xn as sameDestination$1, y as getWorkspaceByName, yn as parseDestination, yt as getDashboardTaskLink, zt as matchSlackAttachments } from "./agent-hooks-DS7k0ZWY.js";
9
+ import { $ as readActorIdentity, $t as getConversationMessageSearchStore, A as getWorkspaceSnapshotBuilder, B as SlackActionError, C as WorkspaceValidationError, Cn as sameDestination$1, D as setWorkspaceSnapshotBuild, E as setWorkspaceSnapshot, G as isConversationScopedChannel, H as getFilePermalink, K as isDmChannel$1, M as workspaceRepoCheckoutPath, N as resolveChannelCapabilities, O as SANDBOX_RUNTIME, Qt as getConversationEventStore, S as updateWorkspace, T as loadSnapshotsForProfile, Ut as saveObjectAnnotations, V as downloadPrivateSlackFile, W as getSlackClient, Wt as createPluginAnnotations, Y as withSlackRetries, _ as deleteWorkspace, _n as saveUserTimezone, _t as getDashboardConversationLink, at as RESOURCE_WATCH_TOOL_SOURCE, b as listWorkspaces, c as getPluginTools, ct as cancelWatch, dt as createWatch, en as getConversationStore, ft as deliverWatch, g as createWorkspace, gn as readUserTimezone, gt as JUNIOR_THREAD_STATE_TTL_MS, it as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, j as tryWorkspaceRepoCheckoutPath, k as deleteWorkspaceSnapshotBuilders, l as getPluginUserPromptContributions, ln as addAgentTurnUsage, mt as listWatches, n as applyPluginFormatMarkdown, nn as getSqlExecutor, nt as getSlackToolContext, ot as STOP_WATCHING_TOOL_NAME, pn as hasAgentTurnUsage, pt as findMatchingWatches, q as normalizeSlackConversationId, r as createPluginHookRunner, rt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, s as getPluginSystemPromptContributions, st as cancelSubscriptions, tn as getDb, u as getPlugins, ut as createTimerWatch, v as getWorkspace, w as invalidateReadySnapshot, wt as createPluginLogger, xn as parseDestination, y as getWorkspaceByName, yt as getDashboardTaskLink, zt as matchSlackAttachments } from "./agent-hooks-otHGbhBx.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-B9ksWZCv.js";
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-C_aYrISI.js";
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-_JLY0x7b.js";
15
- import { n as pluginCatalogRuntime } from "./catalog-runtime-B9u_3-GW.js";
16
- import { a as parseSkillInvocation, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-DAegjk5Y.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-DLcJ5mKL.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-DZ2DUdd1.js";
19
- import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-DrG9Mkje.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-LasSG3Qc.js";
21
- import { r as EVENT_AUTHOR_ID } from "./prompt-BM_5mAU3.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-Cuoj3MML.js";
23
- import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-CY1L2YRn.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";
11
+ import { A as juniorArtifacts, D as juniorConversations, O as juniorIdentities, S as juniorConversationAnnotations, T as juniorAttachments, _ as juniorConversationBriefs, a as juniorSchedulerRuns, f as AGENT_INVOCATION_MAILBOX_STATUSES, l as juniorStats, o as juniorSchedulerTasks, s as juniorAutomationVersions, u as juniorEventAutomations } from "./executor-BNxfDS1V.js";
12
+ import { F as isVisionImageMediaType, G as removedCardSchema, L as briefLinkSchema, R as briefOutcomeStatusSchema, at as sameActorIdentity, it as instructionProvenanceFor, nt as contextProvenance, q as KNOWN_CONVERSATION_EVENT_TYPES, rt as instructionActors, z as conversationBriefSchema } from "./conversation-9Fxa1Zbq.js";
13
+ import { a as listReferenceFiles, c as soulPathCandidates, l as worldPathCandidates } from "./package-discovery-BVvSnQBB.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-zfTzTHe6.js";
15
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-DlXuhrmk.js";
16
+ import { a as parseSkillInvocation, i as parseSkillFile, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-BVpr_Gnv.js";
17
+ import { C as isToolResultError, D as stripRuntimeTurnContext, E as retainRuntimeTurnContext, H as recordAuthorizationRequested, I as loadTurnRoute, K as recordToolExecutionStarted, L as openConversationProjection, M as loadConnectedMcpProviders, N as loadConversationProjection, O as trimTrailingAssistantMessages, R as recordAgentsInstructionsUpdated, S as isContinuablePiBoundary, T as normalizeToolNameFromResult, U as recordGuardianActionReviewed, W as recordMcpProviderConnected, _ as getTerminalAssistantMessages, _t as historyItemFromPiMessage, d as TurnSliceLimitExceededError, f as assertTurnToolCallLimit, g as getPiMessageRole, gt as getAgentContextInputLimitTokens, h as extractAssistantText, ht as getAgentContextCompactionTriggerTokens, k as TURN_CONTEXT_TAG, m as isTurnExecutionLimitExceededError, mt as estimateTextTokens, n as loadTurnCheckpoint, nt as resolveTaskTitle, q as recordTurnRoute, r as saveTurnCheckpoint, t as continuableMessages, tt as fallbackShortTitle, v as getUserMessageInstructionText, vt as piMessageFromHistoryItem, w as isToolResultMessage, x as isAssistantMessage, y as hasRuntimeTurnContext, z as recordAttachmentsDelivered } from "./checkpoint-BlIIiHG5.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-D6apIG2N.js";
19
+ import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-moCA2mTc.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-5T1S1v_1.js";
21
+ import { r as EVENT_AUTHOR_ID } from "./prompt-Ctwy6hSI.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-sJtTzuBO.js";
23
+ import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-Dq5_zt_l.js";
24
+ import { A as eventAutomationSchema, D as scheduledRunSchema, E as scheduledAutomationSchema, M as compileScheduleIntent, N as isValidTimeZone$1, O as automationInstructionToolSchema, P as scheduleIntentSchema, R as getZonedDateTimeParts, S as automationVersionSchema, T as SCHEDULED_AUTOMATION_SYSTEM_ACTOR, j as ScheduleIntentError, k as automationTitleSchema, z as taskOutcomeInputSchema } from "./automation-CrQGQ2MT.js";
25
25
  import { n as privateTraceResultAttributes } from "./private-trace-result-BLvBjy_e.js";
26
26
  import { streamSimple } from "@earendil-works/pi-ai/compat";
27
27
  import { createGatewayProvider } from "@ai-sdk/gateway";
@@ -397,6 +397,15 @@ async function collectFiles(params) {
397
397
  //#region src/chat/repository-instructions.ts
398
398
  const AGENTS_FILENAME = "AGENTS.md";
399
399
  const MAX_REPOSITORY_INSTRUCTIONS_BYTES = 32768;
400
+ /** Repository skill directories, in priority order, relative to the Git root. */
401
+ const REPOSITORY_SKILL_ROOTS = [".agents/skills", ".claude/skills"];
402
+ const REPOSITORY_SKILLS_HEADER = [
403
+ "## Repository skills",
404
+ "",
405
+ "These skills come from the repository, not from `<available-skills>`. `loadSkill` cannot load them.",
406
+ "Before work that matches a skill description, read its `SKILL.md` with `readFile` and follow it.",
407
+ "Resolve relative paths in a skill against the skill directory."
408
+ ].join("\n");
400
409
  const AGENTS_REPLACEMENT_NOTICE = "These AGENTS.md instructions replace all previously provided AGENTS.md instructions.";
401
410
  const AGENTS_REMOVAL_NOTICE = "The previously provided AGENTS.md instructions no longer apply.";
402
411
  async function pathExists(fs, target) {
@@ -446,20 +455,53 @@ async function readInstructionFile(fs, filePath) {
446
455
  throw error;
447
456
  }
448
457
  }
449
- /** Resolve the effective root-to-cwd AGENTS.md bundle for one selected directory. */
450
- async function resolveRepositoryInstructions(args) {
451
- const gitRoot = await findGitRoot(args.fs, args.cwd);
452
- if (!gitRoot) return;
458
+ async function readOptionalDirectory(fs, directory) {
459
+ try {
460
+ return await fs.readdir(directory);
461
+ } catch (error) {
462
+ if (isMissingPathError(error)) return [];
463
+ throw error;
464
+ }
465
+ }
466
+ /** Read model-invocable skills from the repository skill directories. */
467
+ async function readRepositorySkills(fs, gitRoot) {
468
+ const roots = REPOSITORY_SKILL_ROOTS.map((root) => path.posix.join(gitRoot, root));
469
+ const listings = await Promise.all(roots.map(async (root) => await readOptionalDirectory(fs, root)));
470
+ const candidates = /* @__PURE__ */ new Map();
471
+ listings.forEach((entries, index) => {
472
+ for (const entry of [...entries].sort()) if (!candidates.has(entry)) candidates.set(entry, path.posix.join(roots[index], entry));
473
+ });
474
+ return (await Promise.all([...candidates].map(async ([name, skillDirectory]) => {
475
+ if (!await directoryExists(fs, skillDirectory)) return;
476
+ const filePath = path.posix.join(skillDirectory, "SKILL.md");
477
+ const raw = await readInstructionFile(fs, filePath);
478
+ const parsed = raw ? parseSkillFile(raw, name) : void 0;
479
+ if (!parsed?.ok || parsed.skill.disableModelInvocation) return;
480
+ return {
481
+ description: parsed.skill.description.replace(/\s+/g, " ").trim(),
482
+ name,
483
+ path: filePath
484
+ };
485
+ }))).filter((skill) => Boolean(skill)).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
486
+ }
487
+ function sourceBytes(sources) {
488
+ return sources.reduce((total, source) => total + Buffer.byteLength(source.content, "utf8"), 0);
489
+ }
490
+ function skillListBytes(skills) {
491
+ return skills.reduce((total, skill) => total + repositorySkillBytes(skill), 0);
492
+ }
493
+ /** Read root-to-cwd AGENTS.md files within the byte budget. */
494
+ async function readAgentsSources(args) {
453
495
  const directories = [];
454
496
  let current = args.cwd;
455
497
  for (;;) {
456
498
  directories.push(current);
457
- if (current === gitRoot) break;
499
+ if (current === args.gitRoot) break;
458
500
  current = path.posix.dirname(current);
459
501
  }
460
502
  directories.reverse();
461
503
  const sources = [];
462
- let remaining = Math.max(0, args.maxBytes ?? MAX_REPOSITORY_INSTRUCTIONS_BYTES);
504
+ let remaining = Math.max(0, args.maxBytes);
463
505
  for (const directory of directories) {
464
506
  if (remaining <= 0) break;
465
507
  const filePath = path.posix.join(directory, AGENTS_FILENAME);
@@ -473,34 +515,69 @@ async function resolveRepositoryInstructions(args) {
473
515
  });
474
516
  remaining -= Buffer.byteLength(bounded, "utf8");
475
517
  }
476
- if (sources.length === 0) return;
477
- const text = formatInstructionSources(sources);
478
- const fingerprint = createHash("sha256").update(JSON.stringify({
479
- directory: args.cwd,
480
- sources
481
- })).digest("hex");
518
+ return sources;
519
+ }
520
+ /** Read repository skills that fit the byte budget, keeping each entry whole. */
521
+ async function readRepositorySkillsWithinBudget(args) {
522
+ const skills = [];
523
+ let remaining = args.maxBytes;
524
+ if (remaining <= 0) return skills;
525
+ for (const skill of await readRepositorySkills(args.fs, args.gitRoot)) {
526
+ const bytes = repositorySkillBytes(skill);
527
+ if (bytes > remaining) break;
528
+ skills.push(skill);
529
+ remaining -= bytes;
530
+ }
531
+ return skills;
532
+ }
533
+ function buildRepositoryInstructions(directory, sources, skills) {
534
+ if (sources.length === 0 && skills.length === 0) return;
482
535
  return {
483
- directory: args.cwd,
484
- fingerprint,
536
+ directory,
537
+ fingerprint: createHash("sha256").update(JSON.stringify({
538
+ directory,
539
+ sources,
540
+ ...skills.length > 0 ? { skills } : void 0
541
+ })).digest("hex"),
542
+ ...skills.length > 0 ? { skills } : void 0,
485
543
  sources,
486
- text
544
+ text: formatRepositoryInstructions(sources, skills)
487
545
  };
488
546
  }
489
547
  function formatInstructionSources(sources) {
490
548
  if (sources.length === 1) return sources[0].content;
491
549
  return sources.map((source) => `## ${path.posix.dirname(source.path)}\n\n${source.content}`).join("\n\n");
492
550
  }
551
+ function formatRepositorySkill(skill) {
552
+ return `- \`${skill.name}\` (\`${skill.path}\`): ${skill.description}`;
553
+ }
554
+ function repositorySkillBytes(skill) {
555
+ return Buffer.byteLength(formatRepositorySkill(skill), "utf8") + 1;
556
+ }
557
+ function formatRepositoryInstructions(sources, skills) {
558
+ const sections = [];
559
+ if (sources.length > 0) sections.push(formatInstructionSources(sources));
560
+ if (skills.length > 0) sections.push([
561
+ REPOSITORY_SKILLS_HEADER,
562
+ "",
563
+ ...skills.map(formatRepositorySkill)
564
+ ].join("\n"));
565
+ return sections.join("\n\n");
566
+ }
493
567
  /** Combine AGENTS.md bundles from one or more repository directories. */
494
568
  function mergeRepositoryInstructions(bundles) {
495
569
  if (bundles.length === 0) return;
496
570
  if (bundles.length === 1) return bundles[0];
497
571
  const sources = bundles.flatMap((bundle) => bundle.sources);
498
- const text = formatInstructionSources(sources);
572
+ const skills = bundles.flatMap((bundle) => bundle.skills ?? []);
573
+ const text = formatRepositoryInstructions(sources, skills);
499
574
  return {
500
575
  fingerprint: createHash("sha256").update(JSON.stringify({
501
576
  directories: bundles.map((bundle) => bundle.directory ?? null),
502
- sources
577
+ sources,
578
+ ...skills.length > 0 ? { skills } : void 0
503
579
  })).digest("hex"),
580
+ ...skills.length > 0 ? { skills } : void 0,
504
581
  sources,
505
582
  text
506
583
  };
@@ -509,17 +586,33 @@ function mergeRepositoryInstructions(bundles) {
509
586
  async function resolveRepositoryInstructionsForDirectories(args) {
510
587
  const uniqueDirectories = [...new Set(args.directories.filter((directory) => directory === SANDBOX_WORKSPACE_ROOT || directory.startsWith(`${SANDBOX_WORKSPACE_ROOT}/`)))].sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
511
588
  let remaining = MAX_REPOSITORY_INSTRUCTIONS_BYTES;
512
- const bundles = [];
589
+ const repositories = [];
513
590
  for (const directory of uniqueDirectories) {
514
- if (remaining <= 0) break;
515
- const instructions = await resolveRepositoryInstructions({
591
+ const gitRoot = await findGitRoot(args.fs, directory);
592
+ if (!gitRoot) continue;
593
+ const sources = await readAgentsSources({
516
594
  cwd: directory,
517
595
  fs: args.fs,
596
+ gitRoot,
597
+ maxBytes: remaining
598
+ });
599
+ remaining -= sourceBytes(sources);
600
+ repositories.push({
601
+ directory,
602
+ gitRoot,
603
+ sources
604
+ });
605
+ }
606
+ const bundles = [];
607
+ for (const repository of repositories) {
608
+ const skills = await readRepositorySkillsWithinBudget({
609
+ fs: args.fs,
610
+ gitRoot: repository.gitRoot,
518
611
  maxBytes: remaining
519
612
  });
520
- if (!instructions) continue;
521
- bundles.push(instructions);
522
- remaining -= instructions.sources.reduce((total, source) => total + Buffer.byteLength(source.content, "utf8"), 0);
613
+ remaining -= skillListBytes(skills);
614
+ const bundle = buildRepositoryInstructions(repository.directory, repository.sources, skills);
615
+ if (bundle) bundles.push(bundle);
523
616
  }
524
617
  return mergeRepositoryInstructions(bundles);
525
618
  }
@@ -3095,6 +3188,10 @@ function normalizeSlackStatusText(text) {
3095
3188
  if (!trimmed) return "";
3096
3189
  return truncateStatusText(trimmed.replace(/(?:\.\s*)+$/, "").trim());
3097
3190
  }
3191
+ /** Render a Slack user mention, which Slack shows as the person's name. */
3192
+ function slackMention(userId) {
3193
+ return `<@${userId}>`;
3194
+ }
3098
3195
  //#endregion
3099
3196
  //#region src/chat/slack/oauth-authorization-message.ts
3100
3197
  /** Present private OAuth authorization with a clear action and text fallback. */
@@ -3984,12 +4081,14 @@ function renderTaskInput(args) {
3984
4081
  const instructions = args.instructions.trim();
3985
4082
  if (!instructions) throw new Error("Task instructions are required");
3986
4083
  const about = args.about?.trim();
4084
+ const creator = args.creator?.trim();
3987
4085
  const lines = [
3988
4086
  "[task]",
3989
4087
  "",
3990
4088
  "This is a task, not a message from a person.",
3991
4089
  "",
3992
4090
  ...about ? [`About: ${oneLine(about)}`] : [],
4091
+ ...creator ? [`Created by: ${oneLine(creator)}. Where the instructions say "me" or "my", write this mention.`] : [],
3993
4092
  `Instructions: ${instructions}`
3994
4093
  ];
3995
4094
  const guidance = args.guidance?.trim();
@@ -8742,7 +8841,7 @@ var PluginMcpClient = class {
8742
8841
  return [...this.listedTools];
8743
8842
  });
8744
8843
  }
8745
- async callTool(name, args) {
8844
+ async callTool(name, args, signal) {
8746
8845
  return await this.withSessionRecovery(async () => {
8747
8846
  const client = await this.getClient();
8748
8847
  const mcp = this.plugin.manifest.mcp;
@@ -8759,7 +8858,7 @@ var PluginMcpClient = class {
8759
8858
  const result = await this.wrapAuth(() => client.callTool({
8760
8859
  name,
8761
8860
  arguments: args ?? {}
8762
- }), "call_tool");
8861
+ }, void 0, signal ? { signal } : void 0), "call_tool");
8763
8862
  await this.syncTransportSessionId();
8764
8863
  return result;
8765
8864
  });
@@ -9143,7 +9242,7 @@ var McpToolManager = class {
9143
9242
  const argumentAttribute = serializeMcpPayload(resolvedArgs, conversationPrivacy, { privateMetadata: true });
9144
9243
  return await withSpan(`execute_tool ${managedToolName}`, "gen_ai.execute_tool", {}, async () => {
9145
9244
  try {
9146
- const result = await client.callTool(tool.name, resolvedArgs);
9245
+ const result = await client.callTool(tool.name, resolvedArgs, options?.signal);
9147
9246
  if ("isError" in result && result.isError) throw new McpToolError(extractMcpErrorMessage(result));
9148
9247
  const resultAttribute = serializeMcpPayload(result, conversationPrivacy, { privateMetadata: true });
9149
9248
  if (resultAttribute) setSpanAttributes({ "gen_ai.tool.call.result": resultAttribute });
@@ -9503,6 +9602,7 @@ function createCallMcpToolTool(mcpToolManager) {
9503
9602
  }
9504
9603
  const result = await mcpTool.execute(resolveMcpArguments(input), {
9505
9604
  conversationPrivacy: options?.conversationPrivacy ?? "private",
9605
+ ...options?.signal ? { signal: options.signal } : void 0,
9506
9606
  ...options?.toolCallId ? { toolCallId: options.toolCallId } : void 0
9507
9607
  });
9508
9608
  return {
@@ -10262,6 +10362,7 @@ var AutomationConflictError = class extends ToolInputError {
10262
10362
  this.name = "AutomationConflictError";
10263
10363
  }
10264
10364
  };
10365
+ /** Sort object keys so equal values produce equal JSON. */
10265
10366
  function canonicalJson$1(value) {
10266
10367
  if (Array.isArray(value)) return value.map(canonicalJson$1);
10267
10368
  if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => [key, canonicalJson$1(child)]));
@@ -10276,6 +10377,70 @@ function requireAutomationRevision(task, revision) {
10276
10377
  if (!task || automationRevision(task) !== revision) throw new AutomationConflictError();
10277
10378
  }
10278
10379
  //#endregion
10380
+ //#region src/chat/automations/versions.ts
10381
+ /** Automation versions keep each saved definition so people can see how it changed. */
10382
+ /** Return the versioned part of an Automation. Lifecycle and run state are excluded. */
10383
+ function automationDefinition(task) {
10384
+ const common = {
10385
+ title: task.title?.trim() || null,
10386
+ instruction: task.task.text,
10387
+ credentialMode: task.credentialMode,
10388
+ destination: task.destination,
10389
+ outcomes: task.outcomes
10390
+ };
10391
+ return "schedule" in task ? {
10392
+ ...common,
10393
+ schedule: task.schedule
10394
+ } : {
10395
+ ...common,
10396
+ trigger: task.trigger
10397
+ };
10398
+ }
10399
+ /** Compare definition values after key sorting. */
10400
+ function sameDefinitionValue(left, right) {
10401
+ return JSON.stringify(canonicalJson$1(left)) === JSON.stringify(canonicalJson$1(right));
10402
+ }
10403
+ /**
10404
+ * Save a version when the definition changed. Call this in the same
10405
+ * transaction and lock as the Automation write. Without `current`, the
10406
+ * Automation is new, so the creator saves version 1.
10407
+ */
10408
+ async function recordAutomationVersion(db, kind, task, current, editedBy) {
10409
+ const definition = automationDefinition(task);
10410
+ if (current && sameDefinitionValue(automationDefinition(current), definition)) return;
10411
+ await db.insert(juniorAutomationVersions).values({
10412
+ kind,
10413
+ automationId: task.id,
10414
+ version: sql`(
10415
+ SELECT coalesce(max(${juniorAutomationVersions.version}), 0) + 1
10416
+ FROM ${juniorAutomationVersions}
10417
+ WHERE ${juniorAutomationVersions.kind} = ${kind}
10418
+ AND ${juniorAutomationVersions.automationId} = ${task.id}
10419
+ )`,
10420
+ createdAtMs: Date.now(),
10421
+ editedBy: editedBy ?? (current ? null : task.createdBy),
10422
+ definition
10423
+ });
10424
+ }
10425
+ function parseVersionRow(kind, row) {
10426
+ return automationVersionSchema.parse({
10427
+ kind,
10428
+ version: row.version,
10429
+ createdAt: new Date(row.createdAtMs).toISOString(),
10430
+ editedBy: row.editedBy,
10431
+ definition: row.definition
10432
+ });
10433
+ }
10434
+ /** Read one saved definition. */
10435
+ async function readAutomationVersion(db, kind, automationId, version) {
10436
+ const [row] = await db.select().from(juniorAutomationVersions).where(and(eq(juniorAutomationVersions.kind, kind), eq(juniorAutomationVersions.automationId, automationId), eq(juniorAutomationVersions.version, version))).limit(1);
10437
+ return row ? parseVersionRow(kind, row) : void 0;
10438
+ }
10439
+ /** Read saved definitions, newest first. */
10440
+ async function listAutomationVersions(db, kind, automationId, limit) {
10441
+ return (await db.select().from(juniorAutomationVersions).where(and(eq(juniorAutomationVersions.kind, kind), eq(juniorAutomationVersions.automationId, automationId))).orderBy(desc(juniorAutomationVersions.version)).limit(limit)).map((row) => parseVersionRow(kind, row));
10442
+ }
10443
+ //#endregion
10279
10444
  //#region src/chat/event-automations/store.ts
10280
10445
  const retainedEventAutomationSchema = eventAutomationSchema.extend({
10281
10446
  destination: slackDestinationSchema,
@@ -10327,61 +10492,84 @@ async function getEventAutomation(db, id) {
10327
10492
  async function createEventAutomation(db, task) {
10328
10493
  const parsed = eventAutomationSchema.parse(eventAutomationJsonPayload(task));
10329
10494
  const title = task.title?.trim() || null;
10330
- await db.insert(juniorEventAutomations).values({
10331
- id: parsed.id,
10332
- teamId: parsed.destination.teamId,
10333
- namespace: parsed.trigger.namespace,
10334
- identifier: parsed.trigger.identifier,
10335
- createdAtMs: parsed.createdAtMs,
10336
- status: "active",
10337
- title,
10338
- task: parsed
10339
- }).onConflictDoNothing();
10340
- const existing = await getEventAutomation(db, parsed.id);
10341
- if (!existing) return {
10342
- ...parsed,
10343
- status: "active",
10344
- ...title ? { title } : void 0
10345
- };
10346
- if (existing.status !== "deleted") return existing;
10347
- const rows = await db.update(juniorEventAutomations).set({
10348
- teamId: parsed.destination.teamId,
10349
- namespace: parsed.trigger.namespace,
10350
- identifier: parsed.trigger.identifier,
10351
- status: "active",
10352
- title,
10353
- task: parsed
10354
- }).where(and(eq(juniorEventAutomations.id, parsed.id), eq(juniorEventAutomations.status, "deleted"))).returning({
10355
- status: juniorEventAutomations.status,
10356
- task: juniorEventAutomations.task,
10357
- title: juniorEventAutomations.title
10495
+ return db.transaction(async (tx) => {
10496
+ const inserted = await tx.insert(juniorEventAutomations).values({
10497
+ id: parsed.id,
10498
+ teamId: parsed.destination.teamId,
10499
+ namespace: parsed.trigger.namespace,
10500
+ identifier: parsed.trigger.identifier,
10501
+ createdAtMs: parsed.createdAtMs,
10502
+ status: "active",
10503
+ title,
10504
+ task: parsed
10505
+ }).onConflictDoNothing().returning({
10506
+ status: juniorEventAutomations.status,
10507
+ task: juniorEventAutomations.task,
10508
+ title: juniorEventAutomations.title
10509
+ });
10510
+ if (inserted[0]) {
10511
+ const created = parseEventAutomationRow(inserted[0]);
10512
+ await recordAutomationVersion(tx, "event", created, void 0);
10513
+ return created;
10514
+ }
10515
+ const existing = await getEventAutomation(tx, parsed.id);
10516
+ if (!existing) return {
10517
+ ...parsed,
10518
+ status: "active",
10519
+ ...title ? { title } : void 0
10520
+ };
10521
+ if (existing.status !== "deleted") return existing;
10522
+ const rows = await tx.update(juniorEventAutomations).set({
10523
+ teamId: parsed.destination.teamId,
10524
+ namespace: parsed.trigger.namespace,
10525
+ identifier: parsed.trigger.identifier,
10526
+ status: "active",
10527
+ title,
10528
+ task: parsed
10529
+ }).where(and(eq(juniorEventAutomations.id, parsed.id), eq(juniorEventAutomations.status, "deleted"))).returning({
10530
+ status: juniorEventAutomations.status,
10531
+ task: juniorEventAutomations.task,
10532
+ title: juniorEventAutomations.title
10533
+ });
10534
+ if (!rows[0]) return await getEventAutomation(tx, parsed.id) ?? {
10535
+ ...parsed,
10536
+ status: "active",
10537
+ ...title ? { title } : void 0
10538
+ };
10539
+ const revived = parseEventAutomationRow(rows[0]);
10540
+ await recordAutomationVersion(tx, "event", revived, void 0);
10541
+ return revived;
10358
10542
  });
10359
- return rows[0] ? parseEventAutomationRow(rows[0]) : await getEventAutomation(db, parsed.id) ?? {
10360
- ...parsed,
10361
- status: "active",
10362
- ...title ? { title } : void 0
10363
- };
10364
10543
  }
10365
- /** Replace an existing non-deleted event automation. */
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
- });
10544
+ /**
10545
+ * Replace an existing non-deleted event automation under a row lock.
10546
+ * Pass `editedBy` when a person changes the definition so its version names them.
10547
+ */
10548
+ async function saveEventAutomation(db, task, expectedRevision, editedBy) {
10372
10549
  const parsed = eventAutomationSchema.parse(eventAutomationJsonPayload(task));
10373
10550
  const title = task.title?.trim() || null;
10374
- const rows = await db.update(juniorEventAutomations).set({
10375
- namespace: parsed.trigger.namespace,
10376
- identifier: parsed.trigger.identifier,
10377
- title,
10378
- task: parsed
10379
- }).where(and(eq(juniorEventAutomations.id, parsed.id), activeEventAutomationWhere())).returning({
10380
- status: juniorEventAutomations.status,
10381
- task: juniorEventAutomations.task,
10382
- title: juniorEventAutomations.title
10551
+ return db.transaction(async (tx) => {
10552
+ const rows = await tx.select({
10553
+ status: juniorEventAutomations.status,
10554
+ task: juniorEventAutomations.task,
10555
+ title: juniorEventAutomations.title
10556
+ }).from(juniorEventAutomations).where(eq(juniorEventAutomations.id, parsed.id)).for("update");
10557
+ const current = rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10558
+ if (expectedRevision !== void 0) requireAutomationRevision(current, expectedRevision);
10559
+ if (!current || current.status === "deleted") return void 0;
10560
+ const saved = parseEventAutomationRow((await tx.update(juniorEventAutomations).set({
10561
+ namespace: parsed.trigger.namespace,
10562
+ identifier: parsed.trigger.identifier,
10563
+ title,
10564
+ task: parsed
10565
+ }).where(eq(juniorEventAutomations.id, parsed.id)).returning({
10566
+ status: juniorEventAutomations.status,
10567
+ task: juniorEventAutomations.task,
10568
+ title: juniorEventAutomations.title
10569
+ }))[0]);
10570
+ await recordAutomationVersion(tx, "event", saved, current, editedBy);
10571
+ return saved;
10383
10572
  });
10384
- return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10385
10573
  }
10386
10574
  /** Mark one existing event automation deleted while retaining the row for history. */
10387
10575
  async function deleteEventAutomation(db, id) {
@@ -10697,7 +10885,7 @@ function createEventAutomationTool(context, catalog) {
10697
10885
  executionMode: "sequential",
10698
10886
  description: "Create a durable event automation in the active Slack channel or DM, never a thread. It executes the supplied instruction for every matching event. Use for whenever-this-happens-do-X automation; ordinary watch, notify, or tell-me-when requests use watchEvents instead. The automation may use the creator's connected credentials. Prefer a subscribable tool result when available.",
10699
10887
  inputSchema: z.object({
10700
- instruction: z.string().trim().min(1).max(4e3),
10888
+ instruction: automationInstructionToolSchema,
10701
10889
  title: z.string().trim().min(1).max(60).nullable().describe("Optional short display title. Omit or use null to generate one from the task instruction.").optional(),
10702
10890
  trigger,
10703
10891
  outcomes: z.array(taskOutcomeInputSchema).max(5).describe("Successful work is silent by default. Omit this field or use an empty list when the Automation should act through tools without a status message. Add send_message only when the user asks for a notification, post, digest, summary, or other visible result.").optional(),
@@ -10908,7 +11096,7 @@ function createUpdateEventAutomationTool(context, catalog) {
10908
11096
  inputSchema: z.object({
10909
11097
  automationId: z.string().min(1),
10910
11098
  title: automationTitleSchema.optional(),
10911
- instruction: automationInstructionSchema.nullable().optional(),
11099
+ instruction: automationInstructionToolSchema.nullable().optional(),
10912
11100
  trigger: registeredEventAutomationTriggerSchema(catalog).nullable().optional(),
10913
11101
  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(),
10914
11102
  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()
@@ -10936,7 +11124,11 @@ function createUpdateEventAutomationTool(context, catalog) {
10936
11124
  outcomes: input.outcomes ?? void 0,
10937
11125
  credentialMode: input.credentialMode ?? void 0
10938
11126
  }, isCreator, catalog);
10939
- const saved = await saveEventAutomation(getDb(), next, automationRevision(current));
11127
+ const saved = await saveEventAutomation(getDb(), next, automationRevision(current), {
11128
+ slackUserId: actor.userId,
11129
+ ...actor.fullName ? { fullName: actor.fullName } : void 0,
11130
+ ...actor.userName ? { userName: actor.userName } : void 0
11131
+ });
10940
11132
  if (!saved) throw new ToolInputError("Event automation was not found.");
10941
11133
  return eventAutomationToolResult(context.conversationId, saved, catalog, actor.userId);
10942
11134
  }
@@ -11090,10 +11282,11 @@ async function listScheduledAutomations(db) {
11090
11282
  async function listScheduledAutomationsForTeam(db, teamId) {
11091
11283
  return await readListedScheduledAutomations(db, teamId);
11092
11284
  }
11093
- async function writeScheduledAutomation(db, task, current) {
11285
+ async function writeScheduledAutomation(db, task, current, editedBy) {
11094
11286
  if (current?.status === "blocked" && task.status === "active" && typeof task.nextRunAtMs === "number" && Number.isFinite(task.nextRunAtMs)) await db.delete(juniorSchedulerRuns).where(and(eq(juniorSchedulerRuns.id, scheduledRunId(task.id, task.nextRunAtMs)), eq(juniorSchedulerRuns.status, "blocked")));
11095
11287
  if (task.status === "deleted" && current?.status !== "deleted") await skipPendingRunsForDeletedTask(db, task);
11096
11288
  await upsertScheduledAutomation(db, task);
11289
+ await recordAutomationVersion(db, "scheduled", task, current, editedBy);
11097
11290
  }
11098
11291
  async function skipPendingRunsForDeletedTask(db, task) {
11099
11292
  const errorMessage = `Scheduled automation ${task.id} was deleted before the run started.`;
@@ -11123,13 +11316,16 @@ async function createScheduledAutomation(db, task) {
11123
11316
  return next;
11124
11317
  });
11125
11318
  }
11126
- /** Save a scheduled automation and clear its blocked occurrence on reactivation. */
11127
- async function saveScheduledAutomation(db, task, expectedRevision) {
11319
+ /**
11320
+ * Save a scheduled automation and clear its blocked occurrence on reactivation.
11321
+ * Pass `editedBy` when a person changes the definition so its version names them.
11322
+ */
11323
+ async function saveScheduledAutomation(db, task, expectedRevision, editedBy) {
11128
11324
  const next = requireStoredTask(task);
11129
11325
  await withScheduledAutomationLock(db, task.id, async (tx) => {
11130
11326
  const current = await readScheduledAutomation(tx, task.id);
11131
11327
  if (expectedRevision !== void 0) requireAutomationRevision(current, expectedRevision);
11132
- await writeScheduledAutomation(tx, next, current);
11328
+ await writeScheduledAutomation(tx, next, current, editedBy);
11133
11329
  });
11134
11330
  return next;
11135
11331
  }
@@ -11174,6 +11370,76 @@ function logScheduledAutomationRunSkipped(task, run, extras = {}) {
11174
11370
  logInfo("scheduled_automation.run.skipped", scheduledAutomationRunAttributes(task, run, extras));
11175
11371
  }
11176
11372
  //#endregion
11373
+ //#region src/chat/slack/user.ts
11374
+ const slackUserInfoSchema = z.object({
11375
+ ok: z.literal(true),
11376
+ user: z.object({
11377
+ name: z.string().nullish(),
11378
+ tz: z.string().nullish(),
11379
+ profile: z.object({
11380
+ email: z.string().nullish(),
11381
+ real_name: z.string().nullish()
11382
+ }).optional()
11383
+ })
11384
+ });
11385
+ const USER_CACHE_TTL_MS = 3e5;
11386
+ const userCache = /* @__PURE__ */ new Map();
11387
+ function userCacheKey(teamId, userId) {
11388
+ return `${teamId}:${userId}`;
11389
+ }
11390
+ function readFromCache(teamId, userId) {
11391
+ const hit = userCache.get(userCacheKey(teamId, userId));
11392
+ if (!hit) return null;
11393
+ if (hit.expiresAt < Date.now()) {
11394
+ userCache.delete(userCacheKey(teamId, userId));
11395
+ return null;
11396
+ }
11397
+ return hit.value;
11398
+ }
11399
+ function writeToCache(teamId, userId, value) {
11400
+ userCache.set(userCacheKey(teamId, userId), {
11401
+ value,
11402
+ expiresAt: Date.now() + USER_CACHE_TTL_MS
11403
+ });
11404
+ }
11405
+ /** Fetch Slack user profile info with in-memory TTL cache to avoid repeated API calls. */
11406
+ async function lookupSlackUser(teamId, userId) {
11407
+ if (!teamId || !userId) return null;
11408
+ const cached = readFromCache(teamId, userId);
11409
+ if (cached) return cached;
11410
+ const token = getSlackBotToken();
11411
+ if (!token) return null;
11412
+ try {
11413
+ const response = await fetch(`https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`, { headers: { authorization: `Bearer ${token}` } });
11414
+ if (!response.ok) {
11415
+ logWarn("slack.user.lookup.failed", {
11416
+ "enduser.id": userId,
11417
+ "app.slack.team_id": teamId,
11418
+ "http.response.status_code": response.status
11419
+ });
11420
+ return null;
11421
+ }
11422
+ const parsed = slackUserInfoSchema.safeParse(await response.json());
11423
+ if (!parsed.success) return null;
11424
+ const payload = parsed.data;
11425
+ const result = {
11426
+ userName: payload.user.name?.trim() || void 0,
11427
+ fullName: payload.user.profile?.real_name?.trim() || void 0,
11428
+ email: payload.user.profile?.email?.trim() || void 0,
11429
+ timezone: payload.user.tz?.trim() || void 0
11430
+ };
11431
+ writeToCache(teamId, userId, result);
11432
+ return result;
11433
+ } catch (error) {
11434
+ logWarn("slack.user.lookup.failed", {
11435
+ "enduser.id": userId,
11436
+ "app.slack.team_id": teamId,
11437
+ "exception.message": error instanceof Error ? error.message : String(error)
11438
+ });
11439
+ return null;
11440
+ }
11441
+ }
11442
+ //#endregion
11177
11443
  //#region src/chat/scheduled-automations/identity.ts
11178
11444
  const SLACK_USER_ID_PATTERN = /^[UW][A-Z0-9]{5,}$/;
11179
11445
  function clean(value) {
@@ -11425,6 +11691,19 @@ function normalizeStatus(value) {
11425
11691
  function getDefaultScheduleTimezone() {
11426
11692
  return process.env.JUNIOR_TIMEZONE?.trim() || DEFAULT_SCHEDULE_TIMEZONE;
11427
11693
  }
11694
+ /**
11695
+ * Pick the timezone for a new schedule when the user names none: the
11696
+ * creator's Slack profile, then the saved user timezone, then the install
11697
+ * default. A valid Slack timezone is saved on the linked user.
11698
+ */
11699
+ async function resolveCreatorScheduleTimezone(args) {
11700
+ const timezone = (await lookupSlackUser(args.teamId, args.slackUserId))?.timezone;
11701
+ if (timezone && isValidTimeZone$1(timezone)) {
11702
+ if (args.userId) await saveUserTimezone(args.db, args.userId, timezone, args.nowMs);
11703
+ return timezone;
11704
+ }
11705
+ return (args.userId ? await readUserTimezone(args.db, args.userId) : void 0) ?? getDefaultScheduleTimezone();
11706
+ }
11428
11707
  //#endregion
11429
11708
  //#region src/chat/scheduled-automations/tools/create.ts
11430
11709
  /** Create a tool that stores a scheduled automation for the active Slack context. */
@@ -11440,7 +11719,7 @@ function createSlackScheduleCreateAutomationTool(context) {
11440
11719
  description: "Create a one-time or recurring Junior task in the active Slack channel. Store the requested future work; do not perform it or check its service access now unless the user also asks for that.",
11441
11720
  executionMode: "sequential",
11442
11721
  inputSchema: z.object({
11443
- instruction: z.string().min(1).max(4e3).describe("Work to perform when the task runs. Preserve the user's scope, targets, and constraints. Do not add permissions or side effects the user did not request."),
11722
+ instruction: automationInstructionToolSchema,
11444
11723
  title: z.string().trim().min(1).max(60).nullable().describe("Optional short display title. Omit or use null to generate one from the task instruction.").optional(),
11445
11724
  schedule: scheduleIntentSchema.describe("When the task runs. The scheduler computes the exact next run from this intent and the server clock."),
11446
11725
  outcomes: z.array(taskOutcomeInputSchema).max(5).describe("Successful work is silent by default. Omit this field or use an empty list when the Automation should act through tools without a status message. Add send_message only when the user asks for a reminder, post, digest, summary, or other visible result.").optional(),
@@ -11467,13 +11746,21 @@ function createSlackScheduleCreateAutomationTool(context) {
11467
11746
  if (!sameDestination(existing, destination) || existing.createdBy.slackUserId !== actor.slackUserId) throwToolInputError("Scheduled automation operation identity is invalid.");
11468
11747
  return scheduleAutomationToolResult(context.conversationId, existing, actor.slackUserId);
11469
11748
  }
11470
- const identity = (await context.users.resolveActor())?.identity;
11749
+ const creator = await context.users.resolveActor();
11750
+ const identity = creator?.identity;
11471
11751
  if (!identity || identity.provider !== "slack" || identity.providerTenantId !== destination.teamId || identity.providerSubjectId !== actor.slackUserId) throwToolInputError("Scheduled automation creator identity is unavailable.");
11472
11752
  const nowMs = context.now?.() ?? Date.now();
11753
+ const defaultTimezone = input.schedule.timezone ?? await resolveCreatorScheduleTimezone({
11754
+ db,
11755
+ nowMs,
11756
+ slackUserId: actor.slackUserId,
11757
+ teamId: destination.teamId,
11758
+ ...creator.user ? { userId: creator.user.id } : void 0
11759
+ });
11473
11760
  let compiled;
11474
11761
  try {
11475
11762
  compiled = compileScheduleIntent({
11476
- defaultTimezone: getDefaultScheduleTimezone(),
11763
+ defaultTimezone,
11477
11764
  intent: input.schedule,
11478
11765
  nowMs
11479
11766
  });
@@ -11730,7 +12017,7 @@ function createSlackScheduleUpdateAutomationTool(context) {
11730
12017
  inputSchema: z.object({
11731
12018
  automationId: z.string().min(1).describe("Scheduled automation ID returned by slackScheduleListAutomations."),
11732
12019
  title: automationTitleSchema.optional(),
11733
- instruction: automationInstructionSchema.optional(),
12020
+ instruction: automationInstructionToolSchema.optional(),
11734
12021
  schedule: scheduleIntentSchema.describe("Complete replacement schedule. Omit to keep it unchanged.").nullable().optional(),
11735
12022
  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(),
11736
12023
  status: z.enum(["active", "blocked"]).describe("Set active to resume a blocked task, or blocked to stop dispatch.").optional(),
@@ -11777,7 +12064,7 @@ function createSlackScheduleUpdateAutomationTool(context) {
11777
12064
  next.outcomes = input.outcomes === void 0 ? moveTaskOutcomes(lookup.outcomes, lookup.destination, requestedDestination) : await resolveTaskOutcomes(input.outcomes, requestedDestination, lookup.createdBy.slackUserId);
11778
12065
  }
11779
12066
  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));
12067
+ const committed = await saveScheduledAutomation(db, next, automationRevision(lookup), actor);
11781
12068
  if (changingDestination) logInfo("scheduled_automation.move.completed", scheduledAutomationAttributes(committed));
11782
12069
  return scheduleAutomationToolResult(context.conversationId, committed, actor.slackUserId);
11783
12070
  }
@@ -14651,9 +14938,6 @@ function explicitUserLookupError(error) {
14651
14938
  if (error.code === "invalid_arguments") return `Slack rejected the user lookup arguments (${error.apiError ?? error.code}).`;
14652
14939
  if (error.code === "feature_unavailable") return "User lookup is not available for this workspace or app installation.";
14653
14940
  }
14654
- function slackMention(userId) {
14655
- return `<@${userId}>`;
14656
- }
14657
14941
  function asMatch(user) {
14658
14942
  return {
14659
14943
  ...user,
@@ -17617,6 +17901,36 @@ function createSearchToolsTool(catalogTools) {
17617
17901
  }
17618
17902
  //#endregion
17619
17903
  //#region src/chat/tool-support/pi-tool-adapter.ts
17904
+ /**
17905
+ * How long a preempted tool may take to return its own aborted result. Keep it
17906
+ * below the agent's abort settle grace, so the parked turn sees the result.
17907
+ */
17908
+ const TOOL_ABORT_SETTLE_GRACE_MS = 2e3;
17909
+ /**
17910
+ * Stop waiting for a tool shortly after the host preempts it. A tool that
17911
+ * ignores the signal must not hold the turn past its deadline, or the parked
17912
+ * turn loses the attempt. Work that keeps running is detached; its outcome is
17913
+ * unknown.
17914
+ */
17915
+ async function untilPreempted(work, signal) {
17916
+ if (!signal) return await work;
17917
+ let timer;
17918
+ let onAbort = () => {};
17919
+ const preempted = new Promise((_, reject) => {
17920
+ onAbort = () => {
17921
+ timer = setTimeout(() => reject(signal.reason), TOOL_ABORT_SETTLE_GRACE_MS);
17922
+ };
17923
+ if (signal.aborted) onAbort();
17924
+ else signal.addEventListener("abort", onAbort, { once: true });
17925
+ });
17926
+ try {
17927
+ return await Promise.race([work, preempted]);
17928
+ } finally {
17929
+ clearTimeout(timer);
17930
+ signal.removeEventListener("abort", onAbort);
17931
+ work.catch(() => void 0);
17932
+ }
17933
+ }
17620
17934
  /** Wrap tool definitions into Pi Agent tool objects with logging, validation, and sandbox execution. */
17621
17935
  function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools, pluginAuthOrchestration, onToolCall, agentHooks, conversationPrivacy, onToolResult, actionReview) {
17622
17936
  const plannedTools = planToolExposure(tools);
@@ -17678,17 +17992,17 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
17678
17992
  }
17679
17993
  const sandboxInput = buildSandboxInput(toolName, executionInput);
17680
17994
  const isSandbox = Boolean(sandboxTools?.supports(toolName));
17681
- const result = isSandbox ? await sandboxTools.execute({
17995
+ const result = await untilPreempted(isSandbox ? sandboxTools.execute({
17682
17996
  toolName,
17683
17997
  input: sandboxInput,
17684
17998
  ...signal ? { signal } : void 0,
17685
17999
  ...toolName === "grep" || toolName === "findFiles" ? { setToolCallSpanAttributes: setSpanAttributes } : void 0
17686
- }) : await toolDef.execute(executionInput, {
18000
+ }) : Promise.resolve(toolDef.execute(executionInput, {
17687
18001
  experimental_context: sandbox,
17688
18002
  ...signal ? { signal } : void 0,
17689
18003
  conversationPrivacy: effectiveConversationPrivacy,
17690
18004
  toolCallId
17691
- });
18005
+ })), signal);
17692
18006
  const normalized = normalizeToolResult(result, {
17693
18007
  requireStructuredResult: Boolean(toolDef.outputSchema),
17694
18008
  toolName
@@ -18068,17 +18382,24 @@ function clientAllowsRedirectUri(clientInformation, callbackUrl) {
18068
18382
  if (!Array.isArray(redirectUris)) return true;
18069
18383
  return redirectUris.includes(callbackUrl);
18070
18384
  }
18385
+ function requireEnv(name) {
18386
+ const value = process.env[name]?.trim();
18387
+ if (!value) throw new Error(`MCP OAuth client env var ${name} is unset`);
18388
+ return value;
18389
+ }
18071
18390
  var StateBackedMcpOAuthClientProvider = class {
18072
18391
  authSessionId;
18073
18392
  callbackUrl;
18074
18393
  sessionContext;
18075
18394
  runCredentialMutation;
18395
+ oauthClient;
18076
18396
  clientMetadata;
18077
- constructor(authSessionId, callbackUrl, sessionContext, runCredentialMutation) {
18397
+ constructor(authSessionId, callbackUrl, sessionContext, runCredentialMutation, oauthClient) {
18078
18398
  this.authSessionId = authSessionId;
18079
18399
  this.callbackUrl = callbackUrl;
18080
18400
  this.sessionContext = sessionContext;
18081
18401
  this.runCredentialMutation = runCredentialMutation;
18402
+ this.oauthClient = oauthClient;
18082
18403
  this.clientMetadata = createClientMetadata(callbackUrl);
18083
18404
  }
18084
18405
  get redirectUrl() {
@@ -18088,6 +18409,10 @@ var StateBackedMcpOAuthClientProvider = class {
18088
18409
  return this.authSessionId;
18089
18410
  }
18090
18411
  async clientInformation() {
18412
+ if (this.oauthClient) return {
18413
+ client_id: requireEnv(this.oauthClient.clientIdEnv),
18414
+ client_secret: requireEnv(this.oauthClient.clientSecretEnv)
18415
+ };
18091
18416
  const session = await this.getCredentialContext();
18092
18417
  const clientInformation = (await getMcpStoredOAuthCredentials(session.userId, session.provider))?.clientInformation;
18093
18418
  if (!clientInformation) return;
@@ -18118,6 +18443,8 @@ var StateBackedMcpOAuthClientProvider = class {
18118
18443
  });
18119
18444
  }
18120
18445
  async redirectToAuthorization(authorizationUrl) {
18446
+ if (this.oauthClient?.scope) authorizationUrl.searchParams.set("scope", this.oauthClient.scope);
18447
+ for (const [key, value] of Object.entries(this.oauthClient?.authorizeParams ?? {})) authorizationUrl.searchParams.set(key, value);
18121
18448
  const existing = await getMcpAuthSession(this.authSessionId);
18122
18449
  if (existing?.authorizationUrl && existing.authorizationUrl !== authorizationUrl.toString()) throw new Error("MCP OAuth authorization attempt is already initialized");
18123
18450
  await this.ensureSession({ authorizationUrl: authorizationUrl.toString() });
@@ -18211,7 +18538,7 @@ function requirePluginWithMcp(provider) {
18211
18538
  }
18212
18539
  /** Create one immutable provider authorization attempt for the active turn. */
18213
18540
  async function createMcpOAuthClientProvider(input) {
18214
- requirePluginWithMcp(input.provider);
18541
+ const plugin = requirePluginWithMcp(input.provider);
18215
18542
  const baseUrl = resolveBaseUrl();
18216
18543
  if (!baseUrl) throw new Error("Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)");
18217
18544
  return new StateBackedMcpOAuthClientProvider(input.createAuthorizationState ? await input.createAuthorizationState() : randomUUID(), `${baseUrl}${getMcpOAuthCallbackPath(input.provider)}`, {
@@ -18226,7 +18553,7 @@ async function createMcpOAuthClientProvider(input) {
18226
18553
  ...input.threadTs ? { threadTs: input.threadTs } : void 0,
18227
18554
  ...input.toolChannelId ? { toolChannelId: input.toolChannelId } : void 0,
18228
18555
  ...input.configuration ? { configuration: input.configuration } : void 0
18229
- });
18556
+ }, void 0, plugin.manifest.mcp?.oauthClient);
18230
18557
  }
18231
18558
  /** Exchange a callback code while guarding every shared credential mutation. */
18232
18559
  async function finalizeMcpAuthorization(provider, authSessionId, authorizationCode, runCredentialMutation) {
@@ -18237,7 +18564,7 @@ async function finalizeMcpAuthorization(provider, authSessionId, authorizationCo
18237
18564
  if (session.provider !== provider) throw new Error(`MCP auth session provider mismatch: expected "${provider}", got "${session.provider}"`);
18238
18565
  const baseUrl = resolveBaseUrl();
18239
18566
  if (!baseUrl) throw new Error("Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)");
18240
- const authProvider = new StateBackedMcpOAuthClientProvider(authSessionId, `${baseUrl}${getMcpOAuthCallbackPath(provider)}`, void 0, runCredentialMutation);
18567
+ const authProvider = new StateBackedMcpOAuthClientProvider(authSessionId, `${baseUrl}${getMcpOAuthCallbackPath(provider)}`, void 0, runCredentialMutation, mcp.oauthClient);
18241
18568
  const headers = mcp.headers ? resolvePluginHeaderEnvRefs(provider, mcp.headers, "MCP header") : void 0;
18242
18569
  let providerStatus;
18243
18570
  const transport = new StreamableHTTPClientTransport(new URL(mcp.url), {
@@ -18431,6 +18758,10 @@ function defaultGrantForProvider(input) {
18431
18758
  }
18432
18759
  };
18433
18760
  }
18761
+ function hasGenericCredentials(provider) {
18762
+ const manifest = pluginCatalogRuntime.getDefinition(provider)?.manifest;
18763
+ return Boolean(manifest?.credentials || manifest?.apiHeaders);
18764
+ }
18434
18765
  function oauthAuthorizationForProvider(provider) {
18435
18766
  const oauth = pluginCatalogRuntime.getOAuthConfig(provider);
18436
18767
  return oauth ? {
@@ -18453,6 +18784,8 @@ function assertLeaseTransformsOwnedByProvider(provider, lease) {
18453
18784
  *
18454
18785
  * GitHub GraphQL and other plugin-owned APIs may need body-aware grant choices;
18455
18786
  * providers without hooks use a simple read/write default based on HTTP method.
18787
+ * A hook plugin that also declares generic credentials can return no grant to
18788
+ * use that default for one request.
18456
18789
  */
18457
18790
  async function selectSandboxEgressGrant(input) {
18458
18791
  if (!hasEgressCredentialHooks(input.provider)) return defaultGrantForProvider(input);
@@ -18463,7 +18796,10 @@ async function selectSandboxEgressGrant(input) {
18463
18796
  method: input.method,
18464
18797
  upstreamUrl: input.upstreamUrl
18465
18798
  });
18466
- if (!pluginGrant) throw new Error(`Plugin "${input.provider}" grantForEgress must return a grant for sandbox egress`);
18799
+ if (!pluginGrant) {
18800
+ if (hasGenericCredentials(input.provider)) return defaultGrantForProvider(input);
18801
+ throw new Error(`Plugin "${input.provider}" grantForEgress must return a grant for sandbox egress`);
18802
+ }
18467
18803
  return {
18468
18804
  source: "plugin",
18469
18805
  grant: pluginGrant
@@ -21476,7 +21812,7 @@ function createAgentRunner(execute, options) {
21476
21812
  } } : void 0
21477
21813
  };
21478
21814
  if (run.instruction.storedAttachments?.length) {
21479
- const { loadInputImages } = await import("./images-CEXcQ0Id.js").then((n) => n.n);
21815
+ const { loadInputImages } = await import("./images-D6Y3FJDQ.js").then((n) => n.n);
21480
21816
  const storage = nextRun.environment?.attachmentStorage;
21481
21817
  if (!storage) throw new Error("Attachment storage is unavailable.");
21482
21818
  nextRun.instruction = {
@@ -21527,4 +21863,4 @@ async function runAgentWithTimeout(agentRunner, run, timeoutMs) {
21527
21863
  }
21528
21864
  }
21529
21865
  //#endregion
21530
- export { deleteEventAutomation as $, isFinalAttempt as $t, requestAttachmentDeletion as A, actorFromRun as An, clearExpiredConversationLease as At, listScheduledAutomations as B, listActiveConversationIds as Bt, isExperimentalFeatureEnabled 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, getExperimentalFeatures 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, resolvePluginOAuthAccount as _, escapeSlackMrkdwnText as _n, ingestEvent as _t, executeCredentialedEgressRequest as a, normalizeSandboxEgressTracePropagationDomains as an, saveEventAutomation as at, unpublishedArtifactHeaders as b, normalizeSlackStatusText as bn, getEventCatalog as bt, deleteMcpAuthSessionsForUserProvider as c, clearSandboxEgressSignals as cn, automationRevision as ct, getMcpAuthSession as d, parseSandboxEgressCredentialToken as dn, agentInvocationSchema as dt, isInvalidConversationRecordError as en, eventAutomationBelongsToUser as et, getMcpStoredOAuthCredentials as f, sandboxEgressSignalsResponseSchema as fn, createAgentInvocationSchema as ft, readStats as g, startOAuthFlow as gn, processWorkspaceSnapshotJob as gt, latestProgressStatus as h, resolveBaseUrl as hn, getMcpProviderErrorAttributes as ht, createContextCompactor 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, deleteMcpServerSessionId as l, consumeSandboxEgressAuthRequiredSignal as ln, requireAutomationRevision as lt, PluginCredentialFailureError as m, parseOAuthStatePayload as mn, AgentInvocationLimitError as mt, runAgentWithTimeout as n, maybePostAutomatedTurnLimitNotice as nn, getEventAutomation as nt, finalizeMcpAuthorization as o, shouldPropagateSandboxEgressTrace as on, setEventAutomationStatus as ot, putMcpStoredOAuthCredentials as p, formatProviderLabel as pn, AgentInvocationBusyError as pt, withScheduledAutomationLock as q, startConversationWork as qt, executeAgentRun as r, recordFinishedTurnForAutomatedLimit as rn, listDeletedEventAutomationsCreatedBy as rt, deleteMcpAuthSession as s, SANDBOX_EGRESS_PROXY_PATH as sn, AutomationConflictError as st, createAgentRunner as t, renderTaskInput as tn, findMatchingEventAutomations as tt, deleteMcpStoredOAuthCredentials as u, consumeSandboxEgressPermissionDeniedSignal as un, agentBindingSchema as ut, publicArtifactHeaders as v, formatSlackLink as vn, EVENT_WAIT_MS as vt, setExperimentalFeatures as w, removeReactionFromMessage as wn, appendAndEnqueueExclusiveInboundMessage as wt, experimental_exports as x, truncateStatusText as xn, eventGuidance as xt, readPublicArtifact as y, normalizeSlackReplyMarkdown as yn, isEventMailboxMetadata as yt, scheduledAutomationRunAttributes as z, hasRunnableConversationWork as zt };
21866
+ export { effectiveTaskOutcomes as $, requestConversationWork as $t, requestAttachmentDeletion as A, addReactionToMessage as An, ackMessages as At, logScheduledAutomationRunSkipped as B, AuthorizationFlowDisabledError as Bn, countPendingConversationMessages as Bt, isExperimentalFeatureEnabled as C, startOAuthFlow as Cn, processWorkspaceSnapshotJob as Ct, renderBlockText as D, normalizeSlackStatusText as Dn, getEventCatalog as Dt, renderAttachmentText as E, normalizeSlackReplyMarkdown as En, isEventMailboxMetadata as Et, resolveSlackChannelIdFromThreadId as F, createUserTokenStore as Fn, checkInConversationWork as Ft, readScheduledAutomation as G, getConversationWorkState as Gt, listScheduledAutomations as H, getConfigDefaults as Hn, drainConversationMailbox as Ht, getConversationInfo as I, buildSteeringPiMessage as In, clearConsumedConversationWake as It, scheduledRunId as J, recordAttemptFailure as Jt, saveScheduledAutomation as K, hasRunnableConversationWork as Kt, listThreadReplies as L, RetryableDeliveryError as Ln, clearExpiredConversationLease as Lt, parseSlackThreadId as M, removeReactionFromMessage as Mn, appendAndEnqueueInboundMessage as Mt, readSlackRawMessageContext as N, slackEntitySchema as Nn, beginConversationResume as Nt, collectAttachmentGarbage as O, slackMention as On, eventGuidance as Ot, resolveSlackChannelIdFromMessage as P, slackExternalRefIdSchema as Pn, cancelHumanFacingPendingMessages as Pt, eventAutomationTriggerAvailable as Q, requestAnotherSlice as Qt, editScheduledAutomation as R, actorFromRun as Rn, completeConversationStop as Rt, getExperimentalFeatures as S, resolveBaseUrl as Sn, getMcpProviderErrorAttributes as St, lookupSlackUserProfile as T, formatSlackLink as Tn, EVENT_WAIT_MS as Tt, listScheduledAutomationsForTeam as U, setConfigDefaults as Un, ensureConversationWake as Ut, scheduledAutomationRunAttributes as V, shouldEmitDevAgentTrace as Vn, deadLetterAttempt as Vt, parseScheduledAutomationRow as W, getConversation as Wt, editEventAutomation as X, releaseConversationWork as Xt, withScheduledAutomationLock as Y, recordConversationRetry as Yt, AutomationEditError as Z, removeActiveConversation as Zt, resolvePluginOAuthAccount as _, consumeSandboxEgressPermissionDeniedSignal as _n, agentBindingSchema as _t, executeCredentialedEgressRequest as a, hasRunnableConversationWork$1 as an, getEventAutomation as at, unpublishedArtifactHeaders as b, formatProviderLabel as bn, AgentInvocationBusyError as bt, deleteMcpAuthSessionsForUserProvider as c, renderTaskInput as cn, saveEventAutomation as ct, getMcpAuthSession as d, resolveSandboxEgressProviderForHost as dn, listAutomationVersions as dt, startConversationWork as en, resolveTaskOutcomes as et, getMcpStoredOAuthCredentials as f, normalizeSandboxEgressTracePropagationDomains as fn, readAutomationVersion as ft, readStats as g, consumeSandboxEgressAuthRequiredSignal as gn, requireAutomationRevision as gt, latestProgressStatus as h, clearSandboxEgressSignals as hn, automationRevision as ht, createContextCompactor as i, hasConversationStop as in, findMatchingEventAutomations as it, storeAttachment as j, postSlackMessage as jn, appendAndEnqueueExclusiveInboundMessage as jt, readLiveAttachment as k, truncateStatusText as kn, pluginEventCatalog as kt, deleteMcpServerSessionId as l, maybePostAutomatedTurnLimitNotice as ln, setEventAutomationStatus as lt, PluginCredentialFailureError as m, SANDBOX_EGRESS_PROXY_PATH as mn, AutomationConflictError as mt, runAgentWithTimeout as n, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as nn, deleteEventAutomation as nt, finalizeMcpAuthorization as o, isFinalAttempt as on, listDeletedEventAutomationsCreatedBy as ot, putMcpStoredOAuthCredentials as p, shouldPropagateSandboxEgressTrace as pn, sameDefinitionValue as pt, saveScheduledAutomationInLock as q, listActiveConversationIds as qt, executeAgentRun as r, CONVERSATION_WORK_STALE_ENQUEUE_MS as rn, eventAutomationBelongsToUser as rt, deleteMcpAuthSession as s, isInvalidConversationRecordError as sn, parseEventAutomationRow as st, createAgentRunner as t, stopConversationWork as tn, collectEventAutomationMatchKeys as tt, deleteMcpStoredOAuthCredentials as u, recordFinishedTurnForAutomatedLimit as un, automationDefinition as ut, publicArtifactHeaders as v, parseSandboxEgressCredentialToken as vn, agentInvocationSchema as vt, setExperimentalFeatures as w, escapeSlackMrkdwnText as wn, ingestEvent as wt, experimental_exports as x, parseOAuthStatePayload as xn, AgentInvocationLimitError as xt, readPublicArtifact as y, sandboxEgressSignalsResponseSchema as yn, createAgentInvocationSchema as yt, lookupSlackUser as z, toolInvocationDestination as zn, completeConversationWork as zt };