omnius 1.0.25 → 1.0.27
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/README.md +22 -14
- package/dist/index.js +978 -45
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1483,7 +1483,7 @@ var init_security_classifier = __esm({
|
|
|
1483
1483
|
// ── Local writes (fs mutation)
|
|
1484
1484
|
{ match: /^(file_write|file_edit|file_patch|batch_edit|notebook_edit|structured_file|create_structured_file|image_resize)$/, info: LOCAL_WRITE },
|
|
1485
1485
|
{ match: /^(working_notes|todo_write)$/, info: LOCAL_WRITE },
|
|
1486
|
-
{ match: /^(scheduler|reminder|agenda)$/, info: SCHEDULER_REMINDER },
|
|
1486
|
+
{ match: /^(scheduler|cronjob|reminder|remind|reminders|agenda)$/, info: SCHEDULER_REMINDER },
|
|
1487
1487
|
{ match: /^(exploration_culture|explore)$/, info: LOCAL_WRITE },
|
|
1488
1488
|
// ── Task control
|
|
1489
1489
|
{ match: /^(task_status|task_output|task_stop)$/, info: TASK_CONTROL },
|
|
@@ -5763,7 +5763,10 @@ var init_explore_tools = __esm({
|
|
|
5763
5763
|
browser_action: "Interactive browser: login, fill forms, click buttons, screenshot — session persists between calls",
|
|
5764
5764
|
carbonyl_browser: "Terminal-rendered real browser automation via Carbonyl: navigate, read rendered text, click/type, sessions, daemon mode",
|
|
5765
5765
|
scheduler: "Schedule tasks for automatic future execution via OS cron",
|
|
5766
|
-
|
|
5766
|
+
cronjob: "Alias for scheduler: OS cron-backed time triggers",
|
|
5767
|
+
reminder: "Set scoped minimal reminders or scheduled action triggers",
|
|
5768
|
+
remind: "Alias for reminder: create or list scoped reminders",
|
|
5769
|
+
reminders: "Alias for reminder: list and manage scoped reminders",
|
|
5767
5770
|
agenda: "View all pending reminders, scheduled tasks, and attention items",
|
|
5768
5771
|
background_run: "Run a shell command in the background",
|
|
5769
5772
|
task_status: "Check status of background tasks",
|
|
@@ -257491,6 +257494,58 @@ function resolveSchedule(schedule) {
|
|
|
257491
257494
|
const lower = schedule.toLowerCase().trim();
|
|
257492
257495
|
if (SCHEDULE_PRESETS[lower])
|
|
257493
257496
|
return SCHEDULE_PRESETS[lower];
|
|
257497
|
+
const dailyAt = lower.match(/^(?:daily|every\s+day)\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
257498
|
+
if (dailyAt) {
|
|
257499
|
+
const hour2 = parseInt(dailyAt[1], 10);
|
|
257500
|
+
const minute3 = parseInt(dailyAt[2], 10);
|
|
257501
|
+
if (isClockTime(hour2, minute3))
|
|
257502
|
+
return `${minute3} ${hour2} * * *`;
|
|
257503
|
+
}
|
|
257504
|
+
const weeklyAt = lower.match(/^weekly(?:\s+on)?\s+([a-z]+|\d)\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
257505
|
+
if (weeklyAt) {
|
|
257506
|
+
const dow = parseWeekday(weeklyAt[1]);
|
|
257507
|
+
const hour2 = parseInt(weeklyAt[2], 10);
|
|
257508
|
+
const minute3 = parseInt(weeklyAt[3], 10);
|
|
257509
|
+
if (dow !== null && isClockTime(hour2, minute3))
|
|
257510
|
+
return `${minute3} ${hour2} * * ${dow}`;
|
|
257511
|
+
}
|
|
257512
|
+
const monthlyAt = lower.match(/^monthly(?:\s+(?:on|day))?\s+(\d{1,2})(?:st|nd|rd|th)?\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
257513
|
+
if (monthlyAt) {
|
|
257514
|
+
const day = parseInt(monthlyAt[1], 10);
|
|
257515
|
+
const hour2 = parseInt(monthlyAt[2], 10);
|
|
257516
|
+
const minute3 = parseInt(monthlyAt[3], 10);
|
|
257517
|
+
if (day >= 1 && day <= 31 && isClockTime(hour2, minute3))
|
|
257518
|
+
return `${minute3} ${hour2} ${day} * *`;
|
|
257519
|
+
}
|
|
257520
|
+
const yearlyNumeric = lower.match(/^(?:yearly|annually|every\s+year)\s+(?:on\s+)?(\d{1,2})-(\d{1,2})\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
257521
|
+
if (yearlyNumeric) {
|
|
257522
|
+
const month = parseInt(yearlyNumeric[1], 10);
|
|
257523
|
+
const day = parseInt(yearlyNumeric[2], 10);
|
|
257524
|
+
const hour2 = parseInt(yearlyNumeric[3], 10);
|
|
257525
|
+
const minute3 = parseInt(yearlyNumeric[4], 10);
|
|
257526
|
+
if (month >= 1 && month <= 12 && day >= 1 && day <= 31 && isClockTime(hour2, minute3)) {
|
|
257527
|
+
return `${minute3} ${hour2} ${day} ${month} *`;
|
|
257528
|
+
}
|
|
257529
|
+
}
|
|
257530
|
+
const yearlyNamed = lower.match(/^(?:yearly|annually|every\s+year)\s+(?:on\s+)?([a-z]+)\s+(\d{1,2})(?:st|nd|rd|th)?\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
257531
|
+
if (yearlyNamed) {
|
|
257532
|
+
const month = parseMonth(yearlyNamed[1]);
|
|
257533
|
+
const day = parseInt(yearlyNamed[2], 10);
|
|
257534
|
+
const hour2 = parseInt(yearlyNamed[3], 10);
|
|
257535
|
+
const minute3 = parseInt(yearlyNamed[4], 10);
|
|
257536
|
+
if (month !== null && day >= 1 && day <= 31 && isClockTime(hour2, minute3)) {
|
|
257537
|
+
return `${minute3} ${hour2} ${day} ${month} *`;
|
|
257538
|
+
}
|
|
257539
|
+
}
|
|
257540
|
+
const everyLong = lower.match(/^every\s+(\d+)\s*(w|wk|wks|weeks?|mo|mos|months?)$/);
|
|
257541
|
+
if (everyLong) {
|
|
257542
|
+
const amount = parseInt(everyLong[1], 10);
|
|
257543
|
+
const unit = everyLong[2].charAt(0);
|
|
257544
|
+
if (amount > 0 && unit === "w")
|
|
257545
|
+
return `0 9 */${amount * 7} * *`;
|
|
257546
|
+
if (amount > 0 && unit === "m")
|
|
257547
|
+
return `0 9 1 */${amount} *`;
|
|
257548
|
+
}
|
|
257494
257549
|
const inMatch = lower.match(/^in\s+(\d+)\s*(m|min|mins|minutes?|h|hr|hrs|hours?|d|days?)$/);
|
|
257495
257550
|
if (inMatch) {
|
|
257496
257551
|
const amount = parseInt(inMatch[1], 10);
|
|
@@ -257516,6 +257571,65 @@ function resolveSchedule(schedule) {
|
|
|
257516
257571
|
return schedule.trim();
|
|
257517
257572
|
return null;
|
|
257518
257573
|
}
|
|
257574
|
+
function isClockTime(hour2, minute3) {
|
|
257575
|
+
return hour2 >= 0 && hour2 <= 23 && minute3 >= 0 && minute3 <= 59;
|
|
257576
|
+
}
|
|
257577
|
+
function parseWeekday(raw) {
|
|
257578
|
+
const value2 = raw.toLowerCase();
|
|
257579
|
+
if (/^[0-6]$/.test(value2))
|
|
257580
|
+
return Number(value2);
|
|
257581
|
+
const days = {
|
|
257582
|
+
sunday: 0,
|
|
257583
|
+
sun: 0,
|
|
257584
|
+
monday: 1,
|
|
257585
|
+
mon: 1,
|
|
257586
|
+
tuesday: 2,
|
|
257587
|
+
tue: 2,
|
|
257588
|
+
tues: 2,
|
|
257589
|
+
wednesday: 3,
|
|
257590
|
+
wed: 3,
|
|
257591
|
+
thursday: 4,
|
|
257592
|
+
thu: 4,
|
|
257593
|
+
thurs: 4,
|
|
257594
|
+
friday: 5,
|
|
257595
|
+
fri: 5,
|
|
257596
|
+
saturday: 6,
|
|
257597
|
+
sat: 6
|
|
257598
|
+
};
|
|
257599
|
+
return days[value2] ?? null;
|
|
257600
|
+
}
|
|
257601
|
+
function parseMonth(raw) {
|
|
257602
|
+
const value2 = raw.toLowerCase();
|
|
257603
|
+
if (/^(?:[1-9]|1[0-2])$/.test(value2))
|
|
257604
|
+
return Number(value2);
|
|
257605
|
+
const months = {
|
|
257606
|
+
january: 1,
|
|
257607
|
+
jan: 1,
|
|
257608
|
+
february: 2,
|
|
257609
|
+
feb: 2,
|
|
257610
|
+
march: 3,
|
|
257611
|
+
mar: 3,
|
|
257612
|
+
april: 4,
|
|
257613
|
+
apr: 4,
|
|
257614
|
+
may: 5,
|
|
257615
|
+
june: 6,
|
|
257616
|
+
jun: 6,
|
|
257617
|
+
july: 7,
|
|
257618
|
+
jul: 7,
|
|
257619
|
+
august: 8,
|
|
257620
|
+
aug: 8,
|
|
257621
|
+
september: 9,
|
|
257622
|
+
sep: 9,
|
|
257623
|
+
sept: 9,
|
|
257624
|
+
october: 10,
|
|
257625
|
+
oct: 10,
|
|
257626
|
+
november: 11,
|
|
257627
|
+
nov: 11,
|
|
257628
|
+
december: 12,
|
|
257629
|
+
dec: 12
|
|
257630
|
+
};
|
|
257631
|
+
return months[value2] ?? null;
|
|
257632
|
+
}
|
|
257519
257633
|
function describeCron(expr) {
|
|
257520
257634
|
const parts = expr.split(/\s+/);
|
|
257521
257635
|
if (parts.length !== 5)
|
|
@@ -257705,12 +257819,14 @@ var init_scheduler = __esm({
|
|
|
257705
257819
|
"daily evening": "0 18 * * *",
|
|
257706
257820
|
"weekly": "0 9 * * 1",
|
|
257707
257821
|
"monthly": "0 9 1 * *",
|
|
257822
|
+
"yearly": "0 9 1 1 *",
|
|
257823
|
+
"annually": "0 9 1 1 *",
|
|
257708
257824
|
"hourly": "0 * * * *"
|
|
257709
257825
|
};
|
|
257710
257826
|
CRON_MARKER = "# OMNIUS-SCHEDULED:";
|
|
257711
257827
|
SchedulerTool = class {
|
|
257712
257828
|
name = "scheduler";
|
|
257713
|
-
description = "Schedule tasks for automatic future execution using OS-level cron. Actions: 'create' a new scheduled task, 'list' all scheduled tasks, 'cancel' a task by ID, 'pause'/'resume' a task. Schedules: use presets ('daily', '
|
|
257829
|
+
description = "Schedule tasks for automatic future execution using OS-level cron. Actions: 'create' a new scheduled task, 'list' all scheduled tasks, 'cancel' a task by ID, 'pause'/'resume' a task. Schedules: use presets ('daily', 'weekly', 'monthly', 'yearly'), intervals ('every 5 minutes'), 24-hour times ('at 14:30', 'weekly friday at 17:45', 'monthly on 15 at 08:30'), or raw cron expressions ('0 */2 * * *'). Scope: 'local' (default, stored in .omnius/) or 'global' (stored in ~/.omnius/, visible from all projects). Tasks launch the agent automatically at the scheduled time.";
|
|
257714
257830
|
parameters = {
|
|
257715
257831
|
type: "object",
|
|
257716
257832
|
properties: {
|
|
@@ -257725,7 +257841,7 @@ var init_scheduler = __esm({
|
|
|
257725
257841
|
},
|
|
257726
257842
|
schedule: {
|
|
257727
257843
|
type: "string",
|
|
257728
|
-
description: "When to run: preset ('daily', 'every 5 minutes'),
|
|
257844
|
+
description: "When to run: preset ('daily', 'weekly', 'monthly', 'yearly'), interval ('every 5 minutes'), 24-hour time ('at 14:30', 'weekly friday at 17:45'), or cron ('0 */2 * * *')"
|
|
257729
257845
|
},
|
|
257730
257846
|
id: {
|
|
257731
257847
|
type: "string",
|
|
@@ -258027,6 +258143,219 @@ function parseDueTime(due) {
|
|
|
258027
258143
|
}
|
|
258028
258144
|
return null;
|
|
258029
258145
|
}
|
|
258146
|
+
function parseDurationMs(input) {
|
|
258147
|
+
const lower = input.toLowerCase().trim();
|
|
258148
|
+
const match = lower.match(/^(?:every\s+)?(\d+)\s*(m|min|mins|minutes?|h|hr|hrs|hours?|d|days?|w|wk|wks|weeks?)$/);
|
|
258149
|
+
if (!match)
|
|
258150
|
+
return null;
|
|
258151
|
+
const amount = parseInt(match[1], 10);
|
|
258152
|
+
if (!Number.isFinite(amount) || amount <= 0)
|
|
258153
|
+
return null;
|
|
258154
|
+
const unit = match[2].charAt(0);
|
|
258155
|
+
const ms = unit === "m" ? amount * 6e4 : unit === "h" ? amount * 36e5 : unit === "d" ? amount * 864e5 : amount * 7 * 864e5;
|
|
258156
|
+
return {
|
|
258157
|
+
ms,
|
|
258158
|
+
description: `every ${amount} ${unit === "m" ? "minute" : unit === "h" ? "hour" : unit === "d" ? "day" : "week"}${amount === 1 ? "" : "s"}`
|
|
258159
|
+
};
|
|
258160
|
+
}
|
|
258161
|
+
function parseTimeOfDay(value2) {
|
|
258162
|
+
const raw = String(value2 ?? "").trim();
|
|
258163
|
+
const match = raw.match(/^(\d{1,2}):(\d{2})$/);
|
|
258164
|
+
if (!match)
|
|
258165
|
+
return void 0;
|
|
258166
|
+
const hour2 = parseInt(match[1], 10);
|
|
258167
|
+
const minute3 = parseInt(match[2], 10);
|
|
258168
|
+
if (hour2 < 0 || hour2 > 23 || minute3 < 0 || minute3 > 59)
|
|
258169
|
+
return void 0;
|
|
258170
|
+
return `${String(hour2).padStart(2, "0")}:${String(minute3).padStart(2, "0")}`;
|
|
258171
|
+
}
|
|
258172
|
+
function parseWeekday2(value2) {
|
|
258173
|
+
if (typeof value2 === "number" && Number.isFinite(value2)) {
|
|
258174
|
+
const day = Math.trunc(value2);
|
|
258175
|
+
return day >= 0 && day <= 6 ? day : void 0;
|
|
258176
|
+
}
|
|
258177
|
+
const raw = String(value2 ?? "").trim().toLowerCase();
|
|
258178
|
+
if (!raw)
|
|
258179
|
+
return void 0;
|
|
258180
|
+
const names = {
|
|
258181
|
+
sunday: 0,
|
|
258182
|
+
sun: 0,
|
|
258183
|
+
monday: 1,
|
|
258184
|
+
mon: 1,
|
|
258185
|
+
tuesday: 2,
|
|
258186
|
+
tue: 2,
|
|
258187
|
+
tues: 2,
|
|
258188
|
+
wednesday: 3,
|
|
258189
|
+
wed: 3,
|
|
258190
|
+
thursday: 4,
|
|
258191
|
+
thu: 4,
|
|
258192
|
+
thurs: 4,
|
|
258193
|
+
friday: 5,
|
|
258194
|
+
fri: 5,
|
|
258195
|
+
saturday: 6,
|
|
258196
|
+
sat: 6
|
|
258197
|
+
};
|
|
258198
|
+
if (/^[0-6]$/.test(raw))
|
|
258199
|
+
return Number(raw);
|
|
258200
|
+
return names[raw];
|
|
258201
|
+
}
|
|
258202
|
+
function parseMonth2(value2) {
|
|
258203
|
+
if (typeof value2 === "number" && Number.isFinite(value2)) {
|
|
258204
|
+
const month = Math.trunc(value2);
|
|
258205
|
+
return month >= 1 && month <= 12 ? month : void 0;
|
|
258206
|
+
}
|
|
258207
|
+
const raw = String(value2 ?? "").trim().toLowerCase();
|
|
258208
|
+
if (!raw)
|
|
258209
|
+
return void 0;
|
|
258210
|
+
const names = {
|
|
258211
|
+
january: 1,
|
|
258212
|
+
jan: 1,
|
|
258213
|
+
february: 2,
|
|
258214
|
+
feb: 2,
|
|
258215
|
+
march: 3,
|
|
258216
|
+
mar: 3,
|
|
258217
|
+
april: 4,
|
|
258218
|
+
apr: 4,
|
|
258219
|
+
may: 5,
|
|
258220
|
+
june: 6,
|
|
258221
|
+
jun: 6,
|
|
258222
|
+
july: 7,
|
|
258223
|
+
jul: 7,
|
|
258224
|
+
august: 8,
|
|
258225
|
+
aug: 8,
|
|
258226
|
+
september: 9,
|
|
258227
|
+
sep: 9,
|
|
258228
|
+
sept: 9,
|
|
258229
|
+
october: 10,
|
|
258230
|
+
oct: 10,
|
|
258231
|
+
november: 11,
|
|
258232
|
+
nov: 11,
|
|
258233
|
+
december: 12,
|
|
258234
|
+
dec: 12
|
|
258235
|
+
};
|
|
258236
|
+
if (/^(?:[1-9]|1[0-2])$/.test(raw))
|
|
258237
|
+
return Number(raw);
|
|
258238
|
+
return names[raw];
|
|
258239
|
+
}
|
|
258240
|
+
function parseRecurrence(args) {
|
|
258241
|
+
const repeatRaw = String(args["repeat"] ?? args["recurrence"] ?? "").trim();
|
|
258242
|
+
if (!repeatRaw)
|
|
258243
|
+
return void 0;
|
|
258244
|
+
const lower = repeatRaw.toLowerCase();
|
|
258245
|
+
if (["none", "off", "false", "no"].includes(lower))
|
|
258246
|
+
return void 0;
|
|
258247
|
+
const maxOccurrences = typeof args["max_occurrences"] === "number" && Number.isFinite(args["max_occurrences"]) ? Math.max(1, Math.floor(args["max_occurrences"])) : typeof args["max_runs"] === "number" && Number.isFinite(args["max_runs"]) ? Math.max(1, Math.floor(args["max_runs"])) : void 0;
|
|
258248
|
+
const intervalInput = lower.startsWith("every ") ? lower : String(args["every"] ?? "").trim().toLowerCase();
|
|
258249
|
+
const interval = parseDurationMs(intervalInput);
|
|
258250
|
+
if (interval) {
|
|
258251
|
+
return {
|
|
258252
|
+
kind: "interval",
|
|
258253
|
+
everyMs: interval.ms,
|
|
258254
|
+
intervalDescription: interval.description,
|
|
258255
|
+
...maxOccurrences ? { maxOccurrences } : {}
|
|
258256
|
+
};
|
|
258257
|
+
}
|
|
258258
|
+
const repeatTime = lower.match(/\bat\s+(\d{1,2}:\d{2})\b/)?.[1];
|
|
258259
|
+
const timeOfDay = parseTimeOfDay(args["time"]) ?? parseTimeOfDay(args["at"]) ?? parseTimeOfDay(repeatTime);
|
|
258260
|
+
const withMax = (recurrence) => maxOccurrences ? { ...recurrence, maxOccurrences } : recurrence;
|
|
258261
|
+
if (lower === "daily" || lower === "every day") {
|
|
258262
|
+
return withMax({ kind: "daily", timeOfDay: timeOfDay ?? "09:00" });
|
|
258263
|
+
}
|
|
258264
|
+
if (lower.startsWith("weekly") || lower === "every week") {
|
|
258265
|
+
const dayFromText = lower.match(/\b(sun(?:day)?|mon(?:day)?|tue(?:s|sday)?|wed(?:nesday)?|thu(?:rs|rsday)?|fri(?:day)?|sat(?:urday)?)\b/i)?.[1];
|
|
258266
|
+
return withMax({
|
|
258267
|
+
kind: "weekly",
|
|
258268
|
+
weekday: parseWeekday2(args["weekday"] ?? dayFromText) ?? 1,
|
|
258269
|
+
timeOfDay: timeOfDay ?? "09:00"
|
|
258270
|
+
});
|
|
258271
|
+
}
|
|
258272
|
+
if (lower.startsWith("monthly") || lower === "every month") {
|
|
258273
|
+
const dayRaw = args["day_of_month"] ?? args["day"] ?? lower.match(/\b(?:day|on)\s+(\d{1,2})\b/)?.[1];
|
|
258274
|
+
const day = typeof dayRaw === "number" ? Math.trunc(dayRaw) : parseInt(String(dayRaw ?? "1"), 10);
|
|
258275
|
+
return withMax({
|
|
258276
|
+
kind: "monthly",
|
|
258277
|
+
dayOfMonth: Math.max(1, Math.min(31, Number.isFinite(day) ? day : 1)),
|
|
258278
|
+
timeOfDay: timeOfDay ?? "09:00"
|
|
258279
|
+
});
|
|
258280
|
+
}
|
|
258281
|
+
if (lower.startsWith("yearly") || lower === "annually" || lower === "every year") {
|
|
258282
|
+
const yearlyText = lower.match(/\b(jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t|tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?|\d{1,2})\s+(\d{1,2})(?:st|nd|rd|th)?\b/i);
|
|
258283
|
+
const month = parseMonth2(args["month"] ?? yearlyText?.[1]) ?? 1;
|
|
258284
|
+
const dayRaw = args["day_of_month"] ?? args["day"] ?? yearlyText?.[2] ?? 1;
|
|
258285
|
+
const day = typeof dayRaw === "number" ? Math.trunc(dayRaw) : parseInt(String(dayRaw), 10);
|
|
258286
|
+
return withMax({
|
|
258287
|
+
kind: "yearly",
|
|
258288
|
+
month,
|
|
258289
|
+
dayOfMonth: Math.max(1, Math.min(31, Number.isFinite(day) ? day : 1)),
|
|
258290
|
+
timeOfDay: timeOfDay ?? "09:00"
|
|
258291
|
+
});
|
|
258292
|
+
}
|
|
258293
|
+
return null;
|
|
258294
|
+
}
|
|
258295
|
+
function setLocalTime(target, timeOfDay, fallback = "09:00") {
|
|
258296
|
+
const [hourRaw, minuteRaw] = (timeOfDay ?? fallback).split(":");
|
|
258297
|
+
target.setHours(parseInt(hourRaw ?? "9", 10), parseInt(minuteRaw ?? "0", 10), 0, 0);
|
|
258298
|
+
}
|
|
258299
|
+
function clampDateToMonth(target, dayOfMonth) {
|
|
258300
|
+
target.setDate(1);
|
|
258301
|
+
const maxDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
258302
|
+
target.setDate(Math.min(Math.max(1, dayOfMonth), maxDay));
|
|
258303
|
+
}
|
|
258304
|
+
function nextDueFromRecurrence(recurrence, after = /* @__PURE__ */ new Date()) {
|
|
258305
|
+
const target = new Date(after);
|
|
258306
|
+
switch (recurrence.kind) {
|
|
258307
|
+
case "interval":
|
|
258308
|
+
return new Date(after.getTime() + Math.max(6e4, recurrence.everyMs ?? 864e5));
|
|
258309
|
+
case "daily":
|
|
258310
|
+
setLocalTime(target, recurrence.timeOfDay);
|
|
258311
|
+
if (target <= after)
|
|
258312
|
+
target.setDate(target.getDate() + 1);
|
|
258313
|
+
return target;
|
|
258314
|
+
case "weekly": {
|
|
258315
|
+
setLocalTime(target, recurrence.timeOfDay);
|
|
258316
|
+
const weekday = recurrence.weekday ?? 1;
|
|
258317
|
+
const daysAhead = (weekday - target.getDay() + 7) % 7;
|
|
258318
|
+
target.setDate(target.getDate() + daysAhead);
|
|
258319
|
+
if (target <= after)
|
|
258320
|
+
target.setDate(target.getDate() + 7);
|
|
258321
|
+
return target;
|
|
258322
|
+
}
|
|
258323
|
+
case "monthly":
|
|
258324
|
+
setLocalTime(target, recurrence.timeOfDay);
|
|
258325
|
+
clampDateToMonth(target, recurrence.dayOfMonth ?? 1);
|
|
258326
|
+
if (target <= after) {
|
|
258327
|
+
target.setMonth(target.getMonth() + 1);
|
|
258328
|
+
clampDateToMonth(target, recurrence.dayOfMonth ?? 1);
|
|
258329
|
+
}
|
|
258330
|
+
return target;
|
|
258331
|
+
case "yearly":
|
|
258332
|
+
target.setMonth((recurrence.month ?? 1) - 1, 1);
|
|
258333
|
+
clampDateToMonth(target, recurrence.dayOfMonth ?? 1);
|
|
258334
|
+
setLocalTime(target, recurrence.timeOfDay);
|
|
258335
|
+
if (target <= after) {
|
|
258336
|
+
target.setFullYear(target.getFullYear() + 1);
|
|
258337
|
+
target.setMonth((recurrence.month ?? 1) - 1, 1);
|
|
258338
|
+
clampDateToMonth(target, recurrence.dayOfMonth ?? 1);
|
|
258339
|
+
}
|
|
258340
|
+
return target;
|
|
258341
|
+
}
|
|
258342
|
+
}
|
|
258343
|
+
function describeRecurrence(recurrence) {
|
|
258344
|
+
if (!recurrence)
|
|
258345
|
+
return void 0;
|
|
258346
|
+
switch (recurrence.kind) {
|
|
258347
|
+
case "interval":
|
|
258348
|
+
return recurrence.intervalDescription ?? `every ${Math.round((recurrence.everyMs ?? 0) / 6e4)} minutes`;
|
|
258349
|
+
case "daily":
|
|
258350
|
+
return `daily at ${recurrence.timeOfDay ?? "09:00"}`;
|
|
258351
|
+
case "weekly":
|
|
258352
|
+
return `weekly on day ${recurrence.weekday ?? 1} at ${recurrence.timeOfDay ?? "09:00"}`;
|
|
258353
|
+
case "monthly":
|
|
258354
|
+
return `monthly on day ${recurrence.dayOfMonth ?? 1} at ${recurrence.timeOfDay ?? "09:00"}`;
|
|
258355
|
+
case "yearly":
|
|
258356
|
+
return `yearly on ${String(recurrence.month ?? 1).padStart(2, "0")}-${String(recurrence.dayOfMonth ?? 1).padStart(2, "0")} at ${recurrence.timeOfDay ?? "09:00"}`;
|
|
258357
|
+
}
|
|
258358
|
+
}
|
|
258030
258359
|
async function getStorePath(workingDir) {
|
|
258031
258360
|
const dir = resolve26(workingDir, ".omnius", "scheduled");
|
|
258032
258361
|
await mkdir14(dir, { recursive: true });
|
|
@@ -258046,28 +258375,77 @@ async function saveReminderStore(workingDir, store2) {
|
|
|
258046
258375
|
store2.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
258047
258376
|
await writeFile19(storePath, JSON.stringify(store2, null, 2), "utf-8");
|
|
258048
258377
|
}
|
|
258049
|
-
async function getDueReminders(workingDir) {
|
|
258378
|
+
async function getDueReminders(workingDir, query = {}) {
|
|
258050
258379
|
const store2 = await loadReminderStore(workingDir);
|
|
258051
|
-
const now = /* @__PURE__ */ new Date();
|
|
258380
|
+
const now = query.now ?? /* @__PURE__ */ new Date();
|
|
258052
258381
|
return store2.reminders.filter((r2) => {
|
|
258053
258382
|
if (r2.status !== "pending")
|
|
258054
258383
|
return false;
|
|
258055
|
-
if (
|
|
258056
|
-
return
|
|
258057
|
-
|
|
258384
|
+
if (r2.dueAt && new Date(r2.dueAt) > now)
|
|
258385
|
+
return false;
|
|
258386
|
+
if (query.deliveryMode && query.deliveryMode !== "any" && (r2.delivery?.mode ?? "minimal") !== query.deliveryMode)
|
|
258387
|
+
return false;
|
|
258388
|
+
if (query.scope && !reminderScopeMatches(r2.scope, query.scope, query.includeUnscoped === true))
|
|
258389
|
+
return false;
|
|
258390
|
+
return true;
|
|
258058
258391
|
});
|
|
258059
258392
|
}
|
|
258060
258393
|
async function markRemindersSeen(workingDir, ids) {
|
|
258394
|
+
await markRemindersTriggered(workingDir, ids);
|
|
258395
|
+
}
|
|
258396
|
+
async function markRemindersTriggered(workingDir, ids, now = /* @__PURE__ */ new Date()) {
|
|
258061
258397
|
const store2 = await loadReminderStore(workingDir);
|
|
258062
258398
|
const idSet = new Set(ids);
|
|
258063
258399
|
for (const r2 of store2.reminders) {
|
|
258064
258400
|
if (idSet.has(r2.id) && r2.status === "pending") {
|
|
258065
|
-
r2.
|
|
258066
|
-
r2.
|
|
258401
|
+
r2.lastTriggeredAt = now.toISOString();
|
|
258402
|
+
r2.triggerCount = (r2.triggerCount ?? 0) + 1;
|
|
258403
|
+
const max = r2.recurrence?.maxOccurrences;
|
|
258404
|
+
if (r2.recurrence && (!max || r2.triggerCount < max)) {
|
|
258405
|
+
r2.dueAt = nextDueFromRecurrence(r2.recurrence, now).toISOString();
|
|
258406
|
+
r2.dueDescription = describeRecurrence(r2.recurrence);
|
|
258407
|
+
r2.seenAt = void 0;
|
|
258408
|
+
} else {
|
|
258409
|
+
r2.status = "seen";
|
|
258410
|
+
r2.seenAt = now.toISOString();
|
|
258411
|
+
}
|
|
258067
258412
|
}
|
|
258068
258413
|
}
|
|
258069
258414
|
await saveReminderStore(workingDir, store2);
|
|
258070
258415
|
}
|
|
258416
|
+
function reminderScopeMatches(scope, query, includeUnscoped) {
|
|
258417
|
+
if (!scope)
|
|
258418
|
+
return includeUnscoped;
|
|
258419
|
+
const keys = ["surface", "visibility", "targetId", "sessionId", "chatId", "threadId", "userId", "username", "label"];
|
|
258420
|
+
for (const key of keys) {
|
|
258421
|
+
const expected = query[key];
|
|
258422
|
+
if (expected !== void 0 && scope[key] !== expected)
|
|
258423
|
+
return false;
|
|
258424
|
+
}
|
|
258425
|
+
return true;
|
|
258426
|
+
}
|
|
258427
|
+
function normalizeDeliveryKind(value2) {
|
|
258428
|
+
const raw = String(value2 ?? "").trim().toLowerCase();
|
|
258429
|
+
if (raw === "action" || raw === "agent" || raw === "agent_action")
|
|
258430
|
+
return "action";
|
|
258431
|
+
return "minimal";
|
|
258432
|
+
}
|
|
258433
|
+
function normalizeSurface(value2) {
|
|
258434
|
+
const raw = String(value2 ?? "").trim().toLowerCase();
|
|
258435
|
+
return raw === "tui" || raw === "gui" || raw === "telegram" || raw === "api" || raw === "global" ? raw : void 0;
|
|
258436
|
+
}
|
|
258437
|
+
function normalizeVisibility(value2) {
|
|
258438
|
+
const raw = String(value2 ?? "").trim().toLowerCase();
|
|
258439
|
+
return raw === "private" || raw === "public" ? raw : void 0;
|
|
258440
|
+
}
|
|
258441
|
+
function stringValue(value2) {
|
|
258442
|
+
const raw = String(value2 ?? "").trim();
|
|
258443
|
+
return raw || void 0;
|
|
258444
|
+
}
|
|
258445
|
+
function formatScope(scope) {
|
|
258446
|
+
const label = scope.label ? ` (${scope.label})` : "";
|
|
258447
|
+
return `${scope.surface}/${scope.visibility}/${scope.targetId}${label}`;
|
|
258448
|
+
}
|
|
258071
258449
|
var STORE_FILE, ReminderTool;
|
|
258072
258450
|
var init_reminder = __esm({
|
|
258073
258451
|
"packages/execution/dist/tools/reminder.js"() {
|
|
@@ -258075,7 +258453,7 @@ var init_reminder = __esm({
|
|
|
258075
258453
|
STORE_FILE = "reminders.json";
|
|
258076
258454
|
ReminderTool = class {
|
|
258077
258455
|
name = "reminder";
|
|
258078
|
-
description = "Set reminders
|
|
258456
|
+
description = "Set scoped reminders and time-triggered action requests. Use kind='minimal' for raw text/content delivery and kind='action' when the trigger should start inference/tool-calling from a task_description. Actions: 'set' a new reminder, 'list' all reminders, 'complete' or 'dismiss' a reminder, 'snooze' to postpone. Reminders can have due dates, recurrence, priority, tags, and per-platform scopes.";
|
|
258079
258457
|
parameters = {
|
|
258080
258458
|
type: "object",
|
|
258081
258459
|
properties: {
|
|
@@ -258097,6 +258475,43 @@ var init_reminder = __esm({
|
|
|
258097
258475
|
enum: ["low", "normal", "high", "critical"],
|
|
258098
258476
|
description: "Priority level (default: normal)"
|
|
258099
258477
|
},
|
|
258478
|
+
kind: {
|
|
258479
|
+
type: "string",
|
|
258480
|
+
enum: ["minimal", "action"],
|
|
258481
|
+
description: "minimal sends raw reminder text/content only. action triggers an inference/tool-call task using task_description."
|
|
258482
|
+
},
|
|
258483
|
+
task_description: {
|
|
258484
|
+
type: "string",
|
|
258485
|
+
description: "For kind='action': the task the agent should perform when the trigger fires."
|
|
258486
|
+
},
|
|
258487
|
+
content: {
|
|
258488
|
+
type: "string",
|
|
258489
|
+
description: "For kind='minimal': raw text/content to deliver. Defaults to message."
|
|
258490
|
+
},
|
|
258491
|
+
repeat: {
|
|
258492
|
+
type: "string",
|
|
258493
|
+
description: "Optional recurrence: 'every 30m', 'daily', 'weekly monday', 'monthly', 'yearly'."
|
|
258494
|
+
},
|
|
258495
|
+
time: {
|
|
258496
|
+
type: "string",
|
|
258497
|
+
description: "24-hour local time HH:MM for daily/weekly/monthly/yearly recurrence."
|
|
258498
|
+
},
|
|
258499
|
+
weekday: {
|
|
258500
|
+
type: "string",
|
|
258501
|
+
description: "Weekday for weekly recurrence, e.g. 'monday' or 1."
|
|
258502
|
+
},
|
|
258503
|
+
day_of_month: {
|
|
258504
|
+
type: "number",
|
|
258505
|
+
description: "Day of month for monthly/yearly recurrence."
|
|
258506
|
+
},
|
|
258507
|
+
month: {
|
|
258508
|
+
type: "string",
|
|
258509
|
+
description: "Month for yearly recurrence, e.g. 'january' or 1."
|
|
258510
|
+
},
|
|
258511
|
+
max_occurrences: {
|
|
258512
|
+
type: "number",
|
|
258513
|
+
description: "Optional cap for recurring reminders."
|
|
258514
|
+
},
|
|
258100
258515
|
tags: {
|
|
258101
258516
|
type: "string",
|
|
258102
258517
|
description: "Comma-separated tags for categorization (e.g. 'deploy,auth,urgent')"
|
|
@@ -258112,13 +258527,29 @@ var init_reminder = __esm({
|
|
|
258112
258527
|
filter: {
|
|
258113
258528
|
type: "string",
|
|
258114
258529
|
description: "Filter by status: 'pending', 'seen', 'all' (for 'list', default: 'pending')"
|
|
258530
|
+
},
|
|
258531
|
+
surface: {
|
|
258532
|
+
type: "string",
|
|
258533
|
+
enum: ["tui", "gui", "telegram", "api", "global"],
|
|
258534
|
+
description: "Optional scope surface. Ignored when this tool is context-locked by a platform adapter."
|
|
258535
|
+
},
|
|
258536
|
+
visibility: {
|
|
258537
|
+
type: "string",
|
|
258538
|
+
enum: ["private", "public"],
|
|
258539
|
+
description: "Optional scope visibility. Ignored when context-locked."
|
|
258540
|
+
},
|
|
258541
|
+
target_id: {
|
|
258542
|
+
type: "string",
|
|
258543
|
+
description: "Optional scope target id. For Telegram this is the chat id. Ignored when context-locked."
|
|
258115
258544
|
}
|
|
258116
258545
|
},
|
|
258117
258546
|
required: ["action"]
|
|
258118
258547
|
};
|
|
258119
258548
|
workingDir;
|
|
258120
|
-
|
|
258549
|
+
options;
|
|
258550
|
+
constructor(workingDir, options2 = {}) {
|
|
258121
258551
|
this.workingDir = workingDir;
|
|
258552
|
+
this.options = options2;
|
|
258122
258553
|
}
|
|
258123
258554
|
async execute(args) {
|
|
258124
258555
|
const start2 = performance.now();
|
|
@@ -258161,6 +258592,33 @@ var init_reminder = __esm({
|
|
|
258161
258592
|
const tags = tagsStr ? tagsStr.split(",").map((t2) => t2.trim()).filter(Boolean) : [];
|
|
258162
258593
|
const context2 = args["context"] ?? void 0;
|
|
258163
258594
|
const dueStr = args["due"] ?? "";
|
|
258595
|
+
const recurrence = parseRecurrence(args);
|
|
258596
|
+
if (recurrence === null) {
|
|
258597
|
+
return {
|
|
258598
|
+
success: false,
|
|
258599
|
+
output: "",
|
|
258600
|
+
error: `Cannot parse repeat '${String(args["repeat"] ?? args["recurrence"])}'. Try: 'every 30m', 'daily', 'weekly monday', 'monthly', or 'yearly'.`,
|
|
258601
|
+
durationMs: performance.now() - start2
|
|
258602
|
+
};
|
|
258603
|
+
}
|
|
258604
|
+
const kind = normalizeDeliveryKind(args["kind"] ?? args["mode"] ?? args["delivery"]);
|
|
258605
|
+
if (kind === "action" && !this.options.allowActionDelivery) {
|
|
258606
|
+
return {
|
|
258607
|
+
success: false,
|
|
258608
|
+
output: "",
|
|
258609
|
+
error: "kind='action' is not allowed in this context. Use kind='minimal' for a plain reminder.",
|
|
258610
|
+
durationMs: performance.now() - start2
|
|
258611
|
+
};
|
|
258612
|
+
}
|
|
258613
|
+
const taskDescription = String(args["task_description"] ?? args["task"] ?? args["prompt"] ?? "").trim();
|
|
258614
|
+
if (kind === "action" && !taskDescription) {
|
|
258615
|
+
return {
|
|
258616
|
+
success: false,
|
|
258617
|
+
output: "",
|
|
258618
|
+
error: "task_description is required when kind='action'",
|
|
258619
|
+
durationMs: performance.now() - start2
|
|
258620
|
+
};
|
|
258621
|
+
}
|
|
258164
258622
|
let dueAt;
|
|
258165
258623
|
let dueDescription;
|
|
258166
258624
|
if (dueStr) {
|
|
@@ -258175,7 +258633,12 @@ var init_reminder = __esm({
|
|
|
258175
258633
|
}
|
|
258176
258634
|
dueAt = parsed.isoDate;
|
|
258177
258635
|
dueDescription = parsed.description;
|
|
258636
|
+
} else if (recurrence) {
|
|
258637
|
+
dueAt = nextDueFromRecurrence(recurrence).toISOString();
|
|
258638
|
+
dueDescription = describeRecurrence(recurrence);
|
|
258178
258639
|
}
|
|
258640
|
+
const scope = this.resolveScope(args);
|
|
258641
|
+
const content = String(args["content"] ?? message2).trim() || message2;
|
|
258179
258642
|
const id = `rem-${randomBytes12(4).toString("hex")}`;
|
|
258180
258643
|
const entry = {
|
|
258181
258644
|
id,
|
|
@@ -258187,7 +258650,14 @@ var init_reminder = __esm({
|
|
|
258187
258650
|
tags,
|
|
258188
258651
|
status: "pending",
|
|
258189
258652
|
context: context2,
|
|
258190
|
-
source: "agent"
|
|
258653
|
+
source: this.options.source ?? "agent",
|
|
258654
|
+
...scope ? { scope } : {},
|
|
258655
|
+
delivery: {
|
|
258656
|
+
mode: kind,
|
|
258657
|
+
...kind === "action" ? { taskDescription } : { content },
|
|
258658
|
+
...this.options.createdFrom ? { createdFrom: this.options.createdFrom } : {}
|
|
258659
|
+
},
|
|
258660
|
+
...recurrence ? { recurrence } : {}
|
|
258191
258661
|
};
|
|
258192
258662
|
const store2 = await loadReminderStore(this.workingDir);
|
|
258193
258663
|
store2.reminders.push(entry);
|
|
@@ -258199,11 +258669,15 @@ var init_reminder = __esm({
|
|
|
258199
258669
|
` ID: ${id}`,
|
|
258200
258670
|
` Message: ${message2}`,
|
|
258201
258671
|
` Priority: ${priority}`,
|
|
258672
|
+
` Kind: ${kind}`,
|
|
258673
|
+
kind === "action" ? ` Task: ${taskDescription}` : "",
|
|
258202
258674
|
dueDescription ? ` Due: ${dueDescription}` : ` Due: next startup`,
|
|
258675
|
+
describeRecurrence(recurrence) ? ` Repeats: ${describeRecurrence(recurrence)}` : "",
|
|
258676
|
+
scope ? ` Scope: ${formatScope(scope)}` : "",
|
|
258203
258677
|
tags.length > 0 ? ` Tags: ${tags.join(", ")}` : "",
|
|
258204
258678
|
context2 ? ` Context: ${context2.slice(0, 100)}` : "",
|
|
258205
258679
|
``,
|
|
258206
|
-
`This
|
|
258680
|
+
kind === "action" ? `This action will trigger when due${dueDescription ? ` (${dueDescription})` : ""}.` : `This reminder will surface when due${dueDescription ? ` (${dueDescription})` : ""}.`
|
|
258207
258681
|
].filter(Boolean).join("\n"),
|
|
258208
258682
|
durationMs: performance.now() - start2
|
|
258209
258683
|
};
|
|
@@ -258232,8 +258706,14 @@ var init_reminder = __esm({
|
|
|
258232
258706
|
const statusLabel = r2.status === "seen" ? " (seen)" : r2.status === "completed" ? " (done)" : r2.status === "dismissed" ? " (dismissed)" : "";
|
|
258233
258707
|
lines.push(` ${priorityIcon} [${r2.id}]${statusLabel}`);
|
|
258234
258708
|
lines.push(` ${r2.message}`);
|
|
258709
|
+
lines.push(` Kind: ${r2.delivery?.mode ?? "minimal"}`);
|
|
258235
258710
|
if (r2.dueDescription)
|
|
258236
258711
|
lines.push(` Due: ${r2.dueDescription}`);
|
|
258712
|
+
const recurrence = describeRecurrence(r2.recurrence);
|
|
258713
|
+
if (recurrence)
|
|
258714
|
+
lines.push(` Repeats: ${recurrence}`);
|
|
258715
|
+
if (r2.scope)
|
|
258716
|
+
lines.push(` Scope: ${formatScope(r2.scope)}`);
|
|
258237
258717
|
if (r2.tags.length > 0)
|
|
258238
258718
|
lines.push(` Tags: ${r2.tags.join(", ")}`);
|
|
258239
258719
|
if (r2.context)
|
|
@@ -258285,6 +258765,26 @@ var init_reminder = __esm({
|
|
|
258285
258765
|
durationMs: performance.now() - start2
|
|
258286
258766
|
};
|
|
258287
258767
|
}
|
|
258768
|
+
resolveScope(args) {
|
|
258769
|
+
if (this.options.lockScope)
|
|
258770
|
+
return this.options.defaultScope;
|
|
258771
|
+
const surface = normalizeSurface(args["surface"]) ?? this.options.defaultScope?.surface;
|
|
258772
|
+
const visibility = normalizeVisibility(args["visibility"]) ?? this.options.defaultScope?.visibility ?? "private";
|
|
258773
|
+
const targetId = String(args["target_id"] ?? args["targetId"] ?? this.options.defaultScope?.targetId ?? "").trim();
|
|
258774
|
+
if (!surface || !targetId)
|
|
258775
|
+
return this.options.defaultScope;
|
|
258776
|
+
return {
|
|
258777
|
+
surface,
|
|
258778
|
+
visibility,
|
|
258779
|
+
targetId,
|
|
258780
|
+
sessionId: stringValue(args["session_id"] ?? args["sessionId"] ?? this.options.defaultScope?.sessionId),
|
|
258781
|
+
chatId: stringValue(args["chat_id"] ?? args["chatId"] ?? this.options.defaultScope?.chatId),
|
|
258782
|
+
threadId: stringValue(args["thread_id"] ?? args["threadId"] ?? this.options.defaultScope?.threadId),
|
|
258783
|
+
userId: stringValue(args["user_id"] ?? args["userId"] ?? this.options.defaultScope?.userId),
|
|
258784
|
+
username: stringValue(args["username"] ?? this.options.defaultScope?.username),
|
|
258785
|
+
label: stringValue(args["label"] ?? this.options.defaultScope?.label)
|
|
258786
|
+
};
|
|
258787
|
+
}
|
|
258288
258788
|
};
|
|
258289
258789
|
}
|
|
258290
258790
|
});
|
|
@@ -258613,6 +259113,23 @@ ${sections.join("\n")}`,
|
|
|
258613
259113
|
}
|
|
258614
259114
|
});
|
|
258615
259115
|
|
|
259116
|
+
// packages/execution/dist/tools/tool-alias.js
|
|
259117
|
+
function aliasTool(tool, name10, description = `Alias for ${tool.name}: ${tool.description}`) {
|
|
259118
|
+
return {
|
|
259119
|
+
name: name10,
|
|
259120
|
+
description,
|
|
259121
|
+
parameters: tool.parameters,
|
|
259122
|
+
async execute(args) {
|
|
259123
|
+
return tool.execute(args);
|
|
259124
|
+
}
|
|
259125
|
+
};
|
|
259126
|
+
}
|
|
259127
|
+
var init_tool_alias = __esm({
|
|
259128
|
+
"packages/execution/dist/tools/tool-alias.js"() {
|
|
259129
|
+
"use strict";
|
|
259130
|
+
}
|
|
259131
|
+
});
|
|
259132
|
+
|
|
258616
259133
|
// packages/execution/dist/tools/opencode.js
|
|
258617
259134
|
import { execSync as execSync23, spawn as spawn14 } from "node:child_process";
|
|
258618
259135
|
import { existsSync as existsSync33 } from "node:fs";
|
|
@@ -259213,6 +259730,47 @@ function resolveSchedule2(schedule) {
|
|
|
259213
259730
|
if (LONG_HORIZON_PRESETS[lower]) {
|
|
259214
259731
|
return { cron: LONG_HORIZON_PRESETS[lower], description: lower };
|
|
259215
259732
|
}
|
|
259733
|
+
const dailyAt = lower.match(/^(?:daily|every\s+day)\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
259734
|
+
if (dailyAt) {
|
|
259735
|
+
const hour2 = parseInt(dailyAt[1], 10);
|
|
259736
|
+
const minute3 = parseInt(dailyAt[2], 10);
|
|
259737
|
+
if (isClockTime2(hour2, minute3))
|
|
259738
|
+
return { cron: `${minute3} ${hour2} * * *`, description: `daily at ${String(hour2).padStart(2, "0")}:${String(minute3).padStart(2, "0")}` };
|
|
259739
|
+
}
|
|
259740
|
+
const weeklyAt = lower.match(/^weekly(?:\s+on)?\s+([a-z]+|\d)\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
259741
|
+
if (weeklyAt) {
|
|
259742
|
+
const dow = parseWeekday3(weeklyAt[1]);
|
|
259743
|
+
const hour2 = parseInt(weeklyAt[2], 10);
|
|
259744
|
+
const minute3 = parseInt(weeklyAt[3], 10);
|
|
259745
|
+
if (dow !== null && isClockTime2(hour2, minute3))
|
|
259746
|
+
return { cron: `${minute3} ${hour2} * * ${dow}`, description: `weekly on day ${dow} at ${String(hour2).padStart(2, "0")}:${String(minute3).padStart(2, "0")}` };
|
|
259747
|
+
}
|
|
259748
|
+
const monthlyAt = lower.match(/^monthly(?:\s+(?:on|day))?\s+(\d{1,2})(?:st|nd|rd|th)?\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
259749
|
+
if (monthlyAt) {
|
|
259750
|
+
const day = parseInt(monthlyAt[1], 10);
|
|
259751
|
+
const hour2 = parseInt(monthlyAt[2], 10);
|
|
259752
|
+
const minute3 = parseInt(monthlyAt[3], 10);
|
|
259753
|
+
if (day >= 1 && day <= 31 && isClockTime2(hour2, minute3))
|
|
259754
|
+
return { cron: `${minute3} ${hour2} ${day} * *`, description: `monthly on day ${day} at ${String(hour2).padStart(2, "0")}:${String(minute3).padStart(2, "0")}` };
|
|
259755
|
+
}
|
|
259756
|
+
const yearlyNumeric = lower.match(/^(?:yearly|annually|every\s+year)\s+(?:on\s+)?(\d{1,2})-(\d{1,2})\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
259757
|
+
if (yearlyNumeric) {
|
|
259758
|
+
const month = parseInt(yearlyNumeric[1], 10);
|
|
259759
|
+
const day = parseInt(yearlyNumeric[2], 10);
|
|
259760
|
+
const hour2 = parseInt(yearlyNumeric[3], 10);
|
|
259761
|
+
const minute3 = parseInt(yearlyNumeric[4], 10);
|
|
259762
|
+
if (month >= 1 && month <= 12 && day >= 1 && day <= 31 && isClockTime2(hour2, minute3))
|
|
259763
|
+
return { cron: `${minute3} ${hour2} ${day} ${month} *`, description: `yearly on ${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")} at ${String(hour2).padStart(2, "0")}:${String(minute3).padStart(2, "0")}` };
|
|
259764
|
+
}
|
|
259765
|
+
const yearlyNamed = lower.match(/^(?:yearly|annually|every\s+year)\s+(?:on\s+)?([a-z]+)\s+(\d{1,2})(?:st|nd|rd|th)?\s+(?:at\s+)?(\d{1,2}):(\d{2})$/);
|
|
259766
|
+
if (yearlyNamed) {
|
|
259767
|
+
const month = parseMonth3(yearlyNamed[1]);
|
|
259768
|
+
const day = parseInt(yearlyNamed[2], 10);
|
|
259769
|
+
const hour2 = parseInt(yearlyNamed[3], 10);
|
|
259770
|
+
const minute3 = parseInt(yearlyNamed[4], 10);
|
|
259771
|
+
if (month !== null && day >= 1 && day <= 31 && isClockTime2(hour2, minute3))
|
|
259772
|
+
return { cron: `${minute3} ${hour2} ${day} ${month} *`, description: `yearly on ${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")} at ${String(hour2).padStart(2, "0")}:${String(minute3).padStart(2, "0")}` };
|
|
259773
|
+
}
|
|
259216
259774
|
const everyMatch = lower.match(/^every\s+(\d+)\s*(h|hr|hrs|hours?|d|days?|w|wk|wks|weeks?|m|mo|mos|months?)$/);
|
|
259217
259775
|
if (everyMatch) {
|
|
259218
259776
|
const amount = parseInt(everyMatch[1], 10);
|
|
@@ -259260,6 +259818,65 @@ function resolveSchedule2(schedule) {
|
|
|
259260
259818
|
}
|
|
259261
259819
|
return null;
|
|
259262
259820
|
}
|
|
259821
|
+
function isClockTime2(hour2, minute3) {
|
|
259822
|
+
return hour2 >= 0 && hour2 <= 23 && minute3 >= 0 && minute3 <= 59;
|
|
259823
|
+
}
|
|
259824
|
+
function parseWeekday3(raw) {
|
|
259825
|
+
const value2 = raw.toLowerCase();
|
|
259826
|
+
if (/^[0-6]$/.test(value2))
|
|
259827
|
+
return Number(value2);
|
|
259828
|
+
const days = {
|
|
259829
|
+
sunday: 0,
|
|
259830
|
+
sun: 0,
|
|
259831
|
+
monday: 1,
|
|
259832
|
+
mon: 1,
|
|
259833
|
+
tuesday: 2,
|
|
259834
|
+
tue: 2,
|
|
259835
|
+
tues: 2,
|
|
259836
|
+
wednesday: 3,
|
|
259837
|
+
wed: 3,
|
|
259838
|
+
thursday: 4,
|
|
259839
|
+
thu: 4,
|
|
259840
|
+
thurs: 4,
|
|
259841
|
+
friday: 5,
|
|
259842
|
+
fri: 5,
|
|
259843
|
+
saturday: 6,
|
|
259844
|
+
sat: 6
|
|
259845
|
+
};
|
|
259846
|
+
return days[value2] ?? null;
|
|
259847
|
+
}
|
|
259848
|
+
function parseMonth3(raw) {
|
|
259849
|
+
const value2 = raw.toLowerCase();
|
|
259850
|
+
if (/^(?:[1-9]|1[0-2])$/.test(value2))
|
|
259851
|
+
return Number(value2);
|
|
259852
|
+
const months = {
|
|
259853
|
+
january: 1,
|
|
259854
|
+
jan: 1,
|
|
259855
|
+
february: 2,
|
|
259856
|
+
feb: 2,
|
|
259857
|
+
march: 3,
|
|
259858
|
+
mar: 3,
|
|
259859
|
+
april: 4,
|
|
259860
|
+
apr: 4,
|
|
259861
|
+
may: 5,
|
|
259862
|
+
june: 6,
|
|
259863
|
+
jun: 6,
|
|
259864
|
+
july: 7,
|
|
259865
|
+
jul: 7,
|
|
259866
|
+
august: 8,
|
|
259867
|
+
aug: 8,
|
|
259868
|
+
september: 9,
|
|
259869
|
+
sep: 9,
|
|
259870
|
+
sept: 9,
|
|
259871
|
+
october: 10,
|
|
259872
|
+
oct: 10,
|
|
259873
|
+
november: 11,
|
|
259874
|
+
nov: 11,
|
|
259875
|
+
december: 12,
|
|
259876
|
+
dec: 12
|
|
259877
|
+
};
|
|
259878
|
+
return months[value2] ?? null;
|
|
259879
|
+
}
|
|
259263
259880
|
function getCurrentCrontab2() {
|
|
259264
259881
|
try {
|
|
259265
259882
|
return execSync25("crontab -l 2>/dev/null", { stdio: "pipe" }).toString().split("\n");
|
|
@@ -259376,12 +259993,14 @@ var init_cron_agent = __esm({
|
|
|
259376
259993
|
"weekly": "0 9 * * 1",
|
|
259377
259994
|
"biweekly": "0 9 1,15 * *",
|
|
259378
259995
|
"monthly": "0 9 1 * *",
|
|
259379
|
-
"quarterly": "0 9 1 1,4,7,10 *"
|
|
259996
|
+
"quarterly": "0 9 1 1,4,7,10 *",
|
|
259997
|
+
"yearly": "0 9 1 1 *",
|
|
259998
|
+
"annually": "0 9 1 1 *"
|
|
259380
259999
|
};
|
|
259381
260000
|
CRON_AGENT_MARKER = "# Omnius-CRON-AGENT:";
|
|
259382
260001
|
CronAgentTool = class {
|
|
259383
260002
|
name = "cron_agent";
|
|
259384
|
-
description = "Schedule long-horizon autonomous agent tasks that execute on a cron schedule. Unlike one-shot scheduler tasks, cron_agent jobs have goals, completion criteria, and execution history tracking. Actions: 'create' a monitored cron job, 'list' all jobs, 'check' a job's status and history, 'cancel' a job, 'logs' view execution output, 'evaluate' check if goal is met. Schedules: 'every 2 hours', 'daily', 'weekly', 'monthly', '
|
|
260003
|
+
description = "Schedule long-horizon autonomous agent tasks that execute on a cron schedule. Unlike one-shot scheduler tasks, cron_agent jobs have goals, completion criteria, and execution history tracking. Actions: 'create' a monitored cron job, 'list' all jobs, 'check' a job's status and history, 'cancel' a job, 'logs' view execution output, 'evaluate' check if goal is met. Schedules: 'every 2 hours', 'daily at 14:30', 'weekly friday at 17:45', 'monthly', 'yearly', or raw cron. Use this for long-running autonomous workflows: periodic code reviews, test monitoring, dependency updates, performance tracking, log analysis, or any recurring agent task.";
|
|
259385
260004
|
parameters = {
|
|
259386
260005
|
type: "object",
|
|
259387
260006
|
properties: {
|
|
@@ -259400,7 +260019,7 @@ var init_cron_agent = __esm({
|
|
|
259400
260019
|
},
|
|
259401
260020
|
schedule: {
|
|
259402
260021
|
type: "string",
|
|
259403
|
-
description: "When to run: 'every 2 hours', 'daily', 'weekly', 'monthly', '
|
|
260022
|
+
description: "When to run: 'every 2 hours', 'daily at 14:30', 'weekly friday at 17:45', 'monthly', 'yearly', or cron expression"
|
|
259404
260023
|
},
|
|
259405
260024
|
completion_criteria: {
|
|
259406
260025
|
type: "string",
|
|
@@ -287360,9 +287979,9 @@ ${lanes.join("\n")}
|
|
|
287360
287979
|
function isJsonEqual(a2, b) {
|
|
287361
287980
|
return a2 === b || typeof a2 === "object" && a2 !== null && typeof b === "object" && b !== null && equalOwnProperties(a2, b, isJsonEqual);
|
|
287362
287981
|
}
|
|
287363
|
-
function parsePseudoBigInt(
|
|
287982
|
+
function parsePseudoBigInt(stringValue2) {
|
|
287364
287983
|
let log2Base;
|
|
287365
|
-
switch (
|
|
287984
|
+
switch (stringValue2.charCodeAt(1)) {
|
|
287366
287985
|
// "x" in "0x123"
|
|
287367
287986
|
case 98:
|
|
287368
287987
|
case 66:
|
|
@@ -287377,19 +287996,19 @@ ${lanes.join("\n")}
|
|
|
287377
287996
|
log2Base = 4;
|
|
287378
287997
|
break;
|
|
287379
287998
|
default:
|
|
287380
|
-
const nIndex =
|
|
287999
|
+
const nIndex = stringValue2.length - 1;
|
|
287381
288000
|
let nonZeroStart = 0;
|
|
287382
|
-
while (
|
|
288001
|
+
while (stringValue2.charCodeAt(nonZeroStart) === 48) {
|
|
287383
288002
|
nonZeroStart++;
|
|
287384
288003
|
}
|
|
287385
|
-
return
|
|
288004
|
+
return stringValue2.slice(nonZeroStart, nIndex) || "0";
|
|
287386
288005
|
}
|
|
287387
|
-
const startIndex = 2, endIndex =
|
|
288006
|
+
const startIndex = 2, endIndex = stringValue2.length - 1;
|
|
287388
288007
|
const bitsNeeded = (endIndex - startIndex) * log2Base;
|
|
287389
288008
|
const segments = new Uint16Array((bitsNeeded >>> 4) + (bitsNeeded & 15 ? 1 : 0));
|
|
287390
288009
|
for (let i2 = endIndex - 1, bitOffset = 0; i2 >= startIndex; i2--, bitOffset += log2Base) {
|
|
287391
288010
|
const segment = bitOffset >>> 4;
|
|
287392
|
-
const digitChar =
|
|
288011
|
+
const digitChar = stringValue2.charCodeAt(i2);
|
|
287393
288012
|
const digit = digitChar <= 57 ? digitChar - 48 : 10 + digitChar - (digitChar <= 70 ? 65 : 97);
|
|
287394
288013
|
const shiftedDigit = digit << (bitOffset & 15);
|
|
287395
288014
|
segments[segment] |= shiftedDigit;
|
|
@@ -516405,6 +517024,7 @@ __export(dist_exports, {
|
|
|
516405
517024
|
YouTubeDownloadTool: () => YouTubeDownloadTool,
|
|
516406
517025
|
addProjectConstraint: () => addProjectConstraint,
|
|
516407
517026
|
addSessionConstraint: () => addSessionConstraint,
|
|
517027
|
+
aliasTool: () => aliasTool,
|
|
516408
517028
|
applyPatch: () => applyPatch,
|
|
516409
517029
|
audioGenerationDir: () => audioGenerationDir,
|
|
516410
517030
|
audioGenerationSetupPlan: () => audioGenerationSetupPlan,
|
|
@@ -516496,6 +517116,7 @@ __export(dist_exports, {
|
|
|
516496
517116
|
loadSkillContent: () => loadSkillContent,
|
|
516497
517117
|
logsDir: () => logsDir,
|
|
516498
517118
|
markRemindersSeen: () => markRemindersSeen,
|
|
517119
|
+
markRemindersTriggered: () => markRemindersTriggered,
|
|
516499
517120
|
markReverted: () => markReverted,
|
|
516500
517121
|
markSessionValidated: () => markSessionValidated,
|
|
516501
517122
|
normalizeMcpName: () => normalizeMcpName,
|
|
@@ -516615,6 +517236,7 @@ var init_dist5 = __esm({
|
|
|
516615
517236
|
init_scheduler();
|
|
516616
517237
|
init_reminder();
|
|
516617
517238
|
init_agenda();
|
|
517239
|
+
init_tool_alias();
|
|
516618
517240
|
init_opencode();
|
|
516619
517241
|
init_factory();
|
|
516620
517242
|
init_cron_agent();
|
|
@@ -553804,9 +554426,14 @@ var init_command_registry = __esm({
|
|
|
553804
554426
|
["/access <loopback|lan|any>", "Set access policy (OMNIUS_ACCESS) and restart daemon"],
|
|
553805
554427
|
["/k <any|lan|loopback|config>", "Quick network access helper"],
|
|
553806
554428
|
["/scheduler", "Scheduled tasks control panel (list/kill/toggle)"],
|
|
554429
|
+
["/cron", "Alias for /scheduler"],
|
|
553807
554430
|
["/scheduler menu", "Interactive scheduler menu (toggle/kill)"],
|
|
553808
554431
|
["/scheduler list", "List all scheduled tasks and timers"],
|
|
553809
554432
|
["/scheduler kill", "Kill schedulers + active runs (with escalation if needed)"],
|
|
554433
|
+
["/reminder [list|all]", "List scoped TUI reminders"],
|
|
554434
|
+
["/remind <message>", "Set a scoped minimal reminder for this TUI session"],
|
|
554435
|
+
["/remind in 30m <message>", "Set a scoped minimal reminder with a relative due time"],
|
|
554436
|
+
["/reminders", "Alias for /reminder"],
|
|
553810
554437
|
["/daemon", "Show or manage the local API daemon"],
|
|
553811
554438
|
["/daemon <start|stop|restart|takeover>", "Control the local API daemon"],
|
|
553812
554439
|
["/apikey", "Show current API key (for pasting into Web UI / clients)"],
|
|
@@ -553861,7 +554488,6 @@ var init_command_registry = __esm({
|
|
|
553861
554488
|
["/skin", "Configure the visual skin/theme bundle"],
|
|
553862
554489
|
["/toolsets", "Show or select tool exposure sets"],
|
|
553863
554490
|
["/browser connect|disconnect|status", "Manage browser-agent connectivity"],
|
|
553864
|
-
["/cron", "Scheduled/cron agent controls"],
|
|
553865
554491
|
["/reload-mcp", "Reload MCP servers and tools"],
|
|
553866
554492
|
["/plugins", "List or manage plugins"],
|
|
553867
554493
|
["/usage", "Show usage and quota details"],
|
|
@@ -553932,6 +554558,7 @@ var init_command_registry = __esm({
|
|
|
553932
554558
|
network: "network",
|
|
553933
554559
|
k: "network",
|
|
553934
554560
|
scheduler: "runtime",
|
|
554561
|
+
reminder: "runtime",
|
|
553935
554562
|
daemon: "runtime",
|
|
553936
554563
|
apikey: "secret",
|
|
553937
554564
|
key: "secret",
|
|
@@ -553998,6 +554625,8 @@ var init_command_registry = __esm({
|
|
|
553998
554625
|
emojis: ["emoji"],
|
|
553999
554626
|
compact: ["gc"],
|
|
554000
554627
|
network: ["k"],
|
|
554628
|
+
scheduler: ["cron"],
|
|
554629
|
+
reminder: ["remind", "reminders"],
|
|
554001
554630
|
statusbar: ["sb"],
|
|
554002
554631
|
platforms: ["gateway"]
|
|
554003
554632
|
};
|
|
@@ -554056,6 +554685,7 @@ var init_command_registry = __esm({
|
|
|
554056
554685
|
"network",
|
|
554057
554686
|
"k",
|
|
554058
554687
|
"scheduler",
|
|
554688
|
+
"cron",
|
|
554059
554689
|
"daemon",
|
|
554060
554690
|
"fortemi",
|
|
554061
554691
|
"mouse",
|
|
@@ -579989,6 +580619,69 @@ function safeLog(text) {
|
|
|
579989
580619
|
process.stdout.write(text + "\n");
|
|
579990
580620
|
}
|
|
579991
580621
|
}
|
|
580622
|
+
function createSlashReminderTool(ctx3) {
|
|
580623
|
+
const sessionId = process.env["OMNIUS_SESSION_ID"] || "terminal";
|
|
580624
|
+
return new ReminderTool(ctx3.repoRoot, {
|
|
580625
|
+
defaultScope: {
|
|
580626
|
+
surface: "tui",
|
|
580627
|
+
visibility: "private",
|
|
580628
|
+
targetId: sessionId,
|
|
580629
|
+
sessionId,
|
|
580630
|
+
label: "terminal"
|
|
580631
|
+
},
|
|
580632
|
+
lockScope: true,
|
|
580633
|
+
allowActionDelivery: false,
|
|
580634
|
+
source: "user",
|
|
580635
|
+
createdFrom: "tui-slash"
|
|
580636
|
+
});
|
|
580637
|
+
}
|
|
580638
|
+
function splitReminderDue(raw) {
|
|
580639
|
+
const text = raw.trim().replace(/^set\s+/i, "").trim();
|
|
580640
|
+
const dueMatch = text.match(
|
|
580641
|
+
/^((?:in\s+\d+\s*(?:m|min|mins|minutes?|h|hr|hrs|hours?|d|days?|w|weeks?))|tomorrow|next week|next startup|startup|now|(?:today\s+)?at\s+\d{1,2}:\d{2})\s+(.+)$/i
|
|
580642
|
+
);
|
|
580643
|
+
if (!dueMatch) return { message: text };
|
|
580644
|
+
return { due: dueMatch[1].trim(), message: dueMatch[2].trim() };
|
|
580645
|
+
}
|
|
580646
|
+
async function handleReminderSlash(cmd, arg, ctx3) {
|
|
580647
|
+
const tool = createSlashReminderTool(ctx3);
|
|
580648
|
+
const trimmed = arg.trim();
|
|
580649
|
+
const lower = trimmed.toLowerCase();
|
|
580650
|
+
let args;
|
|
580651
|
+
if (!trimmed || lower === "list" || lower === "pending" || lower === "all" || lower === "seen") {
|
|
580652
|
+
args = { action: "list", filter: lower === "all" || lower === "seen" ? lower : "pending" };
|
|
580653
|
+
} else if (lower === "completed" || lower === "dismissed") {
|
|
580654
|
+
args = { action: "list", filter: lower };
|
|
580655
|
+
} else if (lower.startsWith("complete ")) {
|
|
580656
|
+
args = { action: "complete", id: trimmed.slice("complete ".length).trim() };
|
|
580657
|
+
} else if (lower.startsWith("dismiss ")) {
|
|
580658
|
+
args = { action: "dismiss", id: trimmed.slice("dismiss ".length).trim() };
|
|
580659
|
+
} else if (lower.startsWith("snooze ")) {
|
|
580660
|
+
const rest = trimmed.slice("snooze ".length).trim();
|
|
580661
|
+
const [id, ...dueParts] = rest.split(/\s+/);
|
|
580662
|
+
args = { action: "snooze", id, due: dueParts.join(" ").trim() || "in 1h" };
|
|
580663
|
+
} else {
|
|
580664
|
+
const { due, message: message2 } = splitReminderDue(trimmed);
|
|
580665
|
+
if (!message2) {
|
|
580666
|
+
renderInfo("Usage: /remind [in 30m|tomorrow|at 14:30] <message>");
|
|
580667
|
+
return "handled";
|
|
580668
|
+
}
|
|
580669
|
+
args = {
|
|
580670
|
+
action: "set",
|
|
580671
|
+
kind: "minimal",
|
|
580672
|
+
message: message2,
|
|
580673
|
+
content: message2,
|
|
580674
|
+
...due ? { due } : {}
|
|
580675
|
+
};
|
|
580676
|
+
}
|
|
580677
|
+
const result = await tool.execute(args);
|
|
580678
|
+
if (!result.success) {
|
|
580679
|
+
renderError(result.error || `/${cmd} failed`);
|
|
580680
|
+
} else if (result.output) {
|
|
580681
|
+
safeLog(result.output);
|
|
580682
|
+
}
|
|
580683
|
+
return "handled";
|
|
580684
|
+
}
|
|
579992
580685
|
function parseTelegramChatTarget(value2) {
|
|
579993
580686
|
if (!value2) return null;
|
|
579994
580687
|
if (/^-?\d+$/.test(value2)) return Number(value2);
|
|
@@ -580365,6 +581058,10 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
580365
581058
|
case "?":
|
|
580366
581059
|
await showHelpMenu(ctx3);
|
|
580367
581060
|
return "handled";
|
|
581061
|
+
case "reminder":
|
|
581062
|
+
case "remind":
|
|
581063
|
+
case "reminders":
|
|
581064
|
+
return handleReminderSlash(cmd, arg, ctx3);
|
|
580368
581065
|
case "queue": {
|
|
580369
581066
|
if (!arg) {
|
|
580370
581067
|
const count2 = ctx3.queuedPromptCount?.() ?? 0;
|
|
@@ -583173,7 +583870,8 @@ sleep 1
|
|
|
583173
583870
|
}
|
|
583174
583871
|
return "handled";
|
|
583175
583872
|
}
|
|
583176
|
-
case "scheduler":
|
|
583873
|
+
case "scheduler":
|
|
583874
|
+
case "cron": {
|
|
583177
583875
|
const tokens = (arg || "").trim().length ? (arg || "").trim().split(/\s+/) : [];
|
|
583178
583876
|
const sub = (tokens[0] || "menu").toLowerCase();
|
|
583179
583877
|
const base3 = `http://127.0.0.1:${process.env["OMNIUS_PORT"] || "11435"}`;
|
|
@@ -595630,10 +596328,14 @@ var init_bless_engine = __esm({
|
|
|
595630
596328
|
* Priority queue is checked first, then reminders/attention items are ingested. */
|
|
595631
596329
|
async getNextTask() {
|
|
595632
596330
|
try {
|
|
595633
|
-
const dueReminders = await getDueReminders(this.repoRoot
|
|
596331
|
+
const dueReminders = await getDueReminders(this.repoRoot, {
|
|
596332
|
+
deliveryMode: "action",
|
|
596333
|
+
includeUnscoped: true
|
|
596334
|
+
});
|
|
595634
596335
|
for (const r2 of dueReminders.filter((r3) => r3.status === "pending")) {
|
|
595635
596336
|
const priority = r2.priority === "critical" ? "critical" : r2.priority === "high" ? "high" : "moderate";
|
|
595636
|
-
const
|
|
596337
|
+
const task2 = r2.delivery?.taskDescription || r2.message;
|
|
596338
|
+
const prompt = `${priority === "critical" ? "URGENT " : ""}REMINDER ACTION: ${task2}${r2.tags?.length ? ` [tags: ${r2.tags.join(", ")}]` : ""}. Check the agenda for full context and take appropriate action.`;
|
|
595637
596339
|
this.priorityEngine.ingest(prompt, "internal", "reminder", { reminderId: r2.id }, priority);
|
|
595638
596340
|
}
|
|
595639
596341
|
} catch {
|
|
@@ -597342,7 +598044,7 @@ var init_tool_policy = __esm({
|
|
|
597342
598044
|
"aiwg_workflow",
|
|
597343
598045
|
"autoresearch",
|
|
597344
598046
|
"scheduler",
|
|
597345
|
-
"
|
|
598047
|
+
"cronjob",
|
|
597346
598048
|
"agenda"
|
|
597347
598049
|
]);
|
|
597348
598050
|
SAFE_PUBLIC_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -597362,6 +598064,9 @@ var init_tool_policy = __esm({
|
|
|
597362
598064
|
"transcribe_file",
|
|
597363
598065
|
"video_understand",
|
|
597364
598066
|
"audio_analyze",
|
|
598067
|
+
"reminder",
|
|
598068
|
+
"remind",
|
|
598069
|
+
"reminders",
|
|
597365
598070
|
"explore_tools",
|
|
597366
598071
|
"telegram_media_recent",
|
|
597367
598072
|
"generate_image",
|
|
@@ -597389,6 +598094,9 @@ var init_tool_policy = __esm({
|
|
|
597389
598094
|
"transcribe_file",
|
|
597390
598095
|
"video_understand",
|
|
597391
598096
|
"audio_analyze",
|
|
598097
|
+
"reminder",
|
|
598098
|
+
"remind",
|
|
598099
|
+
"reminders",
|
|
597392
598100
|
"explore_tools",
|
|
597393
598101
|
"telegram_media_recent",
|
|
597394
598102
|
"generate_image",
|
|
@@ -598465,6 +599173,14 @@ function renderTelegramLiveProgressHTML(progressLines, accumulated) {
|
|
|
598465
599173
|
}
|
|
598466
599174
|
return progressLines.slice(-6).map((line) => line.trim()).filter((line) => !isTelegramInternalStatusText(line)).filter(Boolean).join("\n");
|
|
598467
599175
|
}
|
|
599176
|
+
function splitTelegramReminderDue(raw) {
|
|
599177
|
+
const text = raw.trim().replace(/^set\s+/i, "").trim();
|
|
599178
|
+
const dueMatch = text.match(
|
|
599179
|
+
/^((?:in\s+\d+\s*(?:m|min|mins|minutes?|h|hr|hrs|hours?|d|days?|w|weeks?))|tomorrow|next week|next startup|startup|now|(?:today\s+)?at\s+\d{1,2}:\d{2})\s+(.+)$/i
|
|
599180
|
+
);
|
|
599181
|
+
if (!dueMatch) return { message: text };
|
|
599182
|
+
return { due: dueMatch[1].trim(), message: dueMatch[2].trim() };
|
|
599183
|
+
}
|
|
598468
599184
|
function telegramSyntheticHelpSignatures() {
|
|
598469
599185
|
return [
|
|
598470
599186
|
{ signature: "/help", description: "Show Telegram command help" },
|
|
@@ -598954,7 +599670,7 @@ function renderTelegramSubAgentError(username, error) {
|
|
|
598954
599670
|
process.stdout.write(` ${c3.dim("⎿")} ${c3.red("✘")} @${username}: ${c3.dim(preview)}
|
|
598955
599671
|
`);
|
|
598956
599672
|
}
|
|
598957
|
-
var TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, TELEGRAM_PUBLIC_SOUL_PROFILE, TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT, TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT, GROUP_REPLY_DISCRETION_PROMPT, TELEGRAM_CHAT_MODE_PROMPT, ADMIN_CHAT_PROFILE_PROMPT, TELEGRAM_ACTION_RESPONSE_CONTRACT, TELEGRAM_CHAT_HISTORY_LIMIT, TELEGRAM_CONTEXT_RECENT_DEFAULT, TELEGRAM_CONTEXT_LINE_LIMIT, TELEGRAM_CONTEXT_SAMPLE_LIMIT, TELEGRAM_MEMORY_CARD_LIMIT, TELEGRAM_MEMORY_NOTE_LIMIT, TELEGRAM_MEMORY_STOPWORDS, TELEGRAM_PUBLIC_HELP_COMMANDS, TELEGRAM_IMAGE_EXTENSIONS, MEDIA_CACHE_TTL_MS, TelegramBridge;
|
|
599673
|
+
var TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, TELEGRAM_PUBLIC_SOUL_PROFILE, TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT, TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT, GROUP_REPLY_DISCRETION_PROMPT, TELEGRAM_CHAT_MODE_PROMPT, ADMIN_CHAT_PROFILE_PROMPT, TELEGRAM_ACTION_RESPONSE_CONTRACT, TELEGRAM_CHAT_HISTORY_LIMIT, TELEGRAM_CONTEXT_RECENT_DEFAULT, TELEGRAM_CONTEXT_LINE_LIMIT, TELEGRAM_CONTEXT_SAMPLE_LIMIT, TELEGRAM_MEMORY_CARD_LIMIT, TELEGRAM_MEMORY_NOTE_LIMIT, TELEGRAM_MEMORY_STOPWORDS, TELEGRAM_PUBLIC_HELP_COMMANDS, TELEGRAM_REMINDER_SLASH_COMMANDS, TELEGRAM_IMAGE_EXTENSIONS, MEDIA_CACHE_TTL_MS, TelegramBridge;
|
|
598958
599674
|
var init_telegram_bridge = __esm({
|
|
598959
599675
|
"packages/cli/src/tui/telegram-bridge.ts"() {
|
|
598960
599676
|
"use strict";
|
|
@@ -599150,6 +599866,7 @@ Telegram response contract:
|
|
|
599150
599866
|
"your"
|
|
599151
599867
|
]);
|
|
599152
599868
|
TELEGRAM_PUBLIC_HELP_COMMANDS = /* @__PURE__ */ new Set(["help", "start", "auth", "call"]);
|
|
599869
|
+
TELEGRAM_REMINDER_SLASH_COMMANDS = /* @__PURE__ */ new Set(["remind", "reminder", "reminders"]);
|
|
599153
599870
|
TELEGRAM_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".tiff", ".tif", ".svg"]);
|
|
599154
599871
|
MEDIA_CACHE_TTL_MS = 30 * 60 * 1e3;
|
|
599155
599872
|
TelegramBridge = class {
|
|
@@ -599350,6 +600067,49 @@ Telegram response contract:
|
|
|
599350
600067
|
const botless = first2.startsWith("/") ? first2.slice(1).split("@")[0]?.toLowerCase() : "";
|
|
599351
600068
|
return !!botless && this.telegramCommandMap.has(botless);
|
|
599352
600069
|
}
|
|
600070
|
+
async handleTelegramReminderSlash(msg, commandText, context2) {
|
|
600071
|
+
if (!this.repoRoot) {
|
|
600072
|
+
await this.replyToTelegramMessage(msg, "Reminder storage is not available yet.");
|
|
600073
|
+
return;
|
|
600074
|
+
}
|
|
600075
|
+
const first2 = commandText.trim().split(/\s+/)[0] ?? "";
|
|
600076
|
+
const cmd = first2.slice(1).split("@")[0]?.toLowerCase() || "reminder";
|
|
600077
|
+
const arg = commandText.trim().slice(first2.length).trim();
|
|
600078
|
+
const lower = arg.toLowerCase();
|
|
600079
|
+
const tool = this.buildTelegramReminderTool(context2, this.repoRoot, msg.chatId, msg);
|
|
600080
|
+
let args;
|
|
600081
|
+
if (!arg || lower === "list" || lower === "pending" || lower === "all" || lower === "seen") {
|
|
600082
|
+
args = { action: "list", filter: lower === "all" || lower === "seen" ? lower : "pending" };
|
|
600083
|
+
} else if (lower === "completed" || lower === "dismissed") {
|
|
600084
|
+
args = { action: "list", filter: lower };
|
|
600085
|
+
} else if (lower.startsWith("complete ")) {
|
|
600086
|
+
args = { action: "complete", id: arg.slice("complete ".length).trim() };
|
|
600087
|
+
} else if (lower.startsWith("dismiss ")) {
|
|
600088
|
+
args = { action: "dismiss", id: arg.slice("dismiss ".length).trim() };
|
|
600089
|
+
} else if (lower.startsWith("snooze ")) {
|
|
600090
|
+
const rest = arg.slice("snooze ".length).trim();
|
|
600091
|
+
const [id, ...dueParts] = rest.split(/\s+/);
|
|
600092
|
+
args = { action: "snooze", id, due: dueParts.join(" ").trim() || "in 1h" };
|
|
600093
|
+
} else {
|
|
600094
|
+
const { due, message: message2 } = splitTelegramReminderDue(arg);
|
|
600095
|
+
if (!message2) {
|
|
600096
|
+
await this.replyToTelegramMessage(msg, "Usage: /remind [in 30m|tomorrow|at 14:30] <message>");
|
|
600097
|
+
return;
|
|
600098
|
+
}
|
|
600099
|
+
args = {
|
|
600100
|
+
action: "set",
|
|
600101
|
+
kind: "minimal",
|
|
600102
|
+
message: message2,
|
|
600103
|
+
content: message2,
|
|
600104
|
+
...due ? { due } : {}
|
|
600105
|
+
};
|
|
600106
|
+
}
|
|
600107
|
+
const result = await tool.execute(args);
|
|
600108
|
+
await this.replyToTelegramMessage(
|
|
600109
|
+
msg,
|
|
600110
|
+
result.success ? result.output || "Reminder updated." : result.error || `/${cmd} failed`
|
|
600111
|
+
);
|
|
600112
|
+
}
|
|
599353
600113
|
/** Write to the scrollable TUI waterfall area (respects status bar scroll region) */
|
|
599354
600114
|
tuiWrite(fn) {
|
|
599355
600115
|
if (this.writeContent) {
|
|
@@ -600424,6 +601184,11 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
|
|
|
600424
601184
|
const toolContext = this.resolveToolContext(msg, isAdmin);
|
|
600425
601185
|
const isAdminDM = toolContext === "telegram-admin-dm";
|
|
600426
601186
|
const sessionKey = this.sessionKeyForMessage(msg);
|
|
601187
|
+
const telegramSlash = this.telegramSlashName(normalizedCommandText);
|
|
601188
|
+
if (msg.text.trim().startsWith("/") && TELEGRAM_REMINDER_SLASH_COMMANDS.has(telegramSlash)) {
|
|
601189
|
+
await this.handleTelegramReminderSlash(msg, normalizedCommandText, toolContext);
|
|
601190
|
+
return;
|
|
601191
|
+
}
|
|
600427
601192
|
if (msg.text.trim().toLowerCase() === "/hangup" && isAdmin && this.callStopper) {
|
|
600428
601193
|
const callUrl = this.callUrlGetter?.();
|
|
600429
601194
|
if (callUrl) {
|
|
@@ -600478,7 +601243,6 @@ Join: ${newUrl}`);
|
|
|
600478
601243
|
return;
|
|
600479
601244
|
}
|
|
600480
601245
|
}
|
|
600481
|
-
const telegramSlash = this.telegramSlashName(normalizedCommandText);
|
|
600482
601246
|
const publicCreativeSlash = telegramSlash === "image";
|
|
600483
601247
|
if (!isAdmin && msg.text.trim().startsWith("/") && this.isKnownTelegramSlash(normalizedCommandText) && !publicCreativeSlash) {
|
|
600484
601248
|
await this.replyToTelegramMessage(
|
|
@@ -601571,7 +602335,8 @@ Scoped workspace: ${scopedRoot}`,
|
|
|
601571
602335
|
new VideoUnderstandTool(repoRoot),
|
|
601572
602336
|
new AudioAnalyzeTool(),
|
|
601573
602337
|
new ExploreToolsTool(),
|
|
601574
|
-
this.buildTelegramMediaRecentTool(chatId, msg)
|
|
602338
|
+
this.buildTelegramMediaRecentTool(chatId, msg),
|
|
602339
|
+
...this.buildTelegramReminderTools(context2, repoRoot, chatId, msg)
|
|
601575
602340
|
];
|
|
601576
602341
|
const adminTools = [
|
|
601577
602342
|
new ShellTool(repoRoot),
|
|
@@ -601629,6 +602394,7 @@ Scoped workspace: ${scopedRoot}`,
|
|
|
601629
602394
|
new ImpactAnalysisTool(repoRoot),
|
|
601630
602395
|
new CodeNeighborsTool(repoRoot),
|
|
601631
602396
|
new ProcessHealthTool(),
|
|
602397
|
+
...this.buildTelegramReminderTools(context2, repoRoot, chatId, msg),
|
|
601632
602398
|
fullSubAgentTool,
|
|
601633
602399
|
this.buildTelegramSendFileTool(context2, repoRoot, chatId, msg)
|
|
601634
602400
|
];
|
|
@@ -601674,6 +602440,34 @@ Scoped workspace: ${scopedRoot}`,
|
|
|
601674
602440
|
]);
|
|
601675
602441
|
return tools.filter((tool) => !blocked.has(tool.name));
|
|
601676
602442
|
}
|
|
602443
|
+
buildTelegramReminderTool(context2, repoRoot, chatId, currentMsg) {
|
|
602444
|
+
const rawChatId = String(chatId ?? currentMsg?.chatId ?? "unknown");
|
|
602445
|
+
const isPrivate2 = currentMsg?.chatType === "private";
|
|
602446
|
+
const username = currentMsg?.username ? currentMsg.username.replace(/^@/, "") : void 0;
|
|
602447
|
+
return new ReminderTool(repoRoot, {
|
|
602448
|
+
defaultScope: {
|
|
602449
|
+
surface: "telegram",
|
|
602450
|
+
visibility: isPrivate2 ? "private" : "public",
|
|
602451
|
+
targetId: rawChatId,
|
|
602452
|
+
chatId: rawChatId,
|
|
602453
|
+
...currentMsg?.fromUserId !== void 0 ? { userId: String(currentMsg.fromUserId) } : {},
|
|
602454
|
+
...username ? { username } : {},
|
|
602455
|
+
label: isPrivate2 ? `telegram dm${username ? ` @${username}` : ""}` : `telegram group ${currentMsg?.chatTitle ?? rawChatId}`
|
|
602456
|
+
},
|
|
602457
|
+
lockScope: true,
|
|
602458
|
+
allowActionDelivery: context2 === "telegram-admin-dm",
|
|
602459
|
+
source: "user",
|
|
602460
|
+
createdFrom: context2
|
|
602461
|
+
});
|
|
602462
|
+
}
|
|
602463
|
+
buildTelegramReminderTools(context2, repoRoot, chatId, currentMsg) {
|
|
602464
|
+
const reminder = this.buildTelegramReminderTool(context2, repoRoot, chatId, currentMsg);
|
|
602465
|
+
return [
|
|
602466
|
+
reminder,
|
|
602467
|
+
aliasTool(reminder, "remind", "Alias for reminder: set scoped Telegram reminders."),
|
|
602468
|
+
aliasTool(reminder, "reminders", "Alias for reminder: list and manage scoped Telegram reminders.")
|
|
602469
|
+
];
|
|
602470
|
+
}
|
|
601677
602471
|
buildTelegramMediaRecentTool(chatId, currentMsg) {
|
|
601678
602472
|
const bridge = this;
|
|
601679
602473
|
return {
|
|
@@ -626784,6 +627578,33 @@ function adaptTool6(tool) {
|
|
|
626784
627578
|
}
|
|
626785
627579
|
};
|
|
626786
627580
|
}
|
|
627581
|
+
function createTuiReminderOptions(allowActionDelivery = true) {
|
|
627582
|
+
const sessionId = process.env["OMNIUS_SESSION_ID"] || "terminal";
|
|
627583
|
+
return {
|
|
627584
|
+
defaultScope: {
|
|
627585
|
+
surface: "tui",
|
|
627586
|
+
visibility: "private",
|
|
627587
|
+
targetId: sessionId,
|
|
627588
|
+
sessionId,
|
|
627589
|
+
label: "terminal"
|
|
627590
|
+
},
|
|
627591
|
+
allowActionDelivery,
|
|
627592
|
+
createdFrom: "tui"
|
|
627593
|
+
};
|
|
627594
|
+
}
|
|
627595
|
+
function withReminderAliases(reminder) {
|
|
627596
|
+
return [
|
|
627597
|
+
reminder,
|
|
627598
|
+
aliasTool(reminder, "remind", "Alias for reminder: set or list scoped minimal reminders and action triggers."),
|
|
627599
|
+
aliasTool(reminder, "reminders", "Alias for reminder: list and manage scoped reminders.")
|
|
627600
|
+
];
|
|
627601
|
+
}
|
|
627602
|
+
function withSchedulerAliases(scheduler) {
|
|
627603
|
+
return [
|
|
627604
|
+
scheduler,
|
|
627605
|
+
aliasTool(scheduler, "cronjob", "Alias for scheduler: create, list, and manage OS cron-backed time triggers.")
|
|
627606
|
+
];
|
|
627607
|
+
}
|
|
626787
627608
|
function scanForSessionSignals(toolOutput) {
|
|
626788
627609
|
if (/SESSION_ACTIVE\s*=\s*true/i.test(toolOutput)) {
|
|
626789
627610
|
_interactiveSessionActive = true;
|
|
@@ -627124,8 +627945,8 @@ function buildSubAgentTools(repoRoot, config) {
|
|
|
627124
627945
|
new AiwgHealthTool(repoRoot),
|
|
627125
627946
|
new AiwgWorkflowTool(repoRoot),
|
|
627126
627947
|
// Scheduler + agenda (time-based tooling)
|
|
627127
|
-
new SchedulerTool(repoRoot),
|
|
627128
|
-
new ReminderTool(repoRoot),
|
|
627948
|
+
...withSchedulerAliases(new SchedulerTool(repoRoot)),
|
|
627949
|
+
...withReminderAliases(new ReminderTool(repoRoot, createTuiReminderOptions())),
|
|
627129
627950
|
new AgendaTool(repoRoot),
|
|
627130
627951
|
// Vision + multimodal memory
|
|
627131
627952
|
new VisionTool(repoRoot),
|
|
@@ -627238,8 +628059,8 @@ function buildTools(repoRoot, config, contextWindowSize, modelTier) {
|
|
|
627238
628059
|
// Autoresearch (autonomous ML experiment loop)
|
|
627239
628060
|
new AutoresearchTool(repoRoot),
|
|
627240
628061
|
// Temporal agency (scheduling, reminders, attention steering)
|
|
627241
|
-
new SchedulerTool(repoRoot),
|
|
627242
|
-
new ReminderTool(repoRoot),
|
|
628062
|
+
...withSchedulerAliases(new SchedulerTool(repoRoot)),
|
|
628063
|
+
...withReminderAliases(new ReminderTool(repoRoot, createTuiReminderOptions())),
|
|
627243
628064
|
new AgendaTool(repoRoot),
|
|
627244
628065
|
// OpenCode + Factory AI delegation + long-horizon cron agent
|
|
627245
628066
|
new OpenCodeTool(repoRoot),
|
|
@@ -630555,6 +631376,7 @@ ${result.summary}`
|
|
|
630555
631376
|
let telegramBridge = null;
|
|
630556
631377
|
let activeTelegramChatId = null;
|
|
630557
631378
|
let dmnRetriggerTimer = null;
|
|
631379
|
+
let reminderDispatchTimer = null;
|
|
630558
631380
|
function scheduleDMNRetrigger(delayMs) {
|
|
630559
631381
|
if (dmnRetriggerTimer) clearTimeout(dmnRetriggerTimer);
|
|
630560
631382
|
dmnRetriggerTimer = setTimeout(async () => {
|
|
@@ -630629,10 +631451,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
630629
631451
|
const turnQueue = [];
|
|
630630
631452
|
let queueDrainScheduled = false;
|
|
630631
631453
|
let sessionTitle = null;
|
|
630632
|
-
const queuePrompt = (prompt, source = "user") => {
|
|
631454
|
+
const queuePrompt = (prompt, source = "user", options2 = {}) => {
|
|
630633
631455
|
const trimmed = prompt.trim();
|
|
630634
631456
|
if (!trimmed) return turnQueue.length;
|
|
630635
|
-
turnQueue.push({ prompt: trimmed, source, enqueuedAt: Date.now() });
|
|
631457
|
+
turnQueue.push({ prompt: trimmed, source, enqueuedAt: Date.now(), ...options2 });
|
|
630636
631458
|
return turnQueue.length;
|
|
630637
631459
|
};
|
|
630638
631460
|
const clearQueuedPrompts = () => {
|
|
@@ -630657,9 +631479,121 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
630657
631479
|
`Starting queued prompt from ${next.source} (${turnQueue.length} remaining).`
|
|
630658
631480
|
)
|
|
630659
631481
|
);
|
|
631482
|
+
if (next.telegramChatId !== void 0) activeTelegramChatId = next.telegramChatId;
|
|
630660
631483
|
rl.emit("line", next.prompt);
|
|
630661
631484
|
}, 0);
|
|
630662
631485
|
};
|
|
631486
|
+
const reminderTelegramTarget = (scope) => {
|
|
631487
|
+
if (!scope || scope.surface !== "telegram") return null;
|
|
631488
|
+
const raw = scope.chatId ?? scope.targetId;
|
|
631489
|
+
if (!raw) return null;
|
|
631490
|
+
return /^-?\d+$/.test(raw) ? Number(raw) : raw;
|
|
631491
|
+
};
|
|
631492
|
+
const reminderText = (reminder) => {
|
|
631493
|
+
const content = reminder.delivery?.content || reminder.message;
|
|
631494
|
+
const prefix = reminder.priority === "critical" ? "URGENT reminder" : "Reminder";
|
|
631495
|
+
return `${prefix}: ${content}`;
|
|
631496
|
+
};
|
|
631497
|
+
const reminderActionPrompt = (reminder) => {
|
|
631498
|
+
const task = reminder.delivery?.taskDescription || reminder.delivery?.prompt || reminder.message;
|
|
631499
|
+
const scope = reminder.scope ? `${reminder.scope.surface}/${reminder.scope.visibility}/${reminder.scope.targetId}` : "unscoped";
|
|
631500
|
+
return [
|
|
631501
|
+
`[Scheduled reminder action | ${reminder.id}]`,
|
|
631502
|
+
``,
|
|
631503
|
+
`Trigger: ${reminder.message}`,
|
|
631504
|
+
`Scope: ${scope}`,
|
|
631505
|
+
reminder.context ? `Context: ${reminder.context}` : "",
|
|
631506
|
+
reminder.tags?.length ? `Tags: ${reminder.tags.join(", ")}` : "",
|
|
631507
|
+
``,
|
|
631508
|
+
`Task description:`,
|
|
631509
|
+
task
|
|
631510
|
+
].filter(Boolean).join("\n");
|
|
631511
|
+
};
|
|
631512
|
+
const dispatchDueReminder = async (reminder) => {
|
|
631513
|
+
const mode = reminder.delivery?.mode ?? "minimal";
|
|
631514
|
+
const scope = reminder.scope;
|
|
631515
|
+
if (scope?.surface === "telegram") {
|
|
631516
|
+
const target = reminderTelegramTarget(scope);
|
|
631517
|
+
if (!target || !telegramBridge?.isActive) return false;
|
|
631518
|
+
if (mode === "minimal") {
|
|
631519
|
+
await telegramBridge.sendMessage(target, reminderText(reminder));
|
|
631520
|
+
return true;
|
|
631521
|
+
}
|
|
631522
|
+
if (activeTask) return false;
|
|
631523
|
+
activeTelegramChatId = target;
|
|
631524
|
+
rl.emit("line", `${TELEGRAM_SAFETY_PROMPT}
|
|
631525
|
+
|
|
631526
|
+
---
|
|
631527
|
+
|
|
631528
|
+
${reminderActionPrompt(reminder)}
|
|
631529
|
+
|
|
631530
|
+
Respond to the scoped Telegram target when complete.`);
|
|
631531
|
+
return true;
|
|
631532
|
+
}
|
|
631533
|
+
if (scope?.surface === "gui") {
|
|
631534
|
+
if (mode === "minimal") {
|
|
631535
|
+
writeContent(() => renderInfo(reminderText(reminder)));
|
|
631536
|
+
showPrompt();
|
|
631537
|
+
return true;
|
|
631538
|
+
}
|
|
631539
|
+
if (activeTask) return false;
|
|
631540
|
+
queuePrompt(reminderActionPrompt(reminder), "reminder");
|
|
631541
|
+
drainQueuedPrompts();
|
|
631542
|
+
return true;
|
|
631543
|
+
}
|
|
631544
|
+
if (mode === "minimal") {
|
|
631545
|
+
writeContent(() => renderInfo(reminderText(reminder)));
|
|
631546
|
+
showPrompt();
|
|
631547
|
+
return true;
|
|
631548
|
+
}
|
|
631549
|
+
if (activeTask) {
|
|
631550
|
+
queuePrompt(reminderActionPrompt(reminder), "reminder");
|
|
631551
|
+
return true;
|
|
631552
|
+
}
|
|
631553
|
+
rl.emit("line", reminderActionPrompt(reminder));
|
|
631554
|
+
return true;
|
|
631555
|
+
};
|
|
631556
|
+
const dispatchDueReminders = async () => {
|
|
631557
|
+
try {
|
|
631558
|
+
const sessionId = process.env["OMNIUS_SESSION_ID"] || "terminal";
|
|
631559
|
+
const dueBatches = await Promise.all([
|
|
631560
|
+
getDueReminders(repoRoot, {
|
|
631561
|
+
deliveryMode: "any",
|
|
631562
|
+
includeUnscoped: true,
|
|
631563
|
+
scope: { surface: "tui", targetId: sessionId }
|
|
631564
|
+
}),
|
|
631565
|
+
getDueReminders(repoRoot, {
|
|
631566
|
+
deliveryMode: "any",
|
|
631567
|
+
scope: { surface: "telegram" }
|
|
631568
|
+
}),
|
|
631569
|
+
getDueReminders(repoRoot, {
|
|
631570
|
+
deliveryMode: "any",
|
|
631571
|
+
scope: { surface: "global" }
|
|
631572
|
+
})
|
|
631573
|
+
]);
|
|
631574
|
+
const due = Array.from(
|
|
631575
|
+
new Map(dueBatches.flat().map((reminder) => [reminder.id, reminder])).values()
|
|
631576
|
+
);
|
|
631577
|
+
const dispatched = [];
|
|
631578
|
+
for (const reminder of due) {
|
|
631579
|
+
const ok2 = await dispatchDueReminder(reminder);
|
|
631580
|
+
if (ok2) dispatched.push(reminder.id);
|
|
631581
|
+
}
|
|
631582
|
+
if (dispatched.length > 0) {
|
|
631583
|
+
await markRemindersTriggered(repoRoot, dispatched);
|
|
631584
|
+
}
|
|
631585
|
+
} catch {
|
|
631586
|
+
}
|
|
631587
|
+
};
|
|
631588
|
+
const startReminderDispatcher = () => {
|
|
631589
|
+
if (reminderDispatchTimer) return;
|
|
631590
|
+
reminderDispatchTimer = setInterval(() => {
|
|
631591
|
+
dispatchDueReminders().catch(() => {
|
|
631592
|
+
});
|
|
631593
|
+
}, 15e3);
|
|
631594
|
+
dispatchDueReminders().catch(() => {
|
|
631595
|
+
});
|
|
631596
|
+
};
|
|
630663
631597
|
const listRollbackCheckpoints = () => {
|
|
630664
631598
|
const out = [];
|
|
630665
631599
|
const pushJsonFiles = (dir, prefix) => {
|
|
@@ -631752,6 +632686,10 @@ Log: ${nexusLogPath}`)
|
|
|
631752
632686
|
statusBar.refreshHeaderContent();
|
|
631753
632687
|
},
|
|
631754
632688
|
exit() {
|
|
632689
|
+
if (reminderDispatchTimer) {
|
|
632690
|
+
clearInterval(reminderDispatchTimer);
|
|
632691
|
+
reminderDispatchTimer = null;
|
|
632692
|
+
}
|
|
631755
632693
|
statusBar.deactivate();
|
|
631756
632694
|
if (carousel.isRunning) carousel.stop();
|
|
631757
632695
|
banner.stop();
|
|
@@ -633697,17 +634635,12 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
633697
634635
|
});
|
|
633698
634636
|
showPrompt();
|
|
633699
634637
|
}, 300);
|
|
633700
|
-
if (dueReminders.length > 0) {
|
|
633701
|
-
await markRemindersSeen(
|
|
633702
|
-
repoRoot,
|
|
633703
|
-
dueReminders.map((r2) => r2.id)
|
|
633704
|
-
);
|
|
633705
|
-
}
|
|
633706
634638
|
}
|
|
633707
634639
|
} catch {
|
|
633708
634640
|
}
|
|
633709
634641
|
})();
|
|
633710
634642
|
}
|
|
634643
|
+
startReminderDispatcher();
|
|
633711
634644
|
if (hasTaskToResume) {
|
|
633712
634645
|
const pendingTask = loadPendingTask(repoRoot);
|
|
633713
634646
|
if (pendingTask) {
|