@sentry/junior-scheduler 0.89.0 → 0.90.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.
package/dist/index.js CHANGED
@@ -1148,14 +1148,9 @@ function scheduledTaskPrincipalLabel(principal) {
1148
1148
  return `Slack User ${author.slackUserId}`;
1149
1149
  }
1150
1150
 
1151
- // src/schedule-tools.ts
1152
- import { randomUUID } from "crypto";
1153
- import { Type } from "@sinclair/typebox";
1154
- import {
1155
- PluginToolInputError,
1156
- pluginCredentialSubjectSchema as pluginCredentialSubjectSchema2,
1157
- sourceSchema
1158
- } from "@sentry/junior-plugin-api";
1151
+ // src/tools/create-task.ts
1152
+ import { definePluginTool } from "@sentry/junior-plugin-api";
1153
+ import { z as z3 } from "zod";
1159
1154
 
1160
1155
  // src/types.ts
1161
1156
  var SCHEDULED_TASK_SYSTEM_ACTOR = Object.freeze({
@@ -1163,10 +1158,55 @@ var SCHEDULED_TASK_SYSTEM_ACTOR = Object.freeze({
1163
1158
  id: "scheduled-task"
1164
1159
  });
1165
1160
 
1166
- // src/schedule-tools.ts
1161
+ // src/tool-support.ts
1162
+ import { randomUUID } from "crypto";
1163
+ import {
1164
+ PluginToolInputError,
1165
+ pluginToolResultSchema,
1166
+ pluginCredentialSubjectSchema as pluginCredentialSubjectSchema2,
1167
+ sourceSchema
1168
+ } from "@sentry/junior-plugin-api";
1169
+ import { z as z2 } from "zod";
1167
1170
  var TASK_ID_PREFIX = "sched";
1168
1171
  var MAX_LISTED_TASKS = 50;
1169
1172
  var DEFAULT_SCHEDULE_TIMEZONE = "America/Los_Angeles";
1173
+ var compactTaskResultSchema = z2.object({
1174
+ id: z2.string(),
1175
+ status: z2.enum(["active", "paused", "blocked", "deleted"]),
1176
+ task: z2.string(),
1177
+ schedule: z2.string(),
1178
+ timezone: z2.string(),
1179
+ recurrence: z2.unknown().nullable(),
1180
+ next_run_at: z2.string().nullable(),
1181
+ conversation_access: z2.unknown().nullable(),
1182
+ credential_subject: z2.unknown().nullable(),
1183
+ last_run_at: z2.string().nullable(),
1184
+ run_now_at: z2.string().nullable()
1185
+ }).strict();
1186
+ var scheduleTaskResultDataSchema = z2.object({
1187
+ ok: z2.literal(true),
1188
+ task: compactTaskResultSchema
1189
+ }).strict();
1190
+ var scheduleTaskToolResultSchema = pluginToolResultSchema.extend({
1191
+ ok: z2.literal(true),
1192
+ status: z2.literal("success"),
1193
+ target: z2.string(),
1194
+ data: scheduleTaskResultDataSchema,
1195
+ task: compactTaskResultSchema
1196
+ });
1197
+ var scheduleListResultDataSchema = z2.object({
1198
+ ok: z2.literal(true),
1199
+ tasks: z2.array(compactTaskResultSchema),
1200
+ truncated: z2.boolean()
1201
+ }).strict();
1202
+ var scheduleListToolResultSchema = pluginToolResultSchema.extend({
1203
+ ok: z2.literal(true),
1204
+ status: z2.literal("success"),
1205
+ target: z2.string(),
1206
+ data: scheduleListResultDataSchema,
1207
+ tasks: z2.array(compactTaskResultSchema),
1208
+ truncated: z2.boolean()
1209
+ });
1170
1210
  function throwToolInputError(error) {
1171
1211
  throw new PluginToolInputError(error);
1172
1212
  }
@@ -1214,9 +1254,6 @@ function requireRequester(context) {
1214
1254
  ...context.requester?.fullName ? { fullName: context.requester.fullName } : {}
1215
1255
  });
1216
1256
  }
1217
- function tool(definition) {
1218
- return definition;
1219
- }
1220
1257
  function isDmChannel(channelId) {
1221
1258
  return channelId.startsWith("D");
1222
1259
  }
@@ -1269,7 +1306,7 @@ async function getWritableTask(args) {
1269
1306
  return task;
1270
1307
  }
1271
1308
  function compactTask(task) {
1272
- return {
1309
+ return compactTaskResultSchema.parse({
1273
1310
  id: task.id,
1274
1311
  status: task.status,
1275
1312
  task: task.task.text,
@@ -1292,6 +1329,34 @@ function compactTask(task) {
1292
1329
  } : null,
1293
1330
  last_run_at: task.lastRunAtMs ? new Date(task.lastRunAtMs).toISOString() : null,
1294
1331
  run_now_at: task.runNowAtMs ? new Date(task.runNowAtMs).toISOString() : null
1332
+ });
1333
+ }
1334
+ function scheduleTaskToolResult(target, task) {
1335
+ const data = {
1336
+ ok: true,
1337
+ task
1338
+ };
1339
+ return {
1340
+ ok: true,
1341
+ status: "success",
1342
+ target,
1343
+ data,
1344
+ task
1345
+ };
1346
+ }
1347
+ function scheduleListToolResult(args) {
1348
+ const data = {
1349
+ ok: true,
1350
+ tasks: args.tasks,
1351
+ truncated: args.truncated
1352
+ };
1353
+ return {
1354
+ ok: true,
1355
+ status: "success",
1356
+ target: args.target,
1357
+ data,
1358
+ tasks: args.tasks,
1359
+ truncated: args.truncated
1295
1360
  };
1296
1361
  }
1297
1362
  function buildTaskId() {
@@ -1351,7 +1416,7 @@ function validateCreateScheduleKind(input) {
1351
1416
  if (input.schedule_kind !== "one_off" && input.schedule_kind !== "recurring") {
1352
1417
  throwToolInputError("schedule_kind must be one_off or recurring.");
1353
1418
  }
1354
- if (input.schedule_kind === "one_off" && input.recurrence !== void 0) {
1419
+ if (input.schedule_kind === "one_off" && input.recurrence !== void 0 && input.recurrence !== null) {
1355
1420
  throwToolInputError("Omit recurrence when schedule_kind is one_off.");
1356
1421
  }
1357
1422
  if (input.schedule_kind === "recurring" && (input.recurrence === void 0 || input.recurrence === null)) {
@@ -1382,46 +1447,29 @@ function parseNextRunAtMs(nextRunAtIso) {
1382
1447
  }
1383
1448
  return void 0;
1384
1449
  }
1450
+
1451
+ // src/tools/create-task.ts
1385
1452
  function createSlackScheduleCreateTaskTool(context) {
1386
- return tool({
1453
+ return definePluginTool({
1387
1454
  description: "Create a one-time or recurring Junior task in the active Slack conversation. For one-time reminders or one-time scheduled work, omit recurrence entirely; never choose a default recurrence. Use only when the user explicitly asks Junior to do work later or on a recurring cadence. Only manage tasks for the active Slack DM or channel; never target threads, other channels, or another user's DM. When the task, schedule, and destination are clear, create it without asking for confirmation; ask only when one of those is ambiguous.",
1388
1455
  executionMode: "sequential",
1389
- inputSchema: Type.Object({
1390
- task: Type.String({ minLength: 1, maxLength: 4e3 }),
1391
- schedule: Type.String({ minLength: 1, maxLength: 300 }),
1392
- schedule_kind: Type.Union(
1393
- [Type.Literal("one_off"), Type.Literal("recurring")],
1394
- {
1395
- description: "Required schedule classification. Use one_off for one-time reminders or one-time scheduled work. Use recurring only when the user explicitly asks for a repeating schedule."
1396
- }
1397
- ),
1398
- timezone: Type.Optional(
1399
- Type.String({
1400
- minLength: 1,
1401
- maxLength: 80,
1402
- description: "IANA timezone, e.g. 'America/Los_Angeles'. Defaults to the channel's configured timezone."
1403
- })
1404
- ),
1405
- next_run_at: Type.Optional(
1406
- Type.String({
1407
- minLength: 1,
1408
- description: "Exact next run time as an ISO timestamp, computed from the user's requested schedule."
1409
- })
1456
+ inputSchema: z3.object({
1457
+ task: z3.string().min(1).max(4e3),
1458
+ schedule: z3.string().min(1).max(300),
1459
+ schedule_kind: z3.enum(["one_off", "recurring"]).describe(
1460
+ "Required schedule classification. Use one_off for one-time reminders or one-time scheduled work. Use recurring only when the user explicitly asks for a repeating schedule."
1410
1461
  ),
1411
- recurrence: Type.Optional(
1412
- Type.Union(
1413
- [
1414
- Type.Literal("daily"),
1415
- Type.Literal("weekly"),
1416
- Type.Literal("monthly"),
1417
- Type.Literal("yearly")
1418
- ],
1419
- {
1420
- description: "Required when schedule_kind is recurring. Omit when schedule_kind is one_off. Recurring tasks run at most once per day: use daily, weekly, monthly, or yearly only."
1421
- }
1422
- )
1423
- )
1462
+ timezone: z3.string().min(1).max(80).describe(
1463
+ "IANA timezone, e.g. 'America/Los_Angeles'. Defaults to the channel's configured timezone."
1464
+ ).optional(),
1465
+ next_run_at: z3.string().min(1).describe(
1466
+ "Exact next run time as an ISO timestamp, computed from the user's requested schedule."
1467
+ ).optional(),
1468
+ recurrence: z3.enum(["daily", "weekly", "monthly", "yearly"]).nullable().describe(
1469
+ "Required when schedule_kind is recurring. Omit when schedule_kind is one_off. Recurring tasks run at most once per day: use daily, weekly, monthly, or yearly only."
1470
+ ).optional()
1424
1471
  }),
1472
+ outputSchema: scheduleTaskToolResultSchema,
1425
1473
  execute: async (input) => {
1426
1474
  const destination = requireActiveConversation(context);
1427
1475
  const requester = requireRequester(context);
@@ -1469,18 +1517,54 @@ function createSlackScheduleCreateTaskTool(context) {
1469
1517
  }
1470
1518
  };
1471
1519
  await schedulerStore(context).saveTask(task);
1472
- return {
1473
- ok: true,
1474
- task: compactTask(task)
1520
+ return scheduleTaskToolResult(
1521
+ "slackScheduleCreateTask",
1522
+ compactTask(task)
1523
+ );
1524
+ }
1525
+ });
1526
+ }
1527
+
1528
+ // src/tools/delete-task.ts
1529
+ import { definePluginTool as definePluginTool2 } from "@sentry/junior-plugin-api";
1530
+ import { z as z4 } from "zod";
1531
+ function createSlackScheduleDeleteTaskTool(context) {
1532
+ return definePluginTool2({
1533
+ description: "Delete one scheduled Junior task from the active Slack conversation. Use only task IDs returned for this conversation. Do not delete schedules from threads, other channels, or another user's DM.",
1534
+ executionMode: "sequential",
1535
+ inputSchema: z4.object({
1536
+ task_id: z4.string().min(1).describe(
1537
+ "ID of the task to delete. Must be from this active Slack conversation."
1538
+ )
1539
+ }),
1540
+ outputSchema: scheduleTaskToolResultSchema,
1541
+ execute: async ({ task_id }) => {
1542
+ const lookup = await getWritableTask({ context, taskId: task_id });
1543
+ const next = {
1544
+ ...lookup,
1545
+ updatedAtMs: Date.now(),
1546
+ status: "deleted",
1547
+ nextRunAtMs: void 0,
1548
+ runNowAtMs: void 0
1475
1549
  };
1550
+ await schedulerStore(context).saveTask(next);
1551
+ return scheduleTaskToolResult(
1552
+ "slackScheduleDeleteTask",
1553
+ compactTask(next)
1554
+ );
1476
1555
  }
1477
1556
  });
1478
1557
  }
1558
+
1559
+ // src/tools/list-tasks.ts
1560
+ import { definePluginTool as definePluginTool3 } from "@sentry/junior-plugin-api";
1561
+ import { z as z5 } from "zod";
1479
1562
  function createSlackScheduleListTasksTool(context) {
1480
- return tool({
1563
+ return definePluginTool3({
1481
1564
  description: "List scheduled Junior tasks for the active Slack conversation. Use when the user asks what is scheduled here, or when task IDs are needed before editing, deleting, or running schedules. Only manages tasks for the active Slack DM or channel.",
1482
1565
  annotations: { readOnlyHint: true, destructiveHint: false },
1483
- inputSchema: Type.Object({}),
1566
+ inputSchema: z5.object({}),
1567
+ outputSchema: scheduleListToolResultSchema,
1484
1568
  execute: async () => {
1485
1569
  const destination = requireActiveConversation(context);
1486
1570
  const tasks = await schedulerStore(context).listTasksForTeam(
@@ -1490,59 +1574,73 @@ function createSlackScheduleListTasksTool(context) {
1490
1574
  (task) => sameDestination(task, destination)
1491
1575
  );
1492
1576
  const visible = matching.slice(0, MAX_LISTED_TASKS).map(compactTask);
1493
- return {
1494
- ok: true,
1577
+ return scheduleListToolResult({
1578
+ target: "slackScheduleListTasks",
1495
1579
  tasks: visible,
1496
1580
  truncated: matching.length > visible.length
1581
+ });
1582
+ }
1583
+ });
1584
+ }
1585
+
1586
+ // src/tools/run-task-now.ts
1587
+ import { definePluginTool as definePluginTool4 } from "@sentry/junior-plugin-api";
1588
+ import { z as z6 } from "zod";
1589
+ function createSlackScheduleRunTaskNowTool(context) {
1590
+ return definePluginTool4({
1591
+ description: "Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled task now. Use only task IDs returned for this conversation.",
1592
+ executionMode: "sequential",
1593
+ inputSchema: z6.object({
1594
+ task_id: z6.string().min(1).describe(
1595
+ "ID of the active task to run now. Must be from this active Slack conversation."
1596
+ )
1597
+ }),
1598
+ outputSchema: scheduleTaskToolResultSchema,
1599
+ execute: async ({ task_id }) => {
1600
+ const lookup = await getWritableTask({ context, taskId: task_id });
1601
+ if (lookup.status !== "active") {
1602
+ throwToolInputError(
1603
+ "Scheduled task must be active before it can be run now. Resume the task first if you want it to run."
1604
+ );
1605
+ }
1606
+ const nowMs = Date.now();
1607
+ const next = {
1608
+ ...lookup,
1609
+ updatedAtMs: nowMs,
1610
+ runNowAtMs: nowMs
1497
1611
  };
1612
+ await schedulerStore(context).saveTask(next);
1613
+ return scheduleTaskToolResult(
1614
+ "slackScheduleRunTaskNow",
1615
+ compactTask(next)
1616
+ );
1498
1617
  }
1499
1618
  });
1500
1619
  }
1620
+
1621
+ // src/tools/update-task.ts
1622
+ import { definePluginTool as definePluginTool5 } from "@sentry/junior-plugin-api";
1623
+ import { z as z7 } from "zod";
1501
1624
  function createSlackScheduleUpdateTaskTool(context) {
1502
- return tool({
1625
+ return definePluginTool5({
1503
1626
  description: "Edit, pause, resume, or reschedule an existing Junior scheduled task in the active Slack conversation. Use only task IDs returned for this conversation. Do not move scheduled tasks across conversations.",
1504
1627
  executionMode: "sequential",
1505
- inputSchema: Type.Object({
1506
- task_id: Type.String({
1507
- minLength: 1,
1508
- description: "ID of the task to update. Must be from this active Slack conversation."
1509
- }),
1510
- task: Type.Optional(Type.String({ minLength: 1, maxLength: 4e3 })),
1511
- schedule: Type.Optional(Type.String({ minLength: 1, maxLength: 300 })),
1512
- timezone: Type.Optional(Type.String({ minLength: 1, maxLength: 80 })),
1513
- next_run_at: Type.Optional(
1514
- Type.String({
1515
- minLength: 1,
1516
- description: "Exact ISO timestamp when changing the next run time."
1517
- })
1518
- ),
1519
- recurrence: Type.Optional(
1520
- Type.Union(
1521
- [
1522
- Type.Literal("daily"),
1523
- Type.Literal("weekly"),
1524
- Type.Literal("monthly"),
1525
- Type.Literal("yearly"),
1526
- Type.Null()
1527
- ],
1528
- {
1529
- description: "Provide only for repeating schedules. Omit for one-time requests. Set to null to convert a recurring task to one-time."
1530
- }
1531
- )
1628
+ inputSchema: z7.object({
1629
+ task_id: z7.string().min(1).describe(
1630
+ "ID of the task to update. Must be from this active Slack conversation."
1532
1631
  ),
1533
- status: Type.Optional(
1534
- Type.Union(
1535
- [
1536
- Type.Literal("active"),
1537
- Type.Literal("paused"),
1538
- Type.Literal("blocked")
1539
- ],
1540
- {
1541
- description: "Set to active, paused, or blocked to resume, pause, or block the task."
1542
- }
1543
- )
1544
- )
1632
+ task: z7.string().min(1).max(4e3).optional(),
1633
+ schedule: z7.string().min(1).max(300).optional(),
1634
+ timezone: z7.string().min(1).max(80).optional(),
1635
+ next_run_at: z7.string().min(1).describe("Exact ISO timestamp when changing the next run time.").optional(),
1636
+ recurrence: z7.enum(["daily", "weekly", "monthly", "yearly"]).nullable().describe(
1637
+ "Provide only for repeating schedules. Omit for one-time requests. Set to null to convert a recurring task to one-time."
1638
+ ).optional(),
1639
+ status: z7.enum(["active", "paused", "blocked"]).describe(
1640
+ "Set to active, paused, or blocked to resume, pause, or block the task."
1641
+ ).optional()
1545
1642
  }),
1643
+ outputSchema: scheduleTaskToolResultSchema,
1546
1644
  execute: async (input) => {
1547
1645
  const lookup = await getWritableTask({
1548
1646
  context,
@@ -1591,68 +1689,10 @@ function createSlackScheduleUpdateTaskTool(context) {
1591
1689
  task: input.task ? { text: input.task } : lookup.task
1592
1690
  };
1593
1691
  await schedulerStore(context).saveTask(next);
1594
- return {
1595
- ok: true,
1596
- task: compactTask(next)
1597
- };
1598
- }
1599
- });
1600
- }
1601
- function createSlackScheduleDeleteTaskTool(context) {
1602
- return tool({
1603
- description: "Delete one scheduled Junior task from the active Slack conversation. Use only task IDs returned for this conversation. Do not delete schedules from threads, other channels, or another user's DM.",
1604
- executionMode: "sequential",
1605
- inputSchema: Type.Object({
1606
- task_id: Type.String({
1607
- minLength: 1,
1608
- description: "ID of the task to delete. Must be from this active Slack conversation."
1609
- })
1610
- }),
1611
- execute: async ({ task_id }) => {
1612
- const lookup = await getWritableTask({ context, taskId: task_id });
1613
- const next = {
1614
- ...lookup,
1615
- updatedAtMs: Date.now(),
1616
- status: "deleted",
1617
- nextRunAtMs: void 0,
1618
- runNowAtMs: void 0
1619
- };
1620
- await schedulerStore(context).saveTask(next);
1621
- return {
1622
- ok: true,
1623
- task: compactTask(next)
1624
- };
1625
- }
1626
- });
1627
- }
1628
- function createSlackScheduleRunTaskNowTool(context) {
1629
- return tool({
1630
- description: "Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled task now. Use only task IDs returned for this conversation.",
1631
- executionMode: "sequential",
1632
- inputSchema: Type.Object({
1633
- task_id: Type.String({
1634
- minLength: 1,
1635
- description: "ID of the active task to run now. Must be from this active Slack conversation."
1636
- })
1637
- }),
1638
- execute: async ({ task_id }) => {
1639
- const lookup = await getWritableTask({ context, taskId: task_id });
1640
- if (lookup.status !== "active") {
1641
- throwToolInputError(
1642
- "Scheduled task must be active before it can be run now. Resume the task first if you want it to run."
1643
- );
1644
- }
1645
- const nowMs = Date.now();
1646
- const next = {
1647
- ...lookup,
1648
- updatedAtMs: nowMs,
1649
- runNowAtMs: nowMs
1650
- };
1651
- await schedulerStore(context).saveTask(next);
1652
- return {
1653
- ok: true,
1654
- task: compactTask(next)
1655
- };
1692
+ return scheduleTaskToolResult(
1693
+ "slackScheduleUpdateTask",
1694
+ compactTask(next)
1695
+ );
1656
1696
  }
1657
1697
  });
1658
1698
  }
@@ -1,19 +1,6 @@
1
- import { type PluginCredentialSubject, type PluginToolDefinition, type SlackRequester, type SlackSource } from "@sentry/junior-plugin-api";
2
- import { type SchedulerStore } from "./store";
3
- export interface SchedulerToolContext {
4
- credentialSubject?: PluginCredentialSubject;
5
- requester?: SlackRequester;
6
- source?: SlackSource;
7
- store: SchedulerStore;
8
- userText?: string;
9
- }
10
- /** Create a tool that stores a scheduled task for the active Slack context. */
11
- export declare function createSlackScheduleCreateTaskTool(context: SchedulerToolContext): PluginToolDefinition<any>;
12
- /** Create a tool that lists scheduled tasks for the active Slack conversation. */
13
- export declare function createSlackScheduleListTasksTool(context: SchedulerToolContext): PluginToolDefinition<any>;
14
- /** Create a tool that edits a scheduled task in the active Slack conversation. */
15
- export declare function createSlackScheduleUpdateTaskTool(context: SchedulerToolContext): PluginToolDefinition<any>;
16
- /** Create a tool that removes a scheduled task from the active Slack conversation. */
17
- export declare function createSlackScheduleDeleteTaskTool(context: SchedulerToolContext): PluginToolDefinition<any>;
18
- /** Create a tool that marks an existing scheduled task due immediately. */
19
- export declare function createSlackScheduleRunTaskNowTool(context: SchedulerToolContext): PluginToolDefinition<any>;
1
+ export { createSlackScheduleCreateTaskTool } from "./tools/create-task";
2
+ export { createSlackScheduleDeleteTaskTool } from "./tools/delete-task";
3
+ export { createSlackScheduleListTasksTool } from "./tools/list-tasks";
4
+ export { createSlackScheduleRunTaskNowTool } from "./tools/run-task-now";
5
+ export { createSlackScheduleUpdateTaskTool } from "./tools/update-task";
6
+ export type { SchedulerToolContext } from "./tool-support";