@sentry/junior 0.178.0 → 0.179.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 (67) hide show
  1. package/dist/{agent-hooks-PBT4NNBV.js → agent-hooks-32IDCLMW.js} +12 -12
  2. package/dist/api.js +229 -196
  3. package/dist/app.js +570 -195
  4. package/dist/{catalog-runtime-M7QGKPFZ.js → catalog-runtime-FBVA6WAQ.js} +5 -5
  5. package/dist/chat/scheduled-tasks/personal.d.ts +5 -8
  6. package/dist/chat/scheduled-tasks/runs.d.ts +49 -0
  7. package/dist/chat/scheduled-tasks/schedule-intent.d.ts +1 -1
  8. package/dist/chat/scheduled-tasks/tasks.d.ts +27 -0
  9. package/dist/chat/scheduled-tasks/tool-support.d.ts +0 -4
  10. package/dist/chat/scheduled-tasks/tools/create.d.ts +1 -1
  11. package/dist/chat/scheduled-tasks/tools/update.d.ts +1 -1
  12. package/dist/chat/scheduled-tasks/types.d.ts +127 -78
  13. package/dist/{chunk-JVXZ3WDH.js → chunk-2HIPYNQI.js} +6 -6
  14. package/dist/{chunk-BHHWCNXI.js → chunk-3AFVR5UC.js} +5 -5
  15. package/dist/{chunk-XWUJWHFD.js → chunk-3I7XE3PA.js} +6 -6
  16. package/dist/{chunk-H6ZXBFGX.js → chunk-3TM3FYLQ.js} +1 -1
  17. package/dist/{chunk-6OYVH66J.js → chunk-4GWXAILB.js} +1 -1
  18. package/dist/{chunk-BUGO42R6.js → chunk-5IRROPA5.js} +4 -4
  19. package/dist/{chunk-534BO42N.js → chunk-B6ECUSVX.js} +3 -3
  20. package/dist/{chunk-G3CQEUHI.js → chunk-CJLBLELR.js} +5 -5
  21. package/dist/{chunk-22T3HB44.js → chunk-FAS6AIMF.js} +1 -1
  22. package/dist/{chunk-BFLMRTPD.js → chunk-FIDMHAO6.js} +6 -6
  23. package/dist/{chunk-AVRWMQ4U.js → chunk-FTGD2FBP.js} +1 -1
  24. package/dist/{chunk-UMG7M32G.js → chunk-G2CAC4CV.js} +17 -17
  25. package/dist/{chunk-3ZZEPLLB.js → chunk-GENV6KF2.js} +2 -2
  26. package/dist/{chunk-RE4XWXBV.js → chunk-GPLAT6H7.js} +6 -6
  27. package/dist/{chunk-UGWBJAGN.js → chunk-HQNE5APD.js} +1 -1
  28. package/dist/{chunk-AQHSXA3J.js → chunk-JMJNFEDC.js} +3 -3
  29. package/dist/{chunk-PRDKO3QB.js → chunk-JT4WMD3C.js} +12 -12
  30. package/dist/{chunk-4K6VNP3S.js → chunk-KJLHIHFF.js} +9 -9
  31. package/dist/{chunk-QCCLDJHB.js → chunk-Q5B3WTGG.js} +8 -8
  32. package/dist/{chunk-RGXOLPWO.js → chunk-R5NWWYIS.js} +1 -1
  33. package/dist/{chunk-ZCHHVTMF.js → chunk-R6U7N4FS.js} +1 -1
  34. package/dist/{chunk-OGRD5PFM.js → chunk-RTRBYSF3.js} +1 -1
  35. package/dist/{chunk-FQ6BMP5P.js → chunk-RZRYOLCE.js} +396 -74
  36. package/dist/{chunk-D3UJTX4U.js → chunk-SLGGOASN.js} +1 -1
  37. package/dist/{chunk-IQRPDKPJ.js → chunk-TIEKUH4Q.js} +1 -1
  38. package/dist/{chunk-LAOP4EPL.js → chunk-U4TKB6F6.js} +4 -4
  39. package/dist/{chunk-AGJ4OQ2V.js → chunk-UT6X7XN7.js} +1 -1
  40. package/dist/{chunk-XCNS3CXE.js → chunk-VP4OVRDD.js} +3 -3
  41. package/dist/{chunk-KEQAA42D.js → chunk-XSPSCWLH.js} +1 -1
  42. package/dist/chunk-XZY6G5YZ.js +1088 -0
  43. package/dist/{chunk-ABLODWPO.js → chunk-YFNAMRGE.js} +1 -1
  44. package/dist/{chunk-U3UDPGZG.js → chunk-ZQMG3CL5.js} +2 -2
  45. package/dist/cli/chat.js +31 -31
  46. package/dist/cli/check.js +6 -6
  47. package/dist/cli/plugins.js +13 -13
  48. package/dist/cli/snapshot-create.js +10 -10
  49. package/dist/cli/upgrade.js +7 -7
  50. package/dist/db/schema/scheduled-tasks.d.ts +29 -5
  51. package/dist/db/schema.d.ts +28 -4
  52. package/dist/{db-QVYOWATH.js → db-EJAV7JL6.js} +7 -7
  53. package/dist/instrumentation.js +4 -4
  54. package/dist/nitro.js +2 -2
  55. package/dist/{oauth-callback-server-PLPAFXO6.js → oauth-callback-server-GAVSUBTQ.js} +23 -23
  56. package/dist/{runner-AGNEIOZS.js → runner-34JL64JF.js} +15 -15
  57. package/dist/{skills-U5KQ66EM.js → skills-U545HALM.js} +6 -6
  58. package/dist/spawn-I2S4IDUQ.js +37 -0
  59. package/dist/{validation-QE4U45KS.js → validation-EVXVGA44.js} +6 -6
  60. package/dist/version.js +1 -1
  61. package/dist/{work-ATAXAHJJ.js → work-QOAUPDBU.js} +18 -18
  62. package/dist/worker-5GX2IKLZ.js +24 -0
  63. package/package.json +5 -5
  64. package/dist/chat/scheduled-tasks/store.d.ts +0 -78
  65. package/dist/chunk-RGV6KHDM.js +0 -1944
  66. package/dist/spawn-ZRYYZP2B.js +0 -37
  67. package/dist/worker-LIL5AOER.js +0 -24
@@ -7,7 +7,7 @@ import {
7
7
  PluginCredentialFailureError,
8
8
  agentNameSchema,
9
9
  createPluginAuthOrchestration
10
- } from "./chunk-BHHWCNXI.js";
10
+ } from "./chunk-3AFVR5UC.js";
11
11
  import {
12
12
  authorizationId
13
13
  } from "./chunk-DIB4GX3G.js";
@@ -32,10 +32,10 @@ import {
32
32
  searchSlackUsers,
33
33
  selectPluginGrant,
34
34
  toMcpProviderError
35
- } from "./chunk-QCCLDJHB.js";
35
+ } from "./chunk-Q5B3WTGG.js";
36
36
  import {
37
37
  getTurnRequestDeadline
38
- } from "./chunk-6OYVH66J.js";
38
+ } from "./chunk-4GWXAILB.js";
39
39
  import {
40
40
  RetryableDeliveryError,
41
41
  actorFromRun,
@@ -51,7 +51,7 @@ import {
51
51
  getSlackMessagePermalink,
52
52
  resolveBaseUrl,
53
53
  uploadFilesToConversation
54
- } from "./chunk-JVXZ3WDH.js";
54
+ } from "./chunk-2HIPYNQI.js";
55
55
  import {
56
56
  parseSandboxEgressAuthRequiredSignal,
57
57
  parseSandboxEgressPermissionDeniedSignal,
@@ -62,7 +62,7 @@ import {
62
62
  SCHEDULED_TASK_SYSTEM_ACTOR,
63
63
  compactEventTask,
64
64
  createEventTask,
65
- createSchedulerSqlStore,
65
+ createScheduledTask,
66
66
  deleteEventTask,
67
67
  eventNamespaceSchema,
68
68
  eventTaskListToolResultSchema,
@@ -70,30 +70,29 @@ import {
70
70
  eventTaskSuccess,
71
71
  eventTaskToolResultSchema,
72
72
  getEventTask,
73
- getFirstRunAtMs,
74
73
  getResourceEventCatalog,
75
- getZonedDateTimeParts,
76
74
  incrementStat,
77
75
  injectContinuationToolName,
78
76
  juniorToolOutputSchema,
79
77
  listEventTasksForTeam,
78
+ listScheduledTasksForTeam,
80
79
  makeStructuredToolOutput,
81
80
  normalizeEventIdentifier,
82
81
  pluginSupportsEvent,
82
+ readScheduledTask,
83
83
  registeredEventTaskTriggerSchema,
84
84
  registeredEventTypeSchema,
85
85
  registeredResourceTypeSchema,
86
86
  requireEventTaskSlackContext,
87
87
  requireSupportedEventTaskTrigger,
88
- resolveLocalScheduleAtMs,
89
88
  saveEventTask,
90
- scheduledTaskAttributes,
89
+ saveScheduledTask,
91
90
  storeAttachments,
92
91
  writableEventTask
93
- } from "./chunk-RGV6KHDM.js";
92
+ } from "./chunk-XZY6G5YZ.js";
94
93
  import {
95
94
  parseSlackThreadId
96
- } from "./chunk-22T3HB44.js";
95
+ } from "./chunk-FAS6AIMF.js";
97
96
  import {
98
97
  AGENTS_REMOVAL_NOTICE,
99
98
  AGENTS_REPLACEMENT_NOTICE,
@@ -163,7 +162,7 @@ import {
163
162
  stripRuntimeTurnContext,
164
163
  trimTrailingAssistantMessages,
165
164
  truncateText
166
- } from "./chunk-BFLMRTPD.js";
165
+ } from "./chunk-FIDMHAO6.js";
167
166
  import {
168
167
  bindSandboxFileSystem,
169
168
  createSandboxSession,
@@ -174,7 +173,7 @@ import {
174
173
  resolve,
175
174
  setSnapshotSpanAttributes,
176
175
  stopSession
177
- } from "./chunk-534BO42N.js";
176
+ } from "./chunk-B6ECUSVX.js";
178
177
  import {
179
178
  privateTraceResultAttributes
180
179
  } from "./chunk-UIE3R5XU.js";
