@sentry/junior 0.128.0 → 0.129.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-F75ANGBV.js → agent-hooks-ZM4WMZCN.js} +9 -9
  2. package/dist/api/schema/task.d.ts +152 -0
  3. package/dist/api/schema.d.ts +2 -0
  4. package/dist/api/schema.js +13 -3
  5. package/dist/api/tasks/routes.d.ts +4 -0
  6. package/dist/api.js +425 -23
  7. package/dist/app.d.ts +2 -1
  8. package/dist/app.js +315 -27
  9. package/dist/{catalog-runtime-ZPSA5QM2.js → catalog-runtime-TN2GPVEI.js} +5 -5
  10. package/dist/chat/agent-dispatch/context.d.ts +18 -0
  11. package/dist/chat/event-tasks/store.d.ts +7 -1
  12. package/dist/chat/event-tasks/tool-support.d.ts +1 -0
  13. package/dist/chat/resource-events/runtime-catalog.d.ts +3 -0
  14. package/dist/chat/sandbox/resources.d.ts +12 -1
  15. package/dist/chat/scheduled-tasks/cadence.d.ts +27 -0
  16. package/dist/chat/scheduled-tasks/heartbeat.d.ts +6 -0
  17. package/dist/chat/scheduled-tasks/identity.d.ts +6 -0
  18. package/dist/chat/scheduled-tasks/personal.d.ts +26 -0
  19. package/dist/chat/scheduled-tasks/schedule-intent.d.ts +61 -0
  20. package/dist/chat/scheduled-tasks/store.d.ts +77 -0
  21. package/dist/chat/scheduled-tasks/tool-support.d.ts +203 -0
  22. package/dist/chat/scheduled-tasks/tools/create.d.ts +80 -0
  23. package/dist/chat/scheduled-tasks/tools/delete.d.ts +56 -0
  24. package/dist/chat/scheduled-tasks/tools/list.d.ts +54 -0
  25. package/dist/chat/scheduled-tasks/tools/run-now.d.ts +56 -0
  26. package/dist/chat/scheduled-tasks/tools/update.d.ts +82 -0
  27. package/dist/chat/scheduled-tasks/tools.d.ts +6 -0
  28. package/dist/chat/scheduled-tasks/types.d.ts +81 -0
  29. package/dist/chat/tasks/read.d.ts +9 -0
  30. package/dist/chat/tools/scheduled-tasks.d.ts +4 -0
  31. package/dist/{chunk-K5ZB3WWH.js → chunk-2BCQKJTX.js} +2 -2
  32. package/dist/{chunk-G6XQODHM.js → chunk-3N4MWF3R.js} +1 -1
  33. package/dist/{chunk-NHWE6Y7G.js → chunk-6CMYU62S.js} +7 -7
  34. package/dist/{chunk-YY6CVET7.js → chunk-6QQOLIJJ.js} +1308 -804
  35. package/dist/{chunk-WZ365SQC.js → chunk-A6QQPVSH.js} +1 -1
  36. package/dist/chunk-BDIEEZK7.js +1470 -0
  37. package/dist/{chunk-AFJF3RGU.js → chunk-BVKP37NE.js} +61 -13
  38. package/dist/{chunk-5KKIBIIP.js → chunk-CZJUBH6O.js} +12 -12
  39. package/dist/{chunk-OLGB5Y7R.js → chunk-CZQ2DSQZ.js} +1 -1
  40. package/dist/{chunk-3PKF6YNU.js → chunk-E4UCPRYL.js} +1 -1
  41. package/dist/{chunk-KNRODVH2.js → chunk-ESYXDXNX.js} +6 -6
  42. package/dist/{chunk-Z4KTQMWW.js → chunk-GPWHBHAG.js} +1 -1
  43. package/dist/{chunk-JDCPDJ54.js → chunk-GURSWCI4.js} +2 -2
  44. package/dist/{chunk-RYWMDDWK.js → chunk-K3U5447S.js} +1 -1
  45. package/dist/{chunk-SHMHHXD5.js → chunk-KB2M27DL.js} +58 -0
  46. package/dist/{chunk-PBWUUVVG.js → chunk-LV2BQ26V.js} +1 -1
  47. package/dist/{chunk-KTGJAWRO.js → chunk-NNRV4T2C.js} +1 -2
  48. package/dist/{chunk-B6E3YA2H.js → chunk-P6I7LFKC.js} +1 -1
  49. package/dist/{chunk-B7FPRGUJ.js → chunk-PQFNTLZI.js} +3 -3
  50. package/dist/{chunk-A76LKS5W.js → chunk-QAOA4GUG.js} +5 -5
  51. package/dist/{chunk-BY43CEXN.js → chunk-R62DRNKB.js} +2 -2
  52. package/dist/{chunk-HBFQLSGV.js → chunk-U23X4ASF.js} +4 -4
  53. package/dist/{chunk-2HTHX6XV.js → chunk-XENYUOZG.js} +38 -17
  54. package/dist/cli/chat.js +24 -24
  55. package/dist/cli/check.js +6 -6
  56. package/dist/cli/plugins.js +12 -12
  57. package/dist/cli/snapshot-create.js +9 -9
  58. package/dist/cli/upgrade.js +9 -17
  59. package/dist/db/schema/scheduled-tasks.d.ts +257 -0
  60. package/dist/db/schema.d.ts +258 -1
  61. package/dist/{db-FYJYPAKG.js → db-ZI6TBXIS.js} +7 -7
  62. package/dist/instrumentation.js +4 -4
  63. package/dist/nitro.js +2 -2
  64. package/dist/{oauth-callback-server-W3PPIHCS.js → oauth-callback-server-TLA4GARF.js} +17 -17
  65. package/dist/{runner-5NOFUYKR.js → runner-23YFRWQJ.js} +11 -11
  66. package/dist/{skills-ENIBKF5V.js → skills-QIUG4D6M.js} +6 -6
  67. package/dist/{validation-BHLBOO6K.js → validation-3KGEBATS.js} +6 -6
  68. package/dist/version.js +1 -1
  69. package/migrations/0016_neat_the_anarchist.sql +171 -0
  70. package/migrations/meta/0016_snapshot.json +1617 -0
  71. package/migrations/meta/_journal.json +7 -0
  72. package/package.json +5 -6
  73. package/dist/chunk-FJEIX3AH.js +0 -37
package/dist/app.js CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  startConversationWork,
51
51
  startSlackProcessingReaction,
52
52
  stripLeadingBotMention
53
- } from "./chunk-5KKIBIIP.js";
53
+ } from "./chunk-CZJUBH6O.js";
54
54
  import "./chunk-FA6POGLH.js";
55
55
  import {
56
56
  ConversationTurnLifecycleService,
@@ -65,13 +65,13 @@ import {
65
65
  processPluginTask,
66
66
  requireTurnFailureEventId,
67
67
  scheduleSessionCompletedPluginTasks
68
- } from "./chunk-KNRODVH2.js";
68
+ } from "./chunk-ESYXDXNX.js";
69
69
  import {
70
70
  GET,
71
71
  conversationVisibilityFromSlackChannelType,
72
72
  resolveSlackChannelTypeFromMessage,
73
73
  resolveSlackConversationContext
74
- } from "./chunk-JDCPDJ54.js";
74
+ } from "./chunk-GURSWCI4.js";
75
75
  import "./chunk-4CODA7P5.js";
76
76
  import "./chunk-UTL3MHPC.js";
77
77
  import {
@@ -90,7 +90,7 @@ import {
90
90
  import {
91
91
  validatePluginEgressCredentialHooks,
92
92
  validatePluginRegistrations
93
- } from "./chunk-3PKF6YNU.js";
93
+ } from "./chunk-E4UCPRYL.js";
94
94
  import {
95
95
  defineJuniorPlugins,
96
96
  pluginCatalogConfigFromEnv,
@@ -112,7 +112,6 @@ import {
112
112
  deliverResourceEventSubscription,
113
113
  executeAgentRun,
114
114
  executeCredentialedEgressRequest,
115
- findMatchingEventTasks,
116
115
  findMatchingResourceEventSubscriptions,
117
116
  getConfigDefaults,
118
117
  latestReportedProgress,
@@ -122,10 +121,11 @@ import {
122
121
  renderSlackLegacyAttachmentText,
123
122
  resolveDestinationVisibility,
124
123
  resolveSandboxEgressProviderForHost,
124
+ sanitizeScheduledTaskPrincipal,
125
125
  setConfigDefaults,
126
126
  shouldEmitDevAgentTrace,
127
127
  shouldPropagateSandboxEgressTrace
128
- } from "./chunk-YY6CVET7.js";
128
+ } from "./chunk-6QQOLIJJ.js";
129
129
  import "./chunk-DIB4GX3G.js";
130
130
  import {
131
131
  RetryableDeliveryError,
@@ -136,7 +136,7 @@ import {
136
136
  formatProviderLabel,
137
137
  postSlackMessage,
138
138
  startOAuthFlow
139
- } from "./chunk-NHWE6Y7G.js";
139
+ } from "./chunk-6CMYU62S.js";
140
140
  import {
141
141
  ConversationTurnBoundaryError,
142
142
  CooperativeTurnYieldError,
@@ -192,13 +192,19 @@ import {
192
192
  trimTrailingAssistantMessages,
193
193
  updateConversationStats,
194
194
  upsertConversationMessage
195
- } from "./chunk-HBFQLSGV.js";
195
+ } from "./chunk-U23X4ASF.js";
196
196
  import "./chunk-EPBBYMNE.js";
197
- import "./chunk-2HTHX6XV.js";
198
- import "./chunk-FJEIX3AH.js";
197
+ import {
198
+ getSandboxResourceConfig,
199
+ setSandboxResourceConfig
200
+ } from "./chunk-XENYUOZG.js";
201
+ import {
202
+ createSchedulerSqlStore,
203
+ findMatchingEventTasks
204
+ } from "./chunk-BDIEEZK7.js";
199
205
  import {
200
206
  parseSlackThreadId
201
- } from "./chunk-PBWUUVVG.js";
207
+ } from "./chunk-LV2BQ26V.js";
202
208
  import "./chunk-HX236W2U.js";
203
209
  import "./chunk-PDO5BLNM.js";
204
210
  import "./chunk-UIE3R5XU.js";
@@ -226,7 +232,7 @@ import {
226
232
  verifyEventTaskCredentialSubject,
227
233
  verifyScheduledTaskCredentialSubject,
228
234
  verifySlackDirectCredentialSubject
229
- } from "./chunk-A76LKS5W.js";
235
+ } from "./chunk-QAOA4GUG.js";
230
236
  import {
231
237
  contextProvenance,
232
238
  createSlackDestination,
@@ -237,16 +243,16 @@ import {
237
243
  instructionProvenanceFor,
238
244
  requireSlackDestination,
239
245
  withConversationEventLock
240
- } from "./chunk-B7FPRGUJ.js";
246
+ } from "./chunk-PQFNTLZI.js";
241
247
  import {
242
248
  juniorConversationEvents,
243
249
  juniorConversations
244
- } from "./chunk-SHMHHXD5.js";
250
+ } from "./chunk-KB2M27DL.js";
245
251
  import {
246
252
  acquireActiveLock,
247
253
  getStateAdapter,
248
254
  sleep
249
- } from "./chunk-G6XQODHM.js";
255
+ } from "./chunk-3N4MWF3R.js";
250
256
  import {
251
257
  STANDARD_MODEL_PROFILE,
252
258
  botConfig,
@@ -264,16 +270,16 @@ import {
264
270
  modelIdForProfile,
265
271
  setSlackReactionConfig,
266
272
  standardModelId
267
- } from "./chunk-K5ZB3WWH.js";
273
+ } from "./chunk-2BCQKJTX.js";
268
274
  import {
269
275
  juniorDestinations
270
276
  } from "./chunk-VFUK3X5B.js";
271
- import "./chunk-Z4KTQMWW.js";
272
- import "./chunk-BY43CEXN.js";
277
+ import "./chunk-GPWHBHAG.js";
278
+ import "./chunk-R62DRNKB.js";
273
279
  import {
274
280
  pluginCatalogRuntime
275
- } from "./chunk-WZ365SQC.js";
276
- import "./chunk-OLGB5Y7R.js";
281
+ } from "./chunk-A6QQPVSH.js";
282
+ import "./chunk-CZQ2DSQZ.js";
277
283
  import {
278
284
  credentialSubjectSchema
279
285
  } from "./chunk-77VDLF3Z.js";
@@ -305,7 +311,7 @@ import {
305
311
  withContext,
306
312
  withLogContext,
307
313
  withSpan
308
- } from "./chunk-B6E3YA2H.js";
314
+ } from "./chunk-P6I7LFKC.js";
309
315
  import {
310
316
  continueTrace
311
317
  } from "./chunk-6GWA276C.js";
@@ -313,10 +319,10 @@ import "./chunk-OOUNJNMR.js";
313
319
  import "./chunk-H4HBKISO.js";
314
320
  import {
315
321
  JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
316
- } from "./chunk-RYWMDDWK.js";
322
+ } from "./chunk-K3U5447S.js";
317
323
  import {
318
324
  JUNIOR_VERSION
319
- } from "./chunk-KTGJAWRO.js";
325
+ } from "./chunk-NNRV4T2C.js";
320
326
  import "./chunk-MLKGABMK.js";
321
327
 
322
328
  // src/app.ts
@@ -1233,6 +1239,11 @@ async function recoverConversationWork(args) {
1233
1239
  return result;
1234
1240
  }
1235
1241
 
1242
+ // src/chat/scheduled-tasks/heartbeat.ts
1243
+ import {
1244
+ createSlackSource
1245
+ } from "@sentry/junior-plugin-api";
1246
+
1236
1247
  // src/chat/agent-dispatch/validation.ts
1237
1248
  import {
1238
1249
  dispatchOptionsSchema,
@@ -1467,6 +1478,264 @@ async function dispatchEventTask(args) {
1467
1478
  plugin
1468
1479
  });
1469
1480
  }
1481
+ async function dispatchScheduledTask(args) {
1482
+ const plugin = "scheduler";
1483
+ const { credentialSubject, ...unboundOptions } = args.options;
1484
+ validateDispatchOptions({ ...unboundOptions });
1485
+ const boundSubject = credentialSubject ? bindScheduledTaskCredentialSubject({
1486
+ plugin,
1487
+ subject: credentialSubject
1488
+ }) : void 0;
1489
+ if (credentialSubject && !boundSubject) {
1490
+ throw new Error("Dispatch credentialSubject is not valid for this action");
1491
+ }
1492
+ const options = {
1493
+ ...unboundOptions,
1494
+ ...boundSubject ? { credentialSubject: boundSubject } : {}
1495
+ };
1496
+ return await dispatch({
1497
+ conversationWorkQueue: args.conversationWorkQueue,
1498
+ nowMs: args.nowMs,
1499
+ options,
1500
+ plugin
1501
+ });
1502
+ }
1503
+ async function getScheduledTaskDispatch(id) {
1504
+ return await getPluginDispatchProjection({ plugin: "scheduler", id });
1505
+ }
1506
+
1507
+ // src/chat/scheduled-tasks/heartbeat.ts
1508
+ var SCHEDULED_TASK_HEARTBEAT_LIMIT = 10;
1509
+ var SCHEDULE_FREQUENCY_COPY = {
1510
+ daily: { label: "Daily", unit: "day" },
1511
+ weekly: { label: "Weekly", unit: "week" },
1512
+ monthly: { label: "Monthly", unit: "month" },
1513
+ yearly: { label: "Yearly", unit: "year" }
1514
+ };
1515
+ function singleLineMetadataValue(value) {
1516
+ return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
1517
+ }
1518
+ function buildDispatchMetadata(args) {
1519
+ const creator = sanitizeScheduledTaskPrincipal(args.task.createdBy);
1520
+ if (!args.task.task.text?.trim()) {
1521
+ throw new Error("Scheduled task text is required");
1522
+ }
1523
+ return {
1524
+ creatorSlackUserId: creator.slackUserId,
1525
+ runId: args.run.id,
1526
+ schedule: singleLineMetadataValue(args.task.schedule.description),
1527
+ scheduleKind: args.task.schedule.kind,
1528
+ scheduledFor: new Date(args.run.scheduledForMs).toISOString(),
1529
+ runningAt: new Date(args.nowMs).toISOString(),
1530
+ taskId: args.task.id,
1531
+ timezone: args.task.schedule.timezone,
1532
+ ...args.task.schedule.recurrence ? {
1533
+ recurrenceFrequency: args.task.schedule.recurrence.frequency,
1534
+ recurrenceInterval: String(args.task.schedule.recurrence.interval),
1535
+ recurrenceStartDate: args.task.schedule.recurrence.startDate
1536
+ } : {}
1537
+ };
1538
+ }
1539
+ function replyAttribution(task) {
1540
+ if (task.schedule.kind === "one_off") {
1541
+ return { label: "Scheduled task", detail: "One-time" };
1542
+ }
1543
+ const recurrence = task.schedule.recurrence;
1544
+ if (!recurrence) {
1545
+ return { label: "Scheduled task", detail: "Recurring" };
1546
+ }
1547
+ const frequency = SCHEDULE_FREQUENCY_COPY[recurrence.frequency];
1548
+ return recurrence.interval === 1 ? { label: "Scheduled task", detail: frequency.label } : {
1549
+ label: "Scheduled task",
1550
+ detail: `Every ${recurrence.interval} ${frequency.unit}s`
1551
+ };
1552
+ }
1553
+ function dispatchSource(task) {
1554
+ return createSlackSource({
1555
+ teamId: task.destination.teamId,
1556
+ channelId: task.destination.channelId,
1557
+ visibility: task.conversationAccess.visibility
1558
+ });
1559
+ }
1560
+ function shouldSkipRun(task, run) {
1561
+ if (task.status === "deleted") {
1562
+ return `Scheduled task ${task.id} was deleted before the run started.`;
1563
+ }
1564
+ if (task.status !== "active") {
1565
+ return `Scheduled task ${task.id} was ${task.status} before the run started.`;
1566
+ }
1567
+ if (task.nextRunAtMs !== run.scheduledForMs && task.runNowAtMs !== run.scheduledForMs) {
1568
+ return `Scheduled task ${task.id} no longer targets ${new Date(run.scheduledForMs).toISOString()}.`;
1569
+ }
1570
+ return void 0;
1571
+ }
1572
+ async function applyDispatchResult(args) {
1573
+ if (args.dispatch.status === "completed") {
1574
+ const completed = await args.store.markRunCompleted({
1575
+ completedAtMs: args.nowMs,
1576
+ resultMessageTs: args.dispatch.resultMessageTs,
1577
+ runId: args.run.id,
1578
+ startedAtMs: args.run.startedAtMs
1579
+ });
1580
+ if (!completed) return false;
1581
+ await args.store.updateTaskAfterRun({
1582
+ nowMs: args.nowMs,
1583
+ run: args.run,
1584
+ status: "completed"
1585
+ });
1586
+ return true;
1587
+ }
1588
+ if (args.dispatch.status === "blocked") {
1589
+ const blocked = await args.store.markRunBlocked({
1590
+ completedAtMs: args.nowMs,
1591
+ errorMessage: args.dispatch.errorMessage ?? "Dispatch blocked.",
1592
+ runId: args.run.id,
1593
+ startedAtMs: args.run.startedAtMs
1594
+ });
1595
+ if (!blocked) return false;
1596
+ await args.store.updateTaskAfterRun({
1597
+ errorMessage: blocked.errorMessage,
1598
+ nowMs: args.nowMs,
1599
+ run: args.run,
1600
+ status: "blocked"
1601
+ });
1602
+ return true;
1603
+ }
1604
+ if (args.dispatch.status === "failed") {
1605
+ const failed = await args.store.markRunFailed({
1606
+ completedAtMs: args.nowMs,
1607
+ errorMessage: args.dispatch.errorMessage ?? "Dispatch failed.",
1608
+ runId: args.run.id,
1609
+ startedAtMs: args.run.startedAtMs
1610
+ });
1611
+ if (!failed) return false;
1612
+ await args.store.updateTaskAfterRun({
1613
+ errorMessage: failed.errorMessage,
1614
+ nowMs: args.nowMs,
1615
+ run: args.run,
1616
+ status: "failed"
1617
+ });
1618
+ return true;
1619
+ }
1620
+ return false;
1621
+ }
1622
+ async function finishClaimedRun(args) {
1623
+ const finished = args.status === "blocked" ? await args.store.markRunBlocked({
1624
+ completedAtMs: args.nowMs,
1625
+ errorMessage: args.errorMessage,
1626
+ runId: args.run.id
1627
+ }) : await args.store.markRunFailed({
1628
+ completedAtMs: args.nowMs,
1629
+ errorMessage: args.errorMessage,
1630
+ runId: args.run.id,
1631
+ startedAtMs: args.run.startedAtMs
1632
+ });
1633
+ if (!finished) return;
1634
+ await args.store.updateTaskAfterRun({
1635
+ errorMessage: args.errorMessage,
1636
+ nowMs: args.nowMs,
1637
+ run: args.run,
1638
+ status: args.status
1639
+ });
1640
+ }
1641
+ async function runScheduledTaskHeartbeat(args) {
1642
+ const store = createSchedulerSqlStore(getDb());
1643
+ let processedCount = 0;
1644
+ let dispatchCount = 0;
1645
+ for (const run of await store.listIncompleteRuns()) {
1646
+ if (!run.dispatchId) continue;
1647
+ const dispatch2 = await getScheduledTaskDispatch(run.dispatchId);
1648
+ if (!dispatch2) {
1649
+ await finishClaimedRun({
1650
+ errorMessage: "Scheduled task dispatch record is missing.",
1651
+ nowMs: args.nowMs,
1652
+ run,
1653
+ status: "failed",
1654
+ store
1655
+ });
1656
+ continue;
1657
+ }
1658
+ if (await applyDispatchResult({ dispatch: dispatch2, nowMs: args.nowMs, run, store })) {
1659
+ processedCount += 1;
1660
+ }
1661
+ }
1662
+ for (let index = processedCount; index < SCHEDULED_TASK_HEARTBEAT_LIMIT; index += 1) {
1663
+ const run = await store.claimDueRun({ nowMs: args.nowMs });
1664
+ if (!run) break;
1665
+ const task = await store.getTask(run.taskId);
1666
+ if (!task) {
1667
+ await store.markRunFailed({
1668
+ completedAtMs: args.nowMs,
1669
+ errorMessage: `Scheduled task ${run.taskId} was not found`,
1670
+ runId: run.id
1671
+ });
1672
+ continue;
1673
+ }
1674
+ const skippedReason = shouldSkipRun(task, run);
1675
+ if (skippedReason) {
1676
+ await store.markRunSkipped({
1677
+ completedAtMs: args.nowMs,
1678
+ errorMessage: skippedReason,
1679
+ runId: run.id
1680
+ });
1681
+ continue;
1682
+ }
1683
+ let metadata;
1684
+ try {
1685
+ metadata = buildDispatchMetadata({ nowMs: args.nowMs, run, task });
1686
+ } catch (error) {
1687
+ await finishClaimedRun({
1688
+ errorMessage: error instanceof Error ? `Scheduled task dispatch metadata could not be built: ${error.message}` : "Scheduled task dispatch metadata could not be built.",
1689
+ nowMs: args.nowMs,
1690
+ run,
1691
+ status: "blocked",
1692
+ store
1693
+ });
1694
+ continue;
1695
+ }
1696
+ let dispatch2;
1697
+ try {
1698
+ dispatch2 = await dispatchScheduledTask({
1699
+ conversationWorkQueue: args.conversationWorkQueue,
1700
+ nowMs: args.nowMs,
1701
+ options: {
1702
+ idempotencyKey: run.id,
1703
+ ...task.credentialMode === "creator" ? {
1704
+ credentialSubject: {
1705
+ type: "user",
1706
+ userId: task.createdBy.slackUserId,
1707
+ allowedWhen: "scheduled-task",
1708
+ taskId: task.id
1709
+ }
1710
+ } : {},
1711
+ destination: task.destination,
1712
+ destinationVisibility: task.conversationAccess.visibility,
1713
+ input: task.task.text,
1714
+ metadata,
1715
+ replyAttribution: replyAttribution(task),
1716
+ source: dispatchSource(task)
1717
+ }
1718
+ });
1719
+ } catch (error) {
1720
+ await finishClaimedRun({
1721
+ errorMessage: error instanceof Error ? `Scheduled task dispatch could not be created: ${error.message}` : "Scheduled task dispatch could not be created.",
1722
+ nowMs: args.nowMs,
1723
+ run,
1724
+ status: "blocked",
1725
+ store
1726
+ });
1727
+ continue;
1728
+ }
1729
+ await store.markRunDispatched({
1730
+ claimedAtMs: run.claimedAtMs,
1731
+ dispatchId: dispatch2.id,
1732
+ nowMs: args.nowMs,
1733
+ runId: run.id
1734
+ });
1735
+ dispatchCount += 1;
1736
+ }
1737
+ return dispatchCount;
1738
+ }
1470
1739
 
1471
1740
  // src/chat/agent-dispatch/heartbeat.ts
1472
1741
  var DEFAULT_PLUGIN_LIMIT = 25;
@@ -1568,6 +1837,19 @@ async function runHeartbeat(args) {
1568
1837
  conversationWorkQueue: queue,
1569
1838
  nowMs: args.nowMs
1570
1839
  });
1840
+ try {
1841
+ const dispatchCount = await runScheduledTaskHeartbeat({
1842
+ conversationWorkQueue: queue,
1843
+ nowMs: args.nowMs
1844
+ });
1845
+ if (dispatchCount > 0) {
1846
+ logInfo("scheduled_tasks.heartbeat.dispatched", {
1847
+ "app.dispatch.count": dispatchCount
1848
+ });
1849
+ }
1850
+ } catch (error) {
1851
+ logException(error, "scheduled_tasks.heartbeat.failed");
1852
+ }
1571
1853
  await runPluginHeartbeats({
1572
1854
  conversationWorkQueue: queue,
1573
1855
  nowMs: args.nowMs
@@ -6256,7 +6538,7 @@ function createJuniorRuntimeServices(overrides = {}) {
6256
6538
  }
6257
6539
 
6258
6540
  // src/chat/runtime/reply-executor.ts
6259
- import { createSlackSource } from "@sentry/junior-plugin-api";
6541
+ import { createSlackSource as createSlackSource2 } from "@sentry/junior-plugin-api";
6260
6542
 
6261
6543
  // src/chat/slack/message.ts
6262
6544
  function getSlackMessageTs(message) {
@@ -6546,7 +6828,7 @@ function createReplyToThread(deps) {
6546
6828
  const assistantThreadContext = getAssistantThreadContext(message);
6547
6829
  const messageTs = getMessageTs(message);
6548
6830
  const teamId = destination.teamId;
6549
- const source = options.execution?.source ?? createSlackSource({
6831
+ const source = options.execution?.source ?? createSlackSource2({
6550
6832
  channelId: channelId ?? destination.channelId,
6551
6833
  messageTs,
6552
6834
  teamId,
@@ -8955,7 +9237,7 @@ async function ingestResourceEvent(input, options) {
8955
9237
  // src/chat/event-tasks/ingest.ts
8956
9238
  import { createHash as createHash2 } from "crypto";
8957
9239
  import {
8958
- createSlackSource as createSlackSource2,
9240
+ createSlackSource as createSlackSource3,
8959
9241
  RESOURCE_EVENT_SUMMARY_MAX_LENGTH,
8960
9242
  RESOURCE_EVENT_TEXT_MAX_LENGTH,
8961
9243
  resourceEventSchema as resourceEventSchema2
@@ -9018,7 +9300,7 @@ async function ingestEventTasks(input, options) {
9018
9300
  destination: task.destination,
9019
9301
  destinationVisibility: task.destinationVisibility,
9020
9302
  input: eventInput(task, event),
9021
- source: createSlackSource2({
9303
+ source: createSlackSource3({
9022
9304
  teamId: task.destination.teamId,
9023
9305
  channelId: task.destination.channelId,
9024
9306
  visibility: task.destinationVisibility
@@ -9193,6 +9475,7 @@ function dashboardHostRoutePaths(dashboard) {
9193
9475
  `${pagePath("locations")}/*`,
9194
9476
  peoplePath,
9195
9477
  `${peoplePath}/*`,
9478
+ pagePath("tasks"),
9196
9479
  pagePath("system"),
9197
9480
  `${pagePath("system")}/*`,
9198
9481
  pagePath("plugins"),
@@ -9216,6 +9499,8 @@ function dashboardHostRoutePaths(dashboard) {
9216
9499
  "/api/plugin-reports",
9217
9500
  "/api/user-pages",
9218
9501
  "/api/user-pages/*",
9502
+ "/api/tasks",
9503
+ "/api/tasks/*",
9219
9504
  "/api/skills",
9220
9505
  "/api/stats",
9221
9506
  "/api/conversations",
@@ -9349,6 +9634,7 @@ async function createApp(options) {
9349
9634
  const previousPlugins = setPlugins(plugins);
9350
9635
  const previousConfigDefaults = getConfigDefaults();
9351
9636
  const previousSlackReactionConfig = getSlackReactionConfig();
9637
+ const previousSandboxResources = getSandboxResourceConfig();
9352
9638
  const previousDashboardLinkOptions = setDashboardConversationLinkOptions(dashboard);
9353
9639
  let pluginRoutes = [];
9354
9640
  let pluginApiRoutes = [];
@@ -9383,6 +9669,7 @@ async function createApp(options) {
9383
9669
  sandboxEgressTracePropagationDomains = normalizeSandboxEgressTracePropagationDomains(
9384
9670
  options?.sandbox?.egressTracePropagationDomains
9385
9671
  );
9672
+ setSandboxResourceConfig(options?.sandbox);
9386
9673
  setConfigDefaults(options?.configDefaults);
9387
9674
  if (options?.slack) {
9388
9675
  setSlackReactionConfig(options.slack);
@@ -9404,6 +9691,7 @@ async function createApp(options) {
9404
9691
  setPlugins(previousPlugins);
9405
9692
  setConfigDefaults(previousConfigDefaults);
9406
9693
  setSlackReactionConfig(previousSlackReactionConfig);
9694
+ setSandboxResourceConfig(previousSandboxResources);
9407
9695
  setDashboardConversationLinkOptions(previousDashboardLinkOptions);
9408
9696
  throw error;
9409
9697
  }
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-WZ365SQC.js";
4
- import "./chunk-OLGB5Y7R.js";
3
+ } from "./chunk-A6QQPVSH.js";
4
+ import "./chunk-CZQ2DSQZ.js";
5
5
  import "./chunk-77VDLF3Z.js";
6
6
  import "./chunk-HZF5P5UN.js";
7
7
  import "./chunk-F3B2YJ76.js";
8
- import "./chunk-B6E3YA2H.js";
8
+ import "./chunk-P6I7LFKC.js";
9
9
  import "./chunk-6GWA276C.js";
10
10
  import "./chunk-OOUNJNMR.js";
11
11
  import "./chunk-H4HBKISO.js";
12
- import "./chunk-RYWMDDWK.js";
13
- import "./chunk-KTGJAWRO.js";
12
+ import "./chunk-K3U5447S.js";
13
+ import "./chunk-NNRV4T2C.js";
14
14
  import "./chunk-MLKGABMK.js";
15
15
  export {
16
16
  pluginCatalogRuntime
@@ -23,3 +23,21 @@ export declare function dispatchEventTask(args: {
23
23
  id: string;
24
24
  status: "already_exists" | "created";
25
25
  }>;
26
+ /** Create and enqueue one core-owned scheduled task dispatch. */
27
+ export declare function dispatchScheduledTask(args: {
28
+ conversationWorkQueue: ConversationWorkQueue;
29
+ nowMs: number;
30
+ options: Omit<SlackDispatchOptions, "credentialSubject"> & {
31
+ credentialSubject?: {
32
+ allowedWhen: "scheduled-task";
33
+ taskId: string;
34
+ type: "user";
35
+ userId: string;
36
+ };
37
+ };
38
+ }): Promise<{
39
+ id: string;
40
+ status: "already_exists" | "created";
41
+ }>;
42
+ /** Read the bounded outcome for one core-owned scheduled task dispatch. */
43
+ export declare function getScheduledTaskDispatch(id: string): Promise<import("./types").DispatchProjection | undefined>;
@@ -1,4 +1,4 @@
1
- import { type ResourceEvent } from "@sentry/junior-plugin-api";
1
+ import { type ResourceEvent, type User } from "@sentry/junior-plugin-api";
2
2
  import type { JuniorDatabase } from "@/db/db";
3
3
  import { type EventTask } from "./types";
4
4
  /** Read one event task by id. */
@@ -11,5 +11,11 @@ export declare function saveEventTask(db: JuniorDatabase, task: EventTask): Prom
11
11
  export declare function deleteEventTask(db: JuniorDatabase, id: string): Promise<EventTask | undefined>;
12
12
  /** List event tasks in one Slack workspace. */
13
13
  export declare function listEventTasksForTeam(db: JuniorDatabase, teamId: string): Promise<EventTask[]>;
14
+ /** Return whether one event task was created by a viewer-linked Slack identity. */
15
+ export declare function eventTaskBelongsToUser(task: EventTask, user: User): boolean;
16
+ /** List a bounded newest-first page of event tasks created by one user. */
17
+ export declare function listEventTasksCreatedBy(db: JuniorDatabase, user: User, limit: number): Promise<EventTask[]>;
18
+ /** List event tasks whose current Slack destination is public. */
19
+ export declare function listPublicEventTasksForTeams(db: JuniorDatabase, teamIds: string[], limit: number): Promise<EventTask[]>;
14
20
  /** Find every task matching one normalized resource event. */
15
21
  export declare function findMatchingEventTasks(db: JuniorDatabase, event: ResourceEvent, teamId: string): Promise<EventTask[]>;
@@ -102,6 +102,7 @@ export declare function eventTaskMatchesDestination(task: EventTask, destination
102
102
  }): boolean;
103
103
  /** Load one task only when it belongs to this Slack channel or DM. */
104
104
  export declare function writableEventTask(context: ToolRuntimeContext, id: string): Promise<EventTask>;
105
+ export declare function eventTaskTriggerAvailable(task: EventTask, catalog: ResourceEventCatalog): boolean;
105
106
  /** Project an event task into the bounded tool-result shape. */
106
107
  export declare function compactEventTask(task: EventTask, catalog: ResourceEventCatalog): {
107
108
  id: string;
@@ -0,0 +1,3 @@
1
+ import type { ResourceEventCatalog } from "@/chat/resource-events/catalog";
2
+ /** Read enabled plugin resource-event registrations as one core catalog. */
3
+ export declare function getResourceEventCatalog(): ResourceEventCatalog;
@@ -1,4 +1,15 @@
1
- /** Resolve optional resource sizing shared by every newly created sandbox. */
1
+ export interface SandboxResourceConfig {
2
+ vcpus?: number;
3
+ }
4
+ /** Return the app-level sandbox sizing override. */
5
+ export declare function getSandboxResourceConfig(): {
6
+ vcpus: number;
7
+ } | undefined;
8
+ /** Replace app-level sandbox sizing and return the previous setting. */
9
+ export declare function setSandboxResourceConfig(config?: SandboxResourceConfig): {
10
+ vcpus: number;
11
+ } | undefined;
12
+ /** Resolve app-level sandbox sizing, falling back to the legacy environment setting. */
2
13
  export declare function getSandboxResources(): {
3
14
  vcpus: number;
4
15
  } | undefined;
@@ -0,0 +1,27 @@
1
+ /** Calendar arithmetic for core-owned scheduled tasks. */
2
+ import type { ScheduledLocalTime, ScheduledTask, ScheduledTaskRecurrence } from "./types";
3
+ export interface ZonedDateTimeParts {
4
+ day: number;
5
+ hour: number;
6
+ minute: number;
7
+ month: number;
8
+ second: number;
9
+ weekday: number;
10
+ year: number;
11
+ }
12
+ /** Resolve a UTC timestamp into calendar parts for a named time zone. */
13
+ export declare function getZonedDateTimeParts(timestampMs: number, timezone: string): ZonedDateTimeParts;
14
+ /** Resolve local time, rejecting DST gaps and choosing the earlier instant in a fold. */
15
+ export declare function resolveLocalScheduleAtMs(args: {
16
+ date: string;
17
+ time: ScheduledLocalTime;
18
+ timezone: string;
19
+ }): number | undefined;
20
+ /** Compute the first recurring calendar occurrence strictly after a timestamp. */
21
+ export declare function getFirstRunAtMs(args: {
22
+ afterMs: number;
23
+ recurrence: ScheduledTaskRecurrence;
24
+ timezone: string;
25
+ }): number | undefined;
26
+ /** Return the next fire time after a completed run, when the task recurs. */
27
+ export declare function getNextRunAtMs(task: ScheduledTask, scheduledForMs: number, afterMs?: number): number | undefined;
@@ -0,0 +1,6 @@
1
+ import type { ConversationWorkQueue } from "@/chat/task-execution/queue";
2
+ /** Reconcile completed dispatches and enqueue a bounded batch of due tasks. */
3
+ export declare function runScheduledTaskHeartbeat(args: {
4
+ conversationWorkQueue: ConversationWorkQueue;
5
+ nowMs: number;
6
+ }): Promise<number>;
@@ -0,0 +1,6 @@
1
+ /** Presentation helpers for persisted scheduled-task creators. */
2
+ import type { ScheduledTaskPrincipal } from "./types";
3
+ /** Keep scheduler creator metadata from promoting Slack IDs into display names. */
4
+ export declare function sanitizeScheduledTaskPrincipal(principal: ScheduledTaskPrincipal): ScheduledTaskPrincipal;
5
+ /** Render scheduler creator metadata without inventing human profile fields. */
6
+ export declare function scheduledTaskPrincipalLabel(principal: ScheduledTaskPrincipal): string;