@@ -222,7 +221,7 @@ import {
222
221
  updateWorkspace,
223
222
  withSlackRetries,
224
223
  workspaceRepoCheckoutPath
225
- } from "./chunk-XWUJWHFD.js";
224
+ } from "./chunk-3I7XE3PA.js";
226
225
  import {
227
226
  KNOWN_CONVERSATION_EVENT_TYPES,
228
227
  contextProvenance,
@@ -234,11 +233,12 @@ import {
234
233
  instructionActors,
235
234
  instructionProvenanceFor,
236
235
  sameActorIdentity
237
- } from "./chunk-XCNS3CXE.js";
236
+ } from "./chunk-VP4OVRDD.js";
238
237
  import {
239
238
  juniorArtifacts,
240
- juniorIdentities
241
- } from "./chunk-ZCHHVTMF.js";
239
+ juniorIdentities,
240
+ juniorSchedulerRuns
241
+ } from "./chunk-R6U7N4FS.js";
242
242
  import {
243
243
  SANDBOX_DATA_ROOT,
244
244
  SANDBOX_REPOS_ROOT,
@@ -269,12 +269,12 @@ import {
269
269
  throwSandboxOperationError,
270
270
  workspaceNameFromWaitingResult,
271
271
  wrapSandboxSetupError
272
- } from "./chunk-AQHSXA3J.js";
272
+ } from "./chunk-JMJNFEDC.js";
273
273
  import {
274
274
  fenceLock,
275
275
  getStateAdapter,
276
276
  withLock
277
- } from "./chunk-H6ZXBFGX.js";
277
+ } from "./chunk-3TM3FYLQ.js";
278
278
  import {
279
279
  ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
280
280
  COMPACTION_SUMMARY_PREFIX,
@@ -307,7 +307,7 @@ import {
307
307
  resolveGatewayCredential,
308
308
  resolveGatewayModel,
309
309
  unwrapCurrentInstruction
310
- } from "./chunk-3ZZEPLLB.js";
310
+ } from "./chunk-GENV6KF2.js";
311
311
  import {
312
312
  canExposeConversationPayload,
313
313
  resolveConversationPrivacy,
@@ -317,16 +317,16 @@ import {
317
317
  toGenAiMessagesTraceAttributes,
318
318
  toGenAiPayloadMetadata,
319
319
  toGenAiPayloadTraceAttributes
320
- } from "./chunk-KEQAA42D.js";
320
+ } from "./chunk-XSPSCWLH.js";
321
321
  import {
322
322
  discoverSkills,
323
323
  findSkillByName,
324
324
  loadSkillsByName,
325
325
  parseSkillInvocation
326
- } from "./chunk-U3UDPGZG.js";
326
+ } from "./chunk-ZQMG3CL5.js";
327
327
  import {
328
328
  pluginCatalogRuntime
329
- } from "./chunk-ABLODWPO.js";
329
+ } from "./chunk-YFNAMRGE.js";
330
330
  import {
331
331
  CredentialUnavailableError,
332
332
  OAuthProviderError,
@@ -334,7 +334,7 @@ import {
334
334
  getOAuthProviderErrorAttributes,
335
335
  resolveAuthTokenPlaceholder,
336
336
  resolvePluginCommandEnv
337
- } from "./chunk-D3UJTX4U.js";
337
+ } from "./chunk-SLGGOASN.js";
338
338
  import {
339
339
  credentialUserSubjectId
340
340
  } from "./chunk-CGA4ERJ5.js";
@@ -364,7 +364,7 @@ import {
364
364
  summarizeMessageText,
365
365
  withLogContext,
366
366
  withSpan
367
- } from "./chunk-UGWBJAGN.js";
367
+ } from "./chunk-HQNE5APD.js";
368
368
  import {
369
369
  startInactiveSpan,
370
370
  withActiveSpan
@@ -8809,6 +8809,296 @@ import { z as z28 } from "zod";
8809
8809
 
8810
8810
  // src/chat/scheduled-tasks/schedule-intent.ts
8811
8811
  import { z as z26 } from "zod";
8812
+
8813
+ // src/chat/scheduled-tasks/cadence.ts
8814
+ var FORMATTERS = /* @__PURE__ */ new Map();
8815
+ function getFormatter(timezone) {
8816
+ const existing = FORMATTERS.get(timezone);
8817
+ if (existing) {
8818
+ return existing;
8819
+ }
8820
+ const formatter = new Intl.DateTimeFormat("en-US", {
8821
+ timeZone: timezone,
8822
+ hour12: false,
8823
+ year: "numeric",
8824
+ month: "2-digit",
8825
+ day: "2-digit",
8826
+ hour: "2-digit",
8827
+ minute: "2-digit",
8828
+ second: "2-digit"
8829
+ });
8830
+ FORMATTERS.set(timezone, formatter);
8831
+ return formatter;
8832
+ }
8833
+ function normalizeHour(hour) {
8834
+ return hour === 24 ? 0 : hour;
8835
+ }
8836
+ function getLocalDateWeekday(date) {
8837
+ return new Date(Date.UTC(date.year, date.month - 1, date.day)).getUTCDay();
8838
+ }
8839
+ function getWeekStart(date) {
8840
+ return addDays(date, -((getLocalDateWeekday(date) + 6) % 7));
8841
+ }
8842
+ function getZonedDateTimeParts(timestampMs, timezone) {
8843
+ const parts = getFormatter(timezone).formatToParts(new Date(timestampMs));
8844
+ const values = new Map(parts.map((part) => [part.type, part.value]));
8845
+ const year = Number(values.get("year"));
8846
+ const month = Number(values.get("month"));
8847
+ const day = Number(values.get("day"));
8848
+ const hour = normalizeHour(Number(values.get("hour")));
8849
+ const minute = Number(values.get("minute"));
8850
+ const second = Number(values.get("second"));
8851
+ return {
8852
+ year,
8853
+ month,
8854
+ day,
8855
+ hour,
8856
+ minute,
8857
+ second,
8858
+ weekday: getLocalDateWeekday({ year, month, day })
8859
+ };
8860
+ }
8861
+ function getTimeZoneOffsetMs(timestampMs, timezone) {
8862
+ const parts = getZonedDateTimeParts(timestampMs, timezone);
8863
+ return Date.UTC(
8864
+ parts.year,
8865
+ parts.month - 1,
8866
+ parts.day,
8867
+ parts.hour,
8868
+ parts.minute,
8869
+ parts.second
8870
+ ) - timestampMs;
8871
+ }
8872
+ function localDateTimeToTimestampMs(args) {
8873
+ const localAsUtcMs = Date.UTC(
8874
+ args.date.year,
8875
+ args.date.month - 1,
8876
+ args.date.day,
8877
+ args.time.hour,
8878
+ args.time.minute,
8879
+ 0
8880
+ );
8881
+ const offsets = /* @__PURE__ */ new Set();
8882
+ for (const probeDeltaMs of [
8883
+ -36 * 60 * 60 * 1e3,
8884
+ -12 * 60 * 60 * 1e3,
8885
+ 0,
8886
+ 12 * 60 * 60 * 1e3,
8887
+ 36 * 60 * 60 * 1e3
8888
+ ]) {
8889
+ offsets.add(
8890
+ getTimeZoneOffsetMs(localAsUtcMs + probeDeltaMs, args.timezone)
8891
+ );
8892
+ }
8893
+ const matches = [...offsets].map((offsetMs) => localAsUtcMs - offsetMs).filter((timestampMs) => {
8894
+ const parts = getZonedDateTimeParts(timestampMs, args.timezone);
8895
+ return parts.year === args.date.year && parts.month === args.date.month && parts.day === args.date.day && parts.hour === args.time.hour && parts.minute === args.time.minute;
8896
+ });
8897
+ if (matches.length === 0) {
8898
+ return void 0;
8899
+ }
8900
+ return Math.min(...matches);
8901
+ }
8902
+ function resolveLocalScheduleAtMs(args) {
8903
+ const date = parseLocalDate(args.date);
8904
+ if (!date) {
8905
+ return void 0;
8906
+ }
8907
+ return localDateTimeToTimestampMs({
8908
+ date,
8909
+ time: args.time,
8910
+ timezone: args.timezone
8911
+ });
8912
+ }
8913
+ function daysBetween(left, right) {
8914
+ return Math.floor(
8915
+ (Date.UTC(right.year, right.month - 1, right.day) - Date.UTC(left.year, left.month - 1, left.day)) / (24 * 60 * 60 * 1e3)
8916
+ );
8917
+ }
8918
+ function weeklyRecurrenceMatchesDate(date, start, recurrence) {
8919
+ if (compareDate(date, start) < 0) {
8920
+ return false;
8921
+ }
8922
+ return normalizeWeekdays(recurrence.weekdays).includes(
8923
+ getLocalDateWeekday(date)
8924
+ ) && Math.floor(daysBetween(getWeekStart(start), getWeekStart(date)) / 7) % recurrence.interval === 0;
8925
+ }
8926
+ function greatestCommonDivisor(left, right) {
8927
+ let a = Math.abs(left);
8928
+ let b = Math.abs(right);
8929
+ while (b !== 0) {
8930
+ [a, b] = [b, a % b];
8931
+ }
8932
+ return a;
8933
+ }
8934
+ function findNextRunAtMs(args) {
8935
+ const start = parseLocalDate(args.recurrence.startDate);
8936
+ const interval = args.recurrence.interval;
8937
+ if (!start || !Number.isInteger(interval) || interval <= 0) {
8938
+ return void 0;
8939
+ }
8940
+ const searchFrom = compareDate(args.searchFrom, start) < 0 ? start : args.searchFrom;
8941
+ if (args.recurrence.frequency === "daily") {
8942
+ const offsetDays = daysBetween(start, searchFrom);
8943
+ let candidateDate = addDays(
8944
+ start,
8945
+ Math.ceil(offsetDays / interval) * interval
8946
+ );
8947
+ const gregorianCycleDays = 146097;
8948
+ const candidateCount2 = gregorianCycleDays / greatestCommonDivisor(gregorianCycleDays, interval);
8949
+ for (let attempts = 0; attempts < candidateCount2; attempts += 1) {
8950
+ const candidate = buildCandidate({
8951
+ date: candidateDate,
8952
+ recurrence: args.recurrence,
8953
+ timezone: args.timezone
8954
+ });
8955
+ if (candidate !== void 0 && candidate > args.afterMs) {
8956
+ return candidate;
8957
+ }
8958
+ candidateDate = addDays(candidateDate, interval);
8959
+ }
8960
+ return void 0;
8961
+ }
8962
+ if (args.recurrence.frequency === "weekly") {
8963
+ if (normalizeWeekdays(args.recurrence.weekdays).length === 0) {
8964
+ return void 0;
8965
+ }
8966
+ let candidateDate = searchFrom;
8967
+ const gregorianCycleDays = 146097;
8968
+ const cadenceDays = interval * 7;
8969
+ const searchDays = gregorianCycleDays * cadenceDays / greatestCommonDivisor(gregorianCycleDays, cadenceDays);
8970
+ for (let attempts = 0; attempts < searchDays; attempts += 1) {
8971
+ if (weeklyRecurrenceMatchesDate(candidateDate, start, args.recurrence)) {
8972
+ const candidate = buildCandidate({
8973
+ date: candidateDate,
8974
+ recurrence: args.recurrence,
8975
+ timezone: args.timezone
8976
+ });
8977
+ if (candidate !== void 0 && candidate > args.afterMs) {
8978
+ return candidate;
8979
+ }
8980
+ }
8981
+ candidateDate = addDays(candidateDate, 1);
8982
+ }
8983
+ return void 0;
8984
+ }
8985
+ if (args.recurrence.frequency === "monthly") {
8986
+ const startMonth = start.year * 12 + start.month - 1;
8987
+ const searchMonth = searchFrom.year * 12 + searchFrom.month - 1;
8988
+ let candidateMonth = startMonth + Math.ceil((searchMonth - startMonth) / interval) * interval;
8989
+ const gregorianCycleMonths = 4800;
8990
+ const candidateCount2 = gregorianCycleMonths / greatestCommonDivisor(gregorianCycleMonths, interval);
8991
+ for (let attempts = 0; attempts < candidateCount2; attempts += 1) {
8992
+ const candidateDate = {
8993
+ year: Math.floor(candidateMonth / 12),
8994
+ month: candidateMonth % 12 + 1,
8995
+ day: args.recurrence.dayOfMonth ?? 0
8996
+ };
8997
+ if (compareDate(candidateDate, searchFrom) >= 0) {
8998
+ const candidate = buildCandidate({
8999
+ date: candidateDate,
9000
+ recurrence: args.recurrence,
9001
+ timezone: args.timezone
9002
+ });
9003
+ if (candidate !== void 0 && candidate > args.afterMs) {
9004
+ return candidate;
9005
+ }
9006
+ }
9007
+ candidateMonth += interval;
9008
+ }
9009
+ return void 0;
9010
+ }
9011
+ let candidateYear = start.year + Math.ceil((searchFrom.year - start.year) / interval) * interval;
9012
+ const candidateCount = 400 / greatestCommonDivisor(400, interval);
9013
+ for (let attempts = 0; attempts < candidateCount; attempts += 1) {
9014
+ const candidateDate = {
9015
+ year: candidateYear,
9016
+ month: args.recurrence.month ?? 0,
9017
+ day: args.recurrence.dayOfMonth ?? 0
9018
+ };
9019
+ if (compareDate(candidateDate, searchFrom) >= 0) {
9020
+ const candidate = buildCandidate({
9021
+ date: candidateDate,
9022
+ recurrence: args.recurrence,
9023
+ timezone: args.timezone
9024
+ });
9025
+ if (candidate !== void 0 && candidate > args.afterMs) {
9026
+ return candidate;
9027
+ }
9028
+ }
9029
+ candidateYear += interval;
9030
+ }
9031
+ return void 0;
9032
+ }
9033
+ function getFirstRunAtMs(args) {
9034
+ return findNextRunAtMs({
9035
+ ...args,
9036
+ searchFrom: getLocalDate(args.afterMs, args.timezone)
9037
+ });
9038
+ }
9039
+ function compareDate(left, right) {
9040
+ return Date.UTC(left.year, left.month - 1, left.day) - Date.UTC(right.year, right.month - 1, right.day);
9041
+ }
9042
+ function addDays(date, days) {
9043
+ const next = new Date(Date.UTC(date.year, date.month - 1, date.day + days));
9044
+ return {
9045
+ year: next.getUTCFullYear(),
9046
+ month: next.getUTCMonth() + 1,
9047
+ day: next.getUTCDate()
9048
+ };
9049
+ }
9050
+ function daysInMonth(year, month) {
9051
+ return new Date(Date.UTC(year, month, 0)).getUTCDate();
9052
+ }
9053
+ function parseLocalDate(value) {
9054
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
9055
+ if (!match) {
9056
+ return void 0;
9057
+ }
9058
+ const year = Number(match[1]);
9059
+ const month = Number(match[2]);
9060
+ const day = Number(match[3]);
9061
+ if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day) || month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month)) {
9062
+ return void 0;
9063
+ }
9064
+ return { year, month, day };
9065
+ }
9066
+ function getLocalDate(timestampMs, timezone) {
9067
+ const parts = getZonedDateTimeParts(timestampMs, timezone);
9068
+ return { year: parts.year, month: parts.month, day: parts.day };
9069
+ }
9070
+ function normalizeWeekdays(values) {
9071
+ return [
9072
+ ...new Set((values ?? []).filter((value) => value >= 0 && value <= 6))
9073
+ ].sort((a, b) => a - b);
9074
+ }
9075
+ function buildCandidate(args) {
9076
+ return localDateTimeToTimestampMs({
9077
+ date: args.date,
9078
+ time: args.recurrence.time,
9079
+ timezone: args.timezone
9080
+ });
9081
+ }
9082
+ function getNextRunAtMs(task, scheduledForMs, afterMs = scheduledForMs) {
9083
+ if (task.schedule.kind !== "recurring") {
9084
+ return void 0;
9085
+ }
9086
+ const recurrence = task.schedule.recurrence;
9087
+ if (!recurrence || !Number.isFinite(recurrence.interval) || recurrence.interval <= 0) {
9088
+ return void 0;
9089
+ }
9090
+ const timezone = task.schedule.timezone;
9091
+ const afterDate = getLocalDate(afterMs, timezone);
9092
+ const nextScheduledDate = addDays(getLocalDate(scheduledForMs, timezone), 1);
9093
+ return findNextRunAtMs({
9094
+ afterMs,
9095
+ recurrence,
9096
+ searchFrom: compareDate(afterDate, nextScheduledDate) < 0 ? nextScheduledDate : afterDate,
9097
+ timezone
9098
+ });
9099
+ }
9100
+
9101
+ // src/chat/scheduled-tasks/schedule-intent.ts
8812
9102
  var localDateSchema = z26.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Use a local date in YYYY-MM-DD format.");
8813
9103
  var localTimeSchema = z26.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "Use local time in HH:MM format.");
8814
9104
  var timezoneSchema = z26.string().min(1).max(80).describe(
@@ -9056,6 +9346,41 @@ function compileScheduleIntent(args) {
9056
9346
  };
9057
9347
  }
9058
9348
 
9349
+ // src/chat/scheduled-tasks/telemetry.ts
9350
+ function scheduledTaskAttributes(task, extras = {}) {
9351
+ return {
9352
+ "app.task.id": task.id,
9353
+ "app.task.type": "scheduled",
9354
+ "app.task.status": task.status,
9355
+ "app.task.schedule.kind": task.schedule.kind,
9356
+ "app.task.schedule.timezone": task.schedule.timezone,
9357
+ "app.task.credential_mode": task.credentialMode,
9358
+ "app.task.destination.channel_id": task.destination.channelId,
9359
+ "app.task.destination.team_id": task.destination.teamId,
9360
+ "app.task.destination.visibility": task.conversationAccess.visibility,
9361
+ "app.task.destination.audience": task.conversationAccess.audience,
9362
+ "messaging.destination.name": task.destination.channelId,
9363
+ ...typeof task.nextRunAtMs === "number" ? { "app.task.next_run_at": new Date(task.nextRunAtMs).toISOString() } : {},
9364
+ ...extras
9365
+ };
9366
+ }
9367
+ function scheduledTaskRunAttributes(task, run, extras = {}) {
9368
+ return scheduledTaskAttributes(task, {
9369
+ "app.task.run.id": run.id,
9370
+ "app.task.run.status": run.status,
9371
+ "app.task.run.scheduled_for": new Date(run.scheduledForMs).toISOString(),
9372
+ ...run.dispatchId ? { "app.dispatch.id": run.dispatchId } : {},
9373
+ ...run.resultMessageTs ? { "app.task.result_message_ts": run.resultMessageTs } : {},
9374
+ ...extras
9375
+ });
9376
+ }
9377
+ function logScheduledTaskRunSkipped(task, run, extras = {}) {
9378
+ logInfo(
9379
+ "scheduled_task.run.skipped",
9380
+ scheduledTaskRunAttributes(task, run, extras)
9381
+ );
9382
+ }
9383
+
9059
9384
  // src/chat/scheduled-tasks/tool-support.ts
9060
9385
  import { createHash as createHash2 } from "crypto";
9061
9386
  import {
@@ -9197,7 +9522,7 @@ function sameDestination(task, destination) {
9197
9522
  }
9198
9523
  async function getWritableTask(args) {
9199
9524
  const destination = requireActiveConversation(args.context);
9200
- const task = await schedulerStore(args.context).getTask(args.taskId);
9525
+ const task = await readScheduledTask(getDb(), args.taskId);
9201
9526
  if (!task || task.status === "deleted") {
9202
9527
  throwToolInputError(
9203
9528
  "Scheduled task was not found in the active Slack conversation."
@@ -9268,9 +9593,6 @@ function buildTaskId(args) {
9268
9593
  ).digest("hex").slice(0, 32);
9269
9594
  return `${TASK_ID_PREFIX}_${digest}`;
9270
9595
  }
9271
- function schedulerStore(context) {
9272
- return context.store;
9273
- }
9274
9596
  function normalizeStatus(value) {
9275
9597
  if (value === "active" || value === "blocked") {
9276
9598
  return value;
@@ -9320,13 +9642,13 @@ function createSlackScheduleCreateTaskTool(context) {
9320
9642
  execute: async (input, options) => {
9321
9643
  const destination = requireActiveConversation(context);
9322
9644
  const actor = requireActor(context, destination);
9323
- const store = schedulerStore(context);
9324
9645
  const id = buildTaskId({
9325
9646
  actor,
9326
9647
  destination,
9327
9648
  toolCallId: options.toolCallId
9328
9649
  });
9329
- const existing = await store.getTask(id);
9650
+ const db = getDb();
9651
+ const existing = await readScheduledTask(db, id);
9330
9652
  if (existing) {
9331
9653
  if (!sameDestination(existing, destination) || existing.createdBy.slackUserId !== actor.slackUserId) {
9332
9654
  throwToolInputError("Scheduled task operation identity is invalid.");
@@ -9383,7 +9705,7 @@ function createSlackScheduleCreateTaskTool(context) {
9383
9705
  },
9384
9706
  ...title ? { title } : {}
9385
9707
  };
9386
- const committed = await store.createTask(task);
9708
+ const committed = await createScheduledTask(db, task);
9387
9709
  if (!sameDestination(committed, destination) || committed.createdBy.slackUserId !== actor.slackUserId) {
9388
9710
  throwToolInputError("Scheduled task operation identity is invalid.");
9389
9711
  }
@@ -9427,7 +9749,7 @@ function createSlackScheduleDeleteTaskTool(context) {
9427
9749
  nextRunAtMs: void 0,
9428
9750
  runNowAtMs: void 0
9429
9751
  };
9430
- await schedulerStore(context).saveTask(next);
9752
+ await saveScheduledTask(getDb(), next);
9431
9753
  return scheduleTaskToolResult(
9432
9754
  "slackScheduleDeleteTask",
9433
9755
  compactTask(next)
@@ -9509,7 +9831,7 @@ function createSlackScheduleListTasksTool(context) {
9509
9831
  }
9510
9832
  const query = input.query?.trim() || void 0;
9511
9833
  const crossConversation = Boolean(query) || channelId !== void 0 && channelId !== destination.channelId;
9512
- const matching = (await schedulerStore(context).listTasksForTeam(destination.teamId)).filter((task) => {
9834
+ const matching = (await listScheduledTasksForTeam(getDb(), destination.teamId)).filter((task) => {
9513
9835
  if (task.destination.platform !== "slack") return false;
9514
9836
  if (task.destination.teamId !== destination.teamId) return false;
9515
9837
  if (task.status === "completed") return false;
@@ -9569,7 +9891,7 @@ function createSlackScheduleRunTaskNowTool(context) {
9569
9891
  updatedAtMs: nowMs,
9570
9892
  runNowAtMs: nowMs
9571
9893
  };
9572
- await schedulerStore(context).saveTask(next);
9894
+ await saveScheduledTask(getDb(), next);
9573
9895
  return scheduleTaskToolResult(
9574
9896
  "slackScheduleRunTaskNow",
9575
9897
  compactTask(next)
@@ -9580,6 +9902,7 @@ function createSlackScheduleRunTaskNowTool(context) {
9580
9902
 
9581
9903
  // src/chat/scheduled-tasks/tools/update.ts
9582
9904
  import { z as z33 } from "zod";
9905
+ import { and, eq, inArray } from "drizzle-orm";
9583
9906
  function createSlackScheduleUpdateTaskTool(context) {
9584
9907
  return zodTool({
9585
9908
  approvalMode: "review",
@@ -9609,8 +9932,8 @@ function createSlackScheduleUpdateTaskTool(context) {
9609
9932
  execute: async (input) => {
9610
9933
  const activeDestination = requireActiveConversation(context);
9611
9934
  const actor = requireActor(context, activeDestination);
9612
- const store = schedulerStore(context);
9613
- const lookup = await store.getTask(input.task_id);
9935
+ const db = getDb();
9936
+ const lookup = await readScheduledTask(db, input.task_id);
9614
9937
  if (!lookup || lookup.status === "deleted") {
9615
9938
  throwToolInputError("Scheduled task was not found.");
9616
9939
  }
@@ -9647,7 +9970,12 @@ function createSlackScheduleUpdateTaskTool(context) {
9647
9970
  }
9648
9971
  const changingDestination = moveHere && !alreadyHere;
9649
9972
  if (changingDestination) {
9650
- const incompleteRuns = await store.listIncompleteRunsForTasks([lookup]);
9973
+ const incompleteRuns = await db.select({ id: juniorSchedulerRuns.id }).from(juniorSchedulerRuns).where(
9974
+ and(
9975
+ eq(juniorSchedulerRuns.taskId, lookup.id),
9976
+ inArray(juniorSchedulerRuns.status, ["pending", "running"])
9977
+ )
9978
+ ).limit(1);
9651
9979
  if (incompleteRuns.length > 0) {
9652
9980
  throwToolInputError(
9653
9981
  "Scheduled task cannot be moved while an occurrence is already running. Try again after the current run finishes."
@@ -9713,15 +10041,8 @@ function createSlackScheduleUpdateTaskTool(context) {
9713
10041
  compactTask(lookup)
9714
10042
  );
9715
10043
  }
9716
- await store.saveTask(next);
9717
- const committed = await store.getTask(input.task_id);
9718
- if (!committed) {
9719
- throwToolInputError("Scheduled task update did not complete.");
9720
- }
10044
+ const committed = await saveScheduledTask(db, next);
9721
10045
  if (changingDestination) {
9722
- if (!sameDestination(committed, activeDestination)) {
9723
- throwToolInputError("Scheduled task move did not complete.");
9724
- }
9725
10046
  logInfo(
9726
10047
  "scheduled_task.move.completed",
9727
10048
  scheduledTaskAttributes(committed)
@@ -9743,7 +10064,6 @@ function scheduledTaskToolContext(context) {
9743
10064
  return {
9744
10065
  actor: context.actor,
9745
10066
  source: context.source,
9746
- store: createSchedulerSqlStore(getDb()),
9747
10067
  users: { resolveActor: context.resolveActorIdentity },
9748
10068
  ...context.userText ? { userText: context.userText } : {}
9749
10069
  };
@@ -12366,7 +12686,7 @@ function createSlackThreadReadTool(context) {
12366
12686
  }
12367
12687
 
12368
12688
  // src/chat/tools/user-lookup.ts
12369
- import { and, eq, or, sql } from "drizzle-orm";
12689
+ import { and as and2, eq as eq2, or, sql } from "drizzle-orm";
12370
12690
  import { alias } from "drizzle-orm/pg-core";
12371
12691
  import { z as z53 } from "zod";
12372
12692
  var linkedSlackIdentity = alias(juniorIdentities, "user_lookup_slack_identity");
@@ -12432,12 +12752,12 @@ async function storedSlackUserByEmail(teamId, email) {
12432
12752
  const emailNormalized = normalizeIdentityEmail(email);
12433
12753
  if (!emailNormalized) return void 0;
12434
12754
  const identities = await getSqlExecutor().db().select().from(juniorIdentities).where(
12435
- and(
12436
- eq(juniorIdentities.provider, "slack"),
12437
- eq(juniorIdentities.providerTenantId, teamId),
12438
- eq(juniorIdentities.kind, "user"),
12439
- eq(juniorIdentities.emailVerified, true),
12440
- eq(juniorIdentities.emailNormalized, emailNormalized)
12755
+ and2(
12756
+ eq2(juniorIdentities.provider, "slack"),
12757
+ eq2(juniorIdentities.providerTenantId, teamId),
12758
+ eq2(juniorIdentities.kind, "user"),
12759
+ eq2(juniorIdentities.emailVerified, true),
12760
+ eq2(juniorIdentities.emailNormalized, emailNormalized)
12441
12761
  )
12442
12762
  ).limit(2);
12443
12763
  if (identities.length > 1) {
@@ -12489,18 +12809,18 @@ async function resolveSlack(teamId, query) {
12489
12809
  async function resolveStoredProvider(teamId, provider, query) {
12490
12810
  const rows = await getSqlExecutor().db().select({ slack: linkedSlackIdentity }).from(juniorIdentities).innerJoin(
12491
12811
  linkedSlackIdentity,
12492
- and(
12493
- eq(linkedSlackIdentity.userId, juniorIdentities.userId),
12494
- eq(linkedSlackIdentity.kind, "user"),
12495
- eq(linkedSlackIdentity.provider, "slack"),
12496
- eq(linkedSlackIdentity.providerTenantId, teamId)
12812
+ and2(
12813
+ eq2(linkedSlackIdentity.userId, juniorIdentities.userId),
12814
+ eq2(linkedSlackIdentity.kind, "user"),
12815
+ eq2(linkedSlackIdentity.provider, "slack"),
12816
+ eq2(linkedSlackIdentity.providerTenantId, teamId)
12497
12817
  )
12498
12818
  ).where(
12499
- and(
12500
- eq(juniorIdentities.kind, "user"),
12501
- eq(juniorIdentities.provider, provider),
12819
+ and2(
12820
+ eq2(juniorIdentities.kind, "user"),
12821
+ eq2(juniorIdentities.provider, provider),
12502
12822
  or(
12503
- eq(juniorIdentities.providerSubjectId, query),
12823
+ eq2(juniorIdentities.providerSubjectId, query),
12504
12824
  sql`lower(${juniorIdentities.handle}) = lower(${query})`
12505
12825
  )
12506
12826
  )
@@ -12634,7 +12954,7 @@ import { z as z55 } from "zod";
12634
12954
 
12635
12955
  // src/chat/artifacts/store.ts
12636
12956
  import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
12637
- import { and as and2, eq as eq2, isNull } from "drizzle-orm";
12957
+ import { and as and3, eq as eq3, isNull } from "drizzle-orm";
12638
12958
  var MAX_IMAGE_BYTES = 10 * 1024 * 1024;
12639
12959
  var IMAGE_TYPES = {
12640
12960
  gif: "image/gif",
@@ -12721,9 +13041,9 @@ async function publishImage(args) {
12721
13041
  const [existing] = await args.db.db().select({
12722
13042
  id: juniorArtifacts.id
12723
13043
  }).from(juniorArtifacts).where(
12724
- and2(
12725
- eq2(juniorArtifacts.conversationId, args.conversationId),
12726
- eq2(juniorArtifacts.sha256, sha256)
13044
+ and3(
13045
+ eq3(juniorArtifacts.conversationId, args.conversationId),
13046
+ eq3(juniorArtifacts.sha256, sha256)
12727
13047
  )
12728
13048
  );
12729
13049
  const id = existing?.id ?? randomUUID5();
@@ -12784,9 +13104,9 @@ async function unpublishArtifact(args) {
12784
13104
  }
12785
13105
  const now = args.now ?? /* @__PURE__ */ new Date();
12786
13106
  const updated = await args.db.db().update(juniorArtifacts).set({ deleteRequestedAt: now }).where(
12787
- and2(
12788
- eq2(juniorArtifacts.id, parsed.id),
12789
- eq2(juniorArtifacts.conversationId, args.conversationId)
13107
+ and3(
13108
+ eq3(juniorArtifacts.id, parsed.id),
13109
+ eq3(juniorArtifacts.conversationId, args.conversationId)
12790
13110
  )
12791
13111
  ).returning({ id: juniorArtifacts.id });
12792
13112
  if (updated.length === 0) {
@@ -12803,9 +13123,9 @@ async function readPublicArtifact(args) {
12803
13123
  contentType: juniorArtifacts.contentType,
12804
13124
  storageKey: juniorArtifacts.storageKey
12805
13125
  }).from(juniorArtifacts).where(
12806
- and2(
12807
- eq2(juniorArtifacts.id, parsed.id),
12808
- eq2(juniorArtifacts.public, true),
13126
+ and3(
13127
+ eq3(juniorArtifacts.id, parsed.id),
13128
+ eq3(juniorArtifacts.public, true),
12809
13129
  isNull(juniorArtifacts.deleteRequestedAt)
12810
13130
  )
12811
13131
  );
@@ -19136,7 +19456,9 @@ export {
19136
19456
  normalizeSandboxEgressTracePropagationDomains,
19137
19457
  shouldPropagateSandboxEgressTrace,
19138
19458
  resolveSandboxEgressProviderForHost,
19139
- sanitizeScheduledTaskPrincipal,
19459
+ getNextRunAtMs,
19460
+ scheduledTaskRunAttributes,
19461
+ logScheduledTaskRunSkipped,
19140
19462
  listThreadReplies,
19141
19463
  renderBlockText,
19142
19464
  renderAttachmentText,