@sideboard-ai/core 0.1.326 → 0.1.327
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/{abletime-RYYFGKMU.js → abletime-NW4PJGHN.js} +4 -5
- package/dist/{abletime-RDHYSZL2.js → abletime-OW7LTFQD.js} +4 -5
- package/dist/{abletime-oauth-OYGS2DAU.js → abletime-oauth-KWQQRHOQ.js} +3 -4
- package/dist/{abletime-oauth-QR2QDVMK.js → abletime-oauth-TPR2QDRI.js} +3 -4
- package/dist/{abletime-rest-QDPTWNS4.js → abletime-rest-5DCWN3P4.js} +3 -4
- package/dist/{abletime-rest-BKYKNPTC.js → abletime-rest-UJ6SXDBN.js} +3 -4
- package/dist/agents/claude-runner.cjs +11 -0
- package/dist/agents/claude-runner.js +7 -1
- package/dist/{agents-QO7GKBYT.js → agents-IYBY3JT5.js} +8 -9
- package/dist/{agents-HANWZNI6.js → agents-XWIPONJR.js} +8 -9
- package/dist/{app-settings-RXBH7KY4.js → app-settings-A5D364JD.js} +1 -2
- package/dist/{app-settings-TUVLZNDE.js → app-settings-SA4HX3ZQ.js} +1 -2
- package/dist/{chunk-3Q4XNYHY.js → chunk-2GEUFPQQ.js} +1 -1
- package/dist/{chunk-MAW7DIG7.js → chunk-4F7THWIO.js} +2 -2
- package/dist/{chunk-K7M7MIWL.js → chunk-4G3W23X3.js} +3 -3
- package/dist/{chunk-Q3FHTGIW.js → chunk-5Y2C7Q55.js} +441 -20
- package/dist/{chunk-TMCK5TLA.js → chunk-ATQLP22S.js} +1 -1
- package/dist/{chunk-PB6HW7SA.js → chunk-CHYUUETG.js} +3 -3
- package/dist/{chunk-QPSKQP6E.js → chunk-D446IWPP.js} +48 -3
- package/dist/{chunk-C7HUCBX7.js → chunk-DACWFN4O.js} +5 -5
- package/dist/{chunk-GP3RLZ6A.js → chunk-DEB47BII.js} +51 -487
- package/dist/{chunk-B244TJWC.js → chunk-ECY7WL6T.js} +2 -2
- package/dist/{chunk-D744HOI5.js → chunk-EJRCHCXM.js} +18 -3
- package/dist/{chunk-KXRF6RNL.js → chunk-EUIVQAPK.js} +2 -2
- package/dist/{chunk-46FECFZU.js → chunk-IXWPCOLQ.js} +8 -195
- package/dist/{chunk-75RPUXJS.js → chunk-JKHCADKB.js} +5 -5
- package/dist/{chunk-4H5MWZ6J.js → chunk-KLVW3J2B.js} +2 -2
- package/dist/{chunk-QG4CYRA3.js → chunk-MO46K6WK.js} +14 -14
- package/dist/{chunk-F2PVRF3B.js → chunk-N6ZF3XRP.js} +2 -1
- package/dist/{chunk-BBNWKL4I.js → chunk-NQGLDQYB.js} +8 -8
- package/dist/{chunk-YGVGXQA7.js → chunk-Q4UPRQOS.js} +12 -12
- package/dist/{chunk-ZUAYA57W.js → chunk-QMLDR63X.js} +2 -2
- package/dist/{chunk-KECHK3ZT.js → chunk-R2C45NHT.js} +2 -2
- package/dist/{chunk-FWVUGLBG.js → chunk-RDXODLEN.js} +4 -4
- package/dist/{chunk-XLVLMQKN.js → chunk-RZJ3QJZT.js} +11 -11
- package/dist/{chunk-JM2TGOHP.js → chunk-SB5ADEZZ.js} +5 -5
- package/dist/{chunk-SO7G6O24.js → chunk-SFXGD5KJ.js} +1 -1
- package/dist/{chunk-LRHUBGEM.js → chunk-TUH4ICHQ.js} +1 -1
- package/dist/chunk-ULWPSBAB.js +192 -0
- package/dist/{chunk-WUCAVIIP.js → chunk-UMXBH344.js} +1 -1
- package/dist/{chunk-RZVOX2MT.js → chunk-XBBZZHJY.js} +3 -3
- package/dist/{chunk-ZSHS46V5.js → chunk-Y6OHM672.js} +476 -20
- package/dist/{chunk-2EOLWHXH.js → chunk-YUHZEIVG.js} +69 -473
- package/dist/{chunk-YWQF7WAG.js → chunk-ZPBOWO64.js} +2 -2
- package/dist/{conductor-4GVTHUUB.js → conductor-CP7TW6TN.js} +7 -7
- package/dist/{conductor-TGWI6ETZ.js → conductor-D62Q2XJC.js} +6 -7
- package/dist/{coordinator-prompt-3E6SIDTM.js → coordinator-prompt-3PJLU3UH.js} +5 -6
- package/dist/{coordinator-prompt-WEYJREV6.js → coordinator-prompt-J7O7JB26.js} +5 -6
- package/dist/{global-workspace-UIEXAG2B.js → global-workspace-4CTLU2BV.js} +5 -6
- package/dist/{global-workspace-FPDZKUPF.js → global-workspace-Y3UDZYJX.js} +5 -6
- package/dist/index.cjs +507 -492
- package/dist/index.d.cts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +67 -65
- package/dist/{linear-6S7MK5YK.js → linear-CXWGH2TW.js} +2 -3
- package/dist/{linear-Z2T4KUAQ.js → linear-WLDCJ3AF.js} +2 -3
- package/dist/{linear-list-Q4M7AZO2.js → linear-list-52LEDEWO.js} +1 -1
- package/dist/{linear-list-A37WLUBO.js → linear-list-FGVN65JU.js} +1 -1
- package/dist/mcp/run-stdio.cjs +19654 -19641
- package/dist/mcp/run-stdio.js +33 -34
- package/dist/{optional-cli-CA4LL322.js → optional-cli-FN4MGB6W.js} +4 -5
- package/dist/{optional-cli-AANBL4U5.js → optional-cli-INRVBBBG.js} +3 -4
- package/dist/{orchestrator-7FVDBE7Y.js → orchestrator-EN3ZKD73.js} +12 -12
- package/dist/{orchestrator-RQXRZW7Z.js → orchestrator-W4TZBBDO.js} +11 -12
- package/dist/{thread-store-4ZN3DS2W.js → thread-store-4WE24XA2.js} +6 -2
- package/dist/{thread-store-IC4BQXDW.js → thread-store-K2ZNGUSM.js} +7 -3
- package/dist/{workspaces-LEW4UP56.js → workspaces-MM7CQYR6.js} +5 -6
- package/dist/{workspaces-QONNLHNR.js → workspaces-WYCVZ6XH.js} +5 -6
- package/dist/{worktree-KFEJAQ2H.js → worktree-JBNEMJ5Z.js} +7 -8
- package/dist/{worktree-6GIONDQO.js → worktree-NNVRGPP4.js} +4 -5
- package/package.json +1 -1
- package/dist/chunk-77WWLBCI.js +0 -50
- package/dist/chunk-KGZBYWZ3.js +0 -23
package/dist/index.cjs
CHANGED
|
@@ -133,7 +133,8 @@ var init_claude_mcp = __esm({
|
|
|
133
133
|
"TaskStop",
|
|
134
134
|
"EnterWorktree",
|
|
135
135
|
"ExitWorktree",
|
|
136
|
-
"Skill"
|
|
136
|
+
"Skill",
|
|
137
|
+
"AskUserQuestion"
|
|
137
138
|
];
|
|
138
139
|
CLAUDE_PRINT_BG_WAIT_CEILING_MS = 72e5;
|
|
139
140
|
CLAUDE_CHROME_ALLOWED_TOOLS = [
|
|
@@ -5185,6 +5186,449 @@ var init_cursor_store = __esm({
|
|
|
5185
5186
|
}
|
|
5186
5187
|
});
|
|
5187
5188
|
|
|
5189
|
+
// src/store/schedule-when.ts
|
|
5190
|
+
function parseDurationMs(every) {
|
|
5191
|
+
const m = every.trim().match(DURATION_RE);
|
|
5192
|
+
if (!m) return null;
|
|
5193
|
+
const n = Number.parseInt(m[1], 10);
|
|
5194
|
+
if (!Number.isFinite(n) || n <= 0) return null;
|
|
5195
|
+
const unit = m[2].toLowerCase();
|
|
5196
|
+
return n * UNIT_MS[unit];
|
|
5197
|
+
}
|
|
5198
|
+
function dayIndex(token) {
|
|
5199
|
+
const text7 = token.trim().toLowerCase();
|
|
5200
|
+
if (/^[0-6]$/.test(text7)) return Number(text7);
|
|
5201
|
+
return DAY_ALIASES[text7];
|
|
5202
|
+
}
|
|
5203
|
+
function normalizeWeekdays(days) {
|
|
5204
|
+
const set = /* @__PURE__ */ new Set();
|
|
5205
|
+
for (const day of days) {
|
|
5206
|
+
if (!Number.isInteger(day) || day < 0 || day > 6) {
|
|
5207
|
+
throw new Error("Days must be 0 (Sunday) through 6 (Saturday)");
|
|
5208
|
+
}
|
|
5209
|
+
set.add(day);
|
|
5210
|
+
}
|
|
5211
|
+
if (set.size === 0) throw new Error("Pick at least one day");
|
|
5212
|
+
return [...set].sort((a, b) => a - b);
|
|
5213
|
+
}
|
|
5214
|
+
function parseWeeklyDays(raw) {
|
|
5215
|
+
const text7 = raw.trim().toLowerCase();
|
|
5216
|
+
if (!text7) throw new Error("Pick at least one day");
|
|
5217
|
+
if (text7 === "daily" || text7 === "all" || text7 === "every day" || text7 === "everyday") {
|
|
5218
|
+
return [0, 1, 2, 3, 4, 5, 6];
|
|
5219
|
+
}
|
|
5220
|
+
if (text7 === "weekdays" || text7 === "weekday") return [1, 2, 3, 4, 5];
|
|
5221
|
+
if (text7 === "weekends" || text7 === "weekend") return [0, 6];
|
|
5222
|
+
const days = [];
|
|
5223
|
+
for (const part of text7.split(/[\s,]+/).filter(Boolean)) {
|
|
5224
|
+
const range = part.split("-");
|
|
5225
|
+
if (range.length === 2 && range[0] && range[1]) {
|
|
5226
|
+
const start = dayIndex(range[0]);
|
|
5227
|
+
const end = dayIndex(range[1]);
|
|
5228
|
+
if (start === void 0 || end === void 0) {
|
|
5229
|
+
throw new Error(`Unknown day: ${part} (use mon,tue, weekdays, weekends, or daily)`);
|
|
5230
|
+
}
|
|
5231
|
+
if (start <= end) {
|
|
5232
|
+
for (let d = start; d <= end; d++) days.push(d);
|
|
5233
|
+
} else {
|
|
5234
|
+
for (let d = start; d <= 6; d++) days.push(d);
|
|
5235
|
+
for (let d = 0; d <= end; d++) days.push(d);
|
|
5236
|
+
}
|
|
5237
|
+
continue;
|
|
5238
|
+
}
|
|
5239
|
+
const n = dayIndex(part);
|
|
5240
|
+
if (n === void 0) {
|
|
5241
|
+
throw new Error(`Unknown day: ${part} (use mon,tue, weekdays, weekends, or daily)`);
|
|
5242
|
+
}
|
|
5243
|
+
days.push(n);
|
|
5244
|
+
}
|
|
5245
|
+
return normalizeWeekdays(days);
|
|
5246
|
+
}
|
|
5247
|
+
function normalizeWeeklyTime(raw) {
|
|
5248
|
+
const m = raw.trim().match(TIME_RE);
|
|
5249
|
+
if (!m) throw new Error(`Invalid time: ${raw} (use HH:mm, 24-hour)`);
|
|
5250
|
+
return `${m[1]}:${m[2]}`;
|
|
5251
|
+
}
|
|
5252
|
+
function formatWeeklyDays(days) {
|
|
5253
|
+
const key = normalizeWeekdays(days).join(",");
|
|
5254
|
+
if (key === "0,1,2,3,4,5,6") return "daily";
|
|
5255
|
+
if (key === "1,2,3,4,5") return "weekdays";
|
|
5256
|
+
if (key === "0,6") return "weekends";
|
|
5257
|
+
return normalizeWeekdays(days).map((day) => WEEKDAY_LABELS[day]).join(", ");
|
|
5258
|
+
}
|
|
5259
|
+
function weeklyCronExpr(when) {
|
|
5260
|
+
const time = normalizeWeeklyTime(when.time);
|
|
5261
|
+
const [hh, mm] = time.split(":");
|
|
5262
|
+
const days = normalizeWeekdays(when.days);
|
|
5263
|
+
return `${Number(mm)} ${Number(hh)} * * ${days.join(",")}`;
|
|
5264
|
+
}
|
|
5265
|
+
function computeNextRunAt(when, from = /* @__PURE__ */ new Date()) {
|
|
5266
|
+
if (when.kind === "once") {
|
|
5267
|
+
const at = new Date(when.at);
|
|
5268
|
+
if (Number.isNaN(at.getTime())) {
|
|
5269
|
+
throw new Error(`Invalid once-at datetime: ${when.at}`);
|
|
5270
|
+
}
|
|
5271
|
+
return at;
|
|
5272
|
+
}
|
|
5273
|
+
if (when.kind === "every") {
|
|
5274
|
+
const ms = parseDurationMs(when.every);
|
|
5275
|
+
if (!ms) {
|
|
5276
|
+
throw new Error(`Invalid interval: ${when.every} (use 15m, 1h, 6h, 1d)`);
|
|
5277
|
+
}
|
|
5278
|
+
return new Date(from.getTime() + ms);
|
|
5279
|
+
}
|
|
5280
|
+
if (when.kind === "weekly") {
|
|
5281
|
+
return computeNextRunAt(
|
|
5282
|
+
{ kind: "cron", expr: weeklyCronExpr(when), tz: when.tz },
|
|
5283
|
+
from
|
|
5284
|
+
);
|
|
5285
|
+
}
|
|
5286
|
+
try {
|
|
5287
|
+
const job = new import_croner.Cron(when.expr, {
|
|
5288
|
+
timezone: when.tz?.trim() || void 0,
|
|
5289
|
+
paused: true
|
|
5290
|
+
});
|
|
5291
|
+
const next = job.nextRun(from);
|
|
5292
|
+
if (!next) {
|
|
5293
|
+
throw new Error(`Cron expression has no next run: ${when.expr}`);
|
|
5294
|
+
}
|
|
5295
|
+
return next;
|
|
5296
|
+
} catch (err) {
|
|
5297
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
5298
|
+
throw new Error(`Invalid cron: ${message}`);
|
|
5299
|
+
}
|
|
5300
|
+
}
|
|
5301
|
+
function formatScheduleWhen(when) {
|
|
5302
|
+
if (when.kind === "once") return `once at ${when.at}`;
|
|
5303
|
+
if (when.kind === "every") return `every ${when.every}`;
|
|
5304
|
+
if (when.kind === "weekly") {
|
|
5305
|
+
const label = `${formatWeeklyDays(when.days)} at ${normalizeWeeklyTime(when.time)}`;
|
|
5306
|
+
const tz2 = when.tz?.trim();
|
|
5307
|
+
return tz2 ? `${label} (${tz2})` : label;
|
|
5308
|
+
}
|
|
5309
|
+
const tz = when.tz?.trim();
|
|
5310
|
+
return tz ? `cron ${when.expr} (${tz})` : `cron ${when.expr}`;
|
|
5311
|
+
}
|
|
5312
|
+
function normalizeWhen(raw) {
|
|
5313
|
+
if (!raw || typeof raw !== "object") {
|
|
5314
|
+
throw new Error("Schedule is missing `when`");
|
|
5315
|
+
}
|
|
5316
|
+
const rec = raw;
|
|
5317
|
+
const kind = rec.kind;
|
|
5318
|
+
if (kind === "once" && typeof rec.at === "string") {
|
|
5319
|
+
return { kind: "once", at: rec.at };
|
|
5320
|
+
}
|
|
5321
|
+
if (kind === "every" && typeof rec.every === "string") {
|
|
5322
|
+
return { kind: "every", every: rec.every };
|
|
5323
|
+
}
|
|
5324
|
+
if (kind === "cron" && typeof rec.expr === "string") {
|
|
5325
|
+
return {
|
|
5326
|
+
kind: "cron",
|
|
5327
|
+
expr: rec.expr,
|
|
5328
|
+
tz: typeof rec.tz === "string" && rec.tz.trim() ? rec.tz.trim() : void 0
|
|
5329
|
+
};
|
|
5330
|
+
}
|
|
5331
|
+
if (kind === "weekly" && Array.isArray(rec.days) && typeof rec.time === "string") {
|
|
5332
|
+
return {
|
|
5333
|
+
kind: "weekly",
|
|
5334
|
+
days: normalizeWeekdays(rec.days.map((day) => Number(day))),
|
|
5335
|
+
time: normalizeWeeklyTime(rec.time),
|
|
5336
|
+
tz: typeof rec.tz === "string" && rec.tz.trim() ? rec.tz.trim() : void 0
|
|
5337
|
+
};
|
|
5338
|
+
}
|
|
5339
|
+
throw new Error("Schedule `when` must be once, every, weekly, or cron");
|
|
5340
|
+
}
|
|
5341
|
+
var import_croner, WEEKDAY_LABELS, DURATION_RE, UNIT_MS, DAY_ALIASES, TIME_RE;
|
|
5342
|
+
var init_schedule_when = __esm({
|
|
5343
|
+
"src/store/schedule-when.ts"() {
|
|
5344
|
+
"use strict";
|
|
5345
|
+
import_croner = require("croner");
|
|
5346
|
+
WEEKDAY_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
5347
|
+
DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
5348
|
+
UNIT_MS = {
|
|
5349
|
+
s: 1e3,
|
|
5350
|
+
m: 6e4,
|
|
5351
|
+
h: 36e5,
|
|
5352
|
+
d: 864e5
|
|
5353
|
+
};
|
|
5354
|
+
DAY_ALIASES = {
|
|
5355
|
+
sun: 0,
|
|
5356
|
+
sunday: 0,
|
|
5357
|
+
mon: 1,
|
|
5358
|
+
monday: 1,
|
|
5359
|
+
tue: 2,
|
|
5360
|
+
tues: 2,
|
|
5361
|
+
tuesday: 2,
|
|
5362
|
+
wed: 3,
|
|
5363
|
+
wednesday: 3,
|
|
5364
|
+
thu: 4,
|
|
5365
|
+
thur: 4,
|
|
5366
|
+
thurs: 4,
|
|
5367
|
+
thursday: 4,
|
|
5368
|
+
fri: 5,
|
|
5369
|
+
friday: 5,
|
|
5370
|
+
sat: 6,
|
|
5371
|
+
saturday: 6
|
|
5372
|
+
};
|
|
5373
|
+
TIME_RE = /^([01]\d|2[0-3]):([0-5]\d)(?::[0-5]\d)?$/;
|
|
5374
|
+
}
|
|
5375
|
+
});
|
|
5376
|
+
|
|
5377
|
+
// src/store/schedules.ts
|
|
5378
|
+
function schedulesPath() {
|
|
5379
|
+
return (0, import_node_path15.join)(appDataDir(), "schedules.json");
|
|
5380
|
+
}
|
|
5381
|
+
function defaultScheduleName(prompt) {
|
|
5382
|
+
const line = prompt.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
5383
|
+
if (!line) return "Untitled automation";
|
|
5384
|
+
return line.length > 60 ? `${line.slice(0, 57).trimEnd()}\u2026` : line;
|
|
5385
|
+
}
|
|
5386
|
+
function resolveScheduleThreadId(raw, env = process.env) {
|
|
5387
|
+
const value = raw?.trim() || "";
|
|
5388
|
+
if (!value) return null;
|
|
5389
|
+
if (value.toLowerCase() === "self") {
|
|
5390
|
+
return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || env.SIDEBOARD_THREAD_ID?.trim() || null;
|
|
5391
|
+
}
|
|
5392
|
+
return value;
|
|
5393
|
+
}
|
|
5394
|
+
function nowIso(d = /* @__PURE__ */ new Date()) {
|
|
5395
|
+
return d.toISOString();
|
|
5396
|
+
}
|
|
5397
|
+
function normalizeOptionalBool(raw) {
|
|
5398
|
+
if (raw === true || raw === false) return raw;
|
|
5399
|
+
return null;
|
|
5400
|
+
}
|
|
5401
|
+
function normalizeAutonomy2(raw) {
|
|
5402
|
+
return raw === "default" || raw === "full" ? raw : null;
|
|
5403
|
+
}
|
|
5404
|
+
function normalizeAttachments(raw) {
|
|
5405
|
+
if (!Array.isArray(raw)) return [];
|
|
5406
|
+
const out = [];
|
|
5407
|
+
for (const item of raw) {
|
|
5408
|
+
if (!item || typeof item !== "object") continue;
|
|
5409
|
+
const row2 = item;
|
|
5410
|
+
if (typeof row2.id !== "string" || !row2.id.trim()) continue;
|
|
5411
|
+
if (typeof row2.name !== "string" || !row2.name) continue;
|
|
5412
|
+
if (typeof row2.content !== "string") continue;
|
|
5413
|
+
if (!ATTACHMENT_KINDS.has(row2.kind)) continue;
|
|
5414
|
+
const next = {
|
|
5415
|
+
id: row2.id,
|
|
5416
|
+
name: row2.name,
|
|
5417
|
+
kind: row2.kind,
|
|
5418
|
+
content: row2.content
|
|
5419
|
+
};
|
|
5420
|
+
if (typeof row2.path === "string" && row2.path) next.path = row2.path;
|
|
5421
|
+
if (typeof row2.previewDataUrl === "string" && row2.previewDataUrl) {
|
|
5422
|
+
next.previewDataUrl = row2.previewDataUrl;
|
|
5423
|
+
}
|
|
5424
|
+
out.push(next);
|
|
5425
|
+
}
|
|
5426
|
+
return out;
|
|
5427
|
+
}
|
|
5428
|
+
function normalizeTask(raw) {
|
|
5429
|
+
const when = normalizeWhen(raw.when);
|
|
5430
|
+
const agent = raw.agent && isOrchestratorCapableAgent(raw.agent) ? raw.agent : null;
|
|
5431
|
+
return {
|
|
5432
|
+
id: raw.id,
|
|
5433
|
+
name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : defaultScheduleName(raw.prompt),
|
|
5434
|
+
prompt: String(raw.prompt ?? ""),
|
|
5435
|
+
enabled: Boolean(raw.enabled),
|
|
5436
|
+
when,
|
|
5437
|
+
threadId: raw.threadId?.trim() || null,
|
|
5438
|
+
agent,
|
|
5439
|
+
model: raw.model?.trim() || null,
|
|
5440
|
+
effort: normalizeThinkingEffort(raw.effort),
|
|
5441
|
+
fast: normalizeOptionalBool(raw.fast),
|
|
5442
|
+
planMode: normalizeOptionalBool(raw.planMode),
|
|
5443
|
+
autonomy: normalizeAutonomy2(raw.autonomy),
|
|
5444
|
+
attachments: normalizeAttachments(raw.attachments),
|
|
5445
|
+
archiveChat: raw.archiveChat !== false,
|
|
5446
|
+
nextRunAt: raw.nextRunAt,
|
|
5447
|
+
lastRunAt: raw.lastRunAt ?? null,
|
|
5448
|
+
lastThreadId: raw.lastThreadId ?? null,
|
|
5449
|
+
lastError: raw.lastError ?? null,
|
|
5450
|
+
createdBy: raw.createdBy === "mcp" || raw.createdBy === "cli" || raw.createdBy === "ui" ? raw.createdBy : "ui",
|
|
5451
|
+
createdAt: raw.createdAt,
|
|
5452
|
+
updatedAt: raw.updatedAt
|
|
5453
|
+
};
|
|
5454
|
+
}
|
|
5455
|
+
function readAll() {
|
|
5456
|
+
const path2 = schedulesPath();
|
|
5457
|
+
if (!(0, import_node_fs12.existsSync)(path2)) return [];
|
|
5458
|
+
try {
|
|
5459
|
+
const parsed = JSON.parse((0, import_node_fs12.readFileSync)(path2, "utf8"));
|
|
5460
|
+
if (!Array.isArray(parsed)) return [];
|
|
5461
|
+
return parsed.map((row2) => {
|
|
5462
|
+
try {
|
|
5463
|
+
return normalizeTask(row2);
|
|
5464
|
+
} catch {
|
|
5465
|
+
return null;
|
|
5466
|
+
}
|
|
5467
|
+
}).filter((row2) => Boolean(row2?.id && row2.prompt));
|
|
5468
|
+
} catch {
|
|
5469
|
+
return [];
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
function writeAll(rows) {
|
|
5473
|
+
writePrivateFile(schedulesPath(), `${JSON.stringify(rows, null, 2)}
|
|
5474
|
+
`);
|
|
5475
|
+
}
|
|
5476
|
+
function buildTask(input, now) {
|
|
5477
|
+
const prompt = input.prompt.trim();
|
|
5478
|
+
if (!prompt) throw new Error("Schedule prompt is required");
|
|
5479
|
+
const when = normalizeWhen(input.when);
|
|
5480
|
+
const nextRunAt = computeNextRunAt(when, now).toISOString();
|
|
5481
|
+
const ts = nowIso(now);
|
|
5482
|
+
const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
|
|
5483
|
+
return {
|
|
5484
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
5485
|
+
name: input.name?.trim() || defaultScheduleName(prompt),
|
|
5486
|
+
prompt,
|
|
5487
|
+
enabled: input.enabled !== false,
|
|
5488
|
+
when,
|
|
5489
|
+
threadId: input.threadId?.trim() || null,
|
|
5490
|
+
agent,
|
|
5491
|
+
model: input.model?.trim() || null,
|
|
5492
|
+
effort: input.effort != null ? normalizeThinkingEffort(input.effort) : null,
|
|
5493
|
+
fast: normalizeOptionalBool(input.fast),
|
|
5494
|
+
planMode: normalizeOptionalBool(input.planMode),
|
|
5495
|
+
autonomy: normalizeAutonomy2(input.autonomy),
|
|
5496
|
+
attachments: normalizeAttachments(input.attachments),
|
|
5497
|
+
archiveChat: input.archiveChat !== false,
|
|
5498
|
+
nextRunAt,
|
|
5499
|
+
lastRunAt: null,
|
|
5500
|
+
lastThreadId: null,
|
|
5501
|
+
lastError: null,
|
|
5502
|
+
createdBy: input.createdBy,
|
|
5503
|
+
createdAt: ts,
|
|
5504
|
+
updatedAt: ts
|
|
5505
|
+
};
|
|
5506
|
+
}
|
|
5507
|
+
function listSchedules() {
|
|
5508
|
+
return readAll().sort((a, b) => a.nextRunAt.localeCompare(b.nextRunAt));
|
|
5509
|
+
}
|
|
5510
|
+
function hasEnabledSchedules() {
|
|
5511
|
+
return listSchedules().some((row2) => row2.enabled);
|
|
5512
|
+
}
|
|
5513
|
+
function scheduleNeedsCaffeinate(task, now = /* @__PURE__ */ new Date()) {
|
|
5514
|
+
if (!task.enabled) return false;
|
|
5515
|
+
const at = new Date(task.nextRunAt);
|
|
5516
|
+
if (Number.isNaN(at.getTime())) return false;
|
|
5517
|
+
return at.getTime() > now.getTime();
|
|
5518
|
+
}
|
|
5519
|
+
function ensureCaffeinateForFutureSchedule(task) {
|
|
5520
|
+
if (!scheduleNeedsCaffeinate(task)) return;
|
|
5521
|
+
if (caffeinateWhileSchedulesEnabled()) return;
|
|
5522
|
+
updateAdvancedSettings({ caffeinateWhileSchedules: true });
|
|
5523
|
+
}
|
|
5524
|
+
function getSchedule(id) {
|
|
5525
|
+
const key = id.trim();
|
|
5526
|
+
if (!key) return null;
|
|
5527
|
+
return readAll().find(
|
|
5528
|
+
(row2) => row2.id === key || row2.id.startsWith(key) && key.length >= 8
|
|
5529
|
+
) ?? null;
|
|
5530
|
+
}
|
|
5531
|
+
function createSchedule(input) {
|
|
5532
|
+
const task = buildTask(input, /* @__PURE__ */ new Date());
|
|
5533
|
+
const rows = readAll();
|
|
5534
|
+
rows.push(task);
|
|
5535
|
+
writeAll(rows);
|
|
5536
|
+
ensureCaffeinateForFutureSchedule(task);
|
|
5537
|
+
return task;
|
|
5538
|
+
}
|
|
5539
|
+
function updateSchedule(id, patch) {
|
|
5540
|
+
const rows = readAll();
|
|
5541
|
+
const idx = rows.findIndex((row2) => row2.id === id || id.length >= 8 && row2.id.startsWith(id));
|
|
5542
|
+
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
5543
|
+
const prev = rows[idx];
|
|
5544
|
+
const when = patch.when ? normalizeWhen(patch.when) : prev.when;
|
|
5545
|
+
const prompt = patch.prompt !== void 0 ? patch.prompt.trim() : prev.prompt;
|
|
5546
|
+
if (!prompt) throw new Error("Schedule prompt is required");
|
|
5547
|
+
const whenChanged = patch.when !== void 0;
|
|
5548
|
+
const next = {
|
|
5549
|
+
...prev,
|
|
5550
|
+
name: patch.name !== void 0 ? patch.name.trim() || defaultScheduleName(prompt) : prev.name,
|
|
5551
|
+
prompt,
|
|
5552
|
+
enabled: patch.enabled ?? prev.enabled,
|
|
5553
|
+
when,
|
|
5554
|
+
threadId: patch.threadId !== void 0 ? patch.threadId?.trim() || null : prev.threadId,
|
|
5555
|
+
agent: patch.agent !== void 0 ? patch.agent ? coerceOrchestratorAgent(patch.agent) : null : prev.agent,
|
|
5556
|
+
model: patch.model !== void 0 ? patch.model?.trim() || null : prev.model,
|
|
5557
|
+
effort: patch.effort !== void 0 ? normalizeThinkingEffort(patch.effort) : prev.effort,
|
|
5558
|
+
fast: patch.fast !== void 0 ? normalizeOptionalBool(patch.fast) : prev.fast,
|
|
5559
|
+
planMode: patch.planMode !== void 0 ? normalizeOptionalBool(patch.planMode) : prev.planMode,
|
|
5560
|
+
autonomy: patch.autonomy !== void 0 ? normalizeAutonomy2(patch.autonomy) : prev.autonomy,
|
|
5561
|
+
attachments: patch.attachments !== void 0 ? normalizeAttachments(patch.attachments) : prev.attachments,
|
|
5562
|
+
archiveChat: patch.archiveChat !== void 0 ? patch.archiveChat !== false : prev.archiveChat,
|
|
5563
|
+
nextRunAt: whenChanged ? computeNextRunAt(when).toISOString() : prev.nextRunAt,
|
|
5564
|
+
lastError: whenChanged ? null : prev.lastError,
|
|
5565
|
+
updatedAt: nowIso()
|
|
5566
|
+
};
|
|
5567
|
+
rows[idx] = next;
|
|
5568
|
+
writeAll(rows);
|
|
5569
|
+
ensureCaffeinateForFutureSchedule(next);
|
|
5570
|
+
return next;
|
|
5571
|
+
}
|
|
5572
|
+
function deleteSchedulesForThread(threadId) {
|
|
5573
|
+
const id = threadId.trim();
|
|
5574
|
+
if (!id) return;
|
|
5575
|
+
const rows = readAll();
|
|
5576
|
+
const next = rows.filter((row2) => row2.threadId !== id);
|
|
5577
|
+
if (next.length === rows.length) return;
|
|
5578
|
+
writeAll(next);
|
|
5579
|
+
}
|
|
5580
|
+
function deleteSchedule(id) {
|
|
5581
|
+
const rows = readAll();
|
|
5582
|
+
const next = rows.filter(
|
|
5583
|
+
(row2) => row2.id !== id && !(id.length >= 8 && row2.id.startsWith(id))
|
|
5584
|
+
);
|
|
5585
|
+
if (next.length === rows.length) throw new Error(`Automation not found: ${id}`);
|
|
5586
|
+
writeAll(next);
|
|
5587
|
+
}
|
|
5588
|
+
function recordScheduleRun(id, result) {
|
|
5589
|
+
const rows = readAll();
|
|
5590
|
+
const idx = rows.findIndex((row2) => row2.id === id);
|
|
5591
|
+
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
5592
|
+
const prev = rows[idx];
|
|
5593
|
+
const firedAt = result.firedAt ?? /* @__PURE__ */ new Date();
|
|
5594
|
+
const next = {
|
|
5595
|
+
...prev,
|
|
5596
|
+
enabled: prev.when.kind === "once" ? false : prev.enabled,
|
|
5597
|
+
nextRunAt: prev.when.kind === "once" ? prev.nextRunAt : computeNextRunAt(prev.when, firedAt).toISOString(),
|
|
5598
|
+
lastRunAt: nowIso(firedAt),
|
|
5599
|
+
lastThreadId: result.lastThreadId !== void 0 ? result.lastThreadId : prev.lastThreadId,
|
|
5600
|
+
lastError: result.lastError ?? null,
|
|
5601
|
+
updatedAt: nowIso(firedAt)
|
|
5602
|
+
};
|
|
5603
|
+
rows[idx] = next;
|
|
5604
|
+
writeAll(rows);
|
|
5605
|
+
return next;
|
|
5606
|
+
}
|
|
5607
|
+
var import_node_crypto5, import_node_fs12, import_node_path15, ATTACHMENT_KINDS;
|
|
5608
|
+
var init_schedules = __esm({
|
|
5609
|
+
"src/store/schedules.ts"() {
|
|
5610
|
+
"use strict";
|
|
5611
|
+
import_node_crypto5 = require("crypto");
|
|
5612
|
+
import_node_fs12 = require("fs");
|
|
5613
|
+
import_node_path15 = require("path");
|
|
5614
|
+
init_schedule_when();
|
|
5615
|
+
init_orchestrator_capable();
|
|
5616
|
+
init_thinking_effort();
|
|
5617
|
+
init_paths();
|
|
5618
|
+
init_private_file();
|
|
5619
|
+
init_app_settings();
|
|
5620
|
+
init_schedule_when();
|
|
5621
|
+
ATTACHMENT_KINDS = /* @__PURE__ */ new Set([
|
|
5622
|
+
"transcript",
|
|
5623
|
+
"file",
|
|
5624
|
+
"issue",
|
|
5625
|
+
"workspace",
|
|
5626
|
+
"diff-comment",
|
|
5627
|
+
"code-ref"
|
|
5628
|
+
]);
|
|
5629
|
+
}
|
|
5630
|
+
});
|
|
5631
|
+
|
|
5188
5632
|
// src/store/thread-store.ts
|
|
5189
5633
|
var thread_store_exports = {};
|
|
5190
5634
|
__export(thread_store_exports, {
|
|
@@ -5205,7 +5649,7 @@ __export(thread_store_exports, {
|
|
|
5205
5649
|
withThreadLock: () => withThreadLock,
|
|
5206
5650
|
writeThread: () => writeThread
|
|
5207
5651
|
});
|
|
5208
|
-
function
|
|
5652
|
+
function nowIso2() {
|
|
5209
5653
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5210
5654
|
}
|
|
5211
5655
|
function resolveThreadEffort(raw) {
|
|
@@ -5294,9 +5738,9 @@ function normalizeThread(raw) {
|
|
|
5294
5738
|
};
|
|
5295
5739
|
}
|
|
5296
5740
|
function createEmptyThread(partial) {
|
|
5297
|
-
const ts =
|
|
5741
|
+
const ts = nowIso2();
|
|
5298
5742
|
return {
|
|
5299
|
-
id: (0,
|
|
5743
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
5300
5744
|
sessionId: partial.sessionId ?? null,
|
|
5301
5745
|
autonomy: partial.autonomy ?? "default",
|
|
5302
5746
|
model: partial.model ?? null,
|
|
@@ -5349,7 +5793,7 @@ function createEmptyThread(partial) {
|
|
|
5349
5793
|
}
|
|
5350
5794
|
async function withThreadLock(id, fn) {
|
|
5351
5795
|
const lockPath = threadLockPath(id);
|
|
5352
|
-
(0,
|
|
5796
|
+
(0, import_node_fs13.writeFileSync)(lockPath, "", { flag: "a" });
|
|
5353
5797
|
let release;
|
|
5354
5798
|
try {
|
|
5355
5799
|
release = await import_proper_lockfile.default.lock(lockPath, {
|
|
@@ -5370,7 +5814,7 @@ function cacheForDir() {
|
|
|
5370
5814
|
}
|
|
5371
5815
|
function fileMtimeMs(path2) {
|
|
5372
5816
|
try {
|
|
5373
|
-
return (0,
|
|
5817
|
+
return (0, import_node_fs13.statSync)(path2).mtimeMs;
|
|
5374
5818
|
} catch {
|
|
5375
5819
|
return null;
|
|
5376
5820
|
}
|
|
@@ -5403,7 +5847,7 @@ function readThread(id) {
|
|
|
5403
5847
|
const cache2 = cacheForDir();
|
|
5404
5848
|
const cached2 = cache2.byId.get(id);
|
|
5405
5849
|
if (cached2 && cache2.mtimeMs.get(id) === mtimeMs) return cached2;
|
|
5406
|
-
const raw = (0,
|
|
5850
|
+
const raw = (0, import_node_fs13.readFileSync)(path2, "utf8");
|
|
5407
5851
|
const thread = normalizeThread(JSON.parse(raw));
|
|
5408
5852
|
rememberThread(thread, mtimeMs);
|
|
5409
5853
|
return thread;
|
|
@@ -5411,9 +5855,9 @@ function readThread(id) {
|
|
|
5411
5855
|
function writeThread(thread, opts) {
|
|
5412
5856
|
const path2 = threadFilePath(idPath(thread.id));
|
|
5413
5857
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
5414
|
-
const next = opts?.touch === false ? { ...thread } : { ...thread, updatedAt:
|
|
5415
|
-
(0,
|
|
5416
|
-
(0,
|
|
5858
|
+
const next = opts?.touch === false ? { ...thread } : { ...thread, updatedAt: nowIso2() };
|
|
5859
|
+
(0, import_node_fs13.writeFileSync)(tmp, JSON.stringify(next, null, 2), "utf8");
|
|
5860
|
+
(0, import_node_fs13.renameSync)(tmp, path2);
|
|
5417
5861
|
const mtimeMs = fileMtimeMs(path2) ?? Date.now();
|
|
5418
5862
|
rememberThread(next, mtimeMs);
|
|
5419
5863
|
selfWriteMtimes.set(thread.id, mtimeMs);
|
|
@@ -5427,12 +5871,12 @@ function idPath(id) {
|
|
|
5427
5871
|
return id;
|
|
5428
5872
|
}
|
|
5429
5873
|
function isThreadRecordFile(nameOrPath) {
|
|
5430
|
-
const name = (0,
|
|
5874
|
+
const name = (0, import_node_path16.basename)(nameOrPath);
|
|
5431
5875
|
return name.endsWith(".json") && !name.endsWith(".live.json") && !name.endsWith(".setup.log.json");
|
|
5432
5876
|
}
|
|
5433
5877
|
function listThreads(opts) {
|
|
5434
5878
|
const cache2 = cacheForDir();
|
|
5435
|
-
const files = (0,
|
|
5879
|
+
const files = (0, import_node_fs13.readdirSync)(threadsDir()).filter(isThreadRecordFile);
|
|
5436
5880
|
const seen = /* @__PURE__ */ new Set();
|
|
5437
5881
|
for (const f of files) {
|
|
5438
5882
|
const id = f.replace(/\.json$/, "");
|
|
@@ -5455,30 +5899,29 @@ function listThreads(opts) {
|
|
|
5455
5899
|
function deleteThreadRecord(id) {
|
|
5456
5900
|
forgetThread(id);
|
|
5457
5901
|
const path2 = threadFilePath(id);
|
|
5458
|
-
if ((0,
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
(0, import_node_fs12.unlinkSync)(lock);
|
|
5463
|
-
} catch {
|
|
5464
|
-
}
|
|
5902
|
+
if ((0, import_node_fs13.existsSync)(path2)) (0, import_node_fs13.unlinkSync)(path2);
|
|
5903
|
+
try {
|
|
5904
|
+
if ((0, import_node_fs13.existsSync)(threadLockPath(id))) (0, import_node_fs13.unlinkSync)(threadLockPath(id));
|
|
5905
|
+
} catch {
|
|
5465
5906
|
}
|
|
5466
5907
|
try {
|
|
5467
|
-
(0,
|
|
5908
|
+
(0, import_node_fs13.rmSync)(cursorSdkStoreDir(id), { recursive: true, force: true });
|
|
5468
5909
|
} catch {
|
|
5469
5910
|
}
|
|
5911
|
+
deleteSchedulesForThread(id);
|
|
5470
5912
|
}
|
|
5471
5913
|
function updateThread(id, patch) {
|
|
5472
5914
|
const current = readThread(id);
|
|
5473
5915
|
if (!current) throw new Error(`Thread not found: ${id}`);
|
|
5474
|
-
const next = { ...current, ...patch, id: current.id, updatedAt:
|
|
5916
|
+
const next = { ...current, ...patch, id: current.id, updatedAt: nowIso2() };
|
|
5475
5917
|
if (next.status === "archived") {
|
|
5476
|
-
next.archivedAt = typeof next.archivedAt === "string" && next.archivedAt.trim() || current.archivedAt ||
|
|
5918
|
+
next.archivedAt = typeof next.archivedAt === "string" && next.archivedAt.trim() || current.archivedAt || nowIso2();
|
|
5477
5919
|
} else {
|
|
5478
5920
|
delete next.archivedAt;
|
|
5479
5921
|
}
|
|
5480
5922
|
if (!next.ephemeralAutomationId?.trim()) delete next.ephemeralAutomationId;
|
|
5481
5923
|
writeThread(next);
|
|
5924
|
+
if (patch.status === "archived" && current.status !== "archived") deleteSchedulesForThread(current.id);
|
|
5482
5925
|
return next;
|
|
5483
5926
|
}
|
|
5484
5927
|
function appendMessage(id, message) {
|
|
@@ -5495,19 +5938,20 @@ function findThreadByRef(ref) {
|
|
|
5495
5938
|
(t) => t.id === ref || t.id.startsWith(ref) || t.branchName === ref || t.title === ref
|
|
5496
5939
|
) ?? null;
|
|
5497
5940
|
}
|
|
5498
|
-
var
|
|
5941
|
+
var import_node_crypto6, import_node_fs13, import_node_path16, import_proper_lockfile, listCache, selfWriteMtimes;
|
|
5499
5942
|
var init_thread_store = __esm({
|
|
5500
5943
|
"src/store/thread-store.ts"() {
|
|
5501
5944
|
"use strict";
|
|
5502
|
-
|
|
5945
|
+
import_node_crypto6 = require("crypto");
|
|
5503
5946
|
init_worktree_labels();
|
|
5504
|
-
|
|
5505
|
-
|
|
5947
|
+
import_node_fs13 = require("fs");
|
|
5948
|
+
import_node_path16 = require("path");
|
|
5506
5949
|
import_proper_lockfile = __toESM(require("proper-lockfile"), 1);
|
|
5507
5950
|
init_thinking_effort();
|
|
5508
5951
|
init_claude_mcp();
|
|
5509
5952
|
init_cursor_store();
|
|
5510
5953
|
init_paths();
|
|
5954
|
+
init_schedules();
|
|
5511
5955
|
listCache = null;
|
|
5512
5956
|
selfWriteMtimes = /* @__PURE__ */ new Map();
|
|
5513
5957
|
}
|
|
@@ -8038,11 +8482,11 @@ function materialize(mem) {
|
|
|
8038
8482
|
};
|
|
8039
8483
|
}
|
|
8040
8484
|
function setupLogPath(threadId) {
|
|
8041
|
-
return (0,
|
|
8485
|
+
return (0, import_node_path17.join)(threadsDir(), `${threadId}.setup.log.json`);
|
|
8042
8486
|
}
|
|
8043
8487
|
function setupLogKeyForWorktree(worktreePath) {
|
|
8044
8488
|
const norm = normalizeWorktreePath(worktreePath);
|
|
8045
|
-
return `wt-${(0,
|
|
8489
|
+
return `wt-${(0, import_node_crypto7.createHash)("sha1").update(norm).digest("hex").slice(0, 16)}`;
|
|
8046
8490
|
}
|
|
8047
8491
|
function emptySetupLog() {
|
|
8048
8492
|
return { ...EMPTY };
|
|
@@ -8064,7 +8508,7 @@ function persistNow(threadId) {
|
|
|
8064
8508
|
const mem = memory.get(threadId);
|
|
8065
8509
|
if (!mem) return;
|
|
8066
8510
|
try {
|
|
8067
|
-
(0,
|
|
8511
|
+
(0, import_node_fs14.writeFileSync)(
|
|
8068
8512
|
setupLogPath(threadId),
|
|
8069
8513
|
`${JSON.stringify(materialize(mem))}
|
|
8070
8514
|
`,
|
|
@@ -8085,9 +8529,9 @@ function schedulePersist(threadId) {
|
|
|
8085
8529
|
}
|
|
8086
8530
|
function loadFromDisk(threadId) {
|
|
8087
8531
|
const path2 = setupLogPath(threadId);
|
|
8088
|
-
if (!(0,
|
|
8532
|
+
if (!(0, import_node_fs14.existsSync)(path2)) return null;
|
|
8089
8533
|
try {
|
|
8090
|
-
const raw = JSON.parse((0,
|
|
8534
|
+
const raw = JSON.parse((0, import_node_fs14.readFileSync)(path2, "utf8"));
|
|
8091
8535
|
return {
|
|
8092
8536
|
output: typeof raw.output === "string" ? raw.output : "",
|
|
8093
8537
|
running: Boolean(raw.running),
|
|
@@ -8143,13 +8587,13 @@ function finishSetupLog(threadId, exitCode, source) {
|
|
|
8143
8587
|
persistNow(threadId);
|
|
8144
8588
|
return materialize(mem);
|
|
8145
8589
|
}
|
|
8146
|
-
var
|
|
8590
|
+
var import_node_crypto7, import_node_fs14, import_node_path17, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
|
|
8147
8591
|
var init_setup_log = __esm({
|
|
8148
8592
|
"src/store/setup-log.ts"() {
|
|
8149
8593
|
"use strict";
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8594
|
+
import_node_crypto7 = require("crypto");
|
|
8595
|
+
import_node_fs14 = require("fs");
|
|
8596
|
+
import_node_path17 = require("path");
|
|
8153
8597
|
init_worktree_labels();
|
|
8154
8598
|
init_paths();
|
|
8155
8599
|
EMPTY = {
|
|
@@ -8194,11 +8638,11 @@ function safeScriptToken(scriptName) {
|
|
|
8194
8638
|
return token || "dev";
|
|
8195
8639
|
}
|
|
8196
8640
|
function runLogPath(key) {
|
|
8197
|
-
return (0,
|
|
8641
|
+
return (0, import_node_path18.join)(threadsDir(), `${key}.run.log.json`);
|
|
8198
8642
|
}
|
|
8199
8643
|
function runLogKeyForWorktree(worktreePath, scriptName) {
|
|
8200
8644
|
const norm = normalizeWorktreePath(worktreePath);
|
|
8201
|
-
const hash = (0,
|
|
8645
|
+
const hash = (0, import_node_crypto8.createHash)("sha1").update(norm).digest("hex").slice(0, 16);
|
|
8202
8646
|
return `wt-${hash}-run-${safeScriptToken(scriptName)}`;
|
|
8203
8647
|
}
|
|
8204
8648
|
function emptyRunLog() {
|
|
@@ -8222,7 +8666,7 @@ function persistNow2(key) {
|
|
|
8222
8666
|
const mem = memory2.get(key);
|
|
8223
8667
|
if (!mem) return;
|
|
8224
8668
|
try {
|
|
8225
|
-
(0,
|
|
8669
|
+
(0, import_node_fs15.writeFileSync)(runLogPath(key), `${JSON.stringify(materialize2(mem))}
|
|
8226
8670
|
`, "utf8");
|
|
8227
8671
|
} catch {
|
|
8228
8672
|
}
|
|
@@ -8239,9 +8683,9 @@ function schedulePersist2(key) {
|
|
|
8239
8683
|
}
|
|
8240
8684
|
function loadFromDisk2(key) {
|
|
8241
8685
|
const path2 = runLogPath(key);
|
|
8242
|
-
if (!(0,
|
|
8686
|
+
if (!(0, import_node_fs15.existsSync)(path2)) return null;
|
|
8243
8687
|
try {
|
|
8244
|
-
const raw = JSON.parse((0,
|
|
8688
|
+
const raw = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
|
|
8245
8689
|
return {
|
|
8246
8690
|
output: typeof raw.output === "string" ? raw.output : "",
|
|
8247
8691
|
running: Boolean(raw.running),
|
|
@@ -8299,13 +8743,13 @@ function finishRunLog(key, exitCode) {
|
|
|
8299
8743
|
function flushRunLog(key) {
|
|
8300
8744
|
persistNow2(key);
|
|
8301
8745
|
}
|
|
8302
|
-
var
|
|
8746
|
+
var import_node_crypto8, import_node_fs15, import_node_path18, EMPTY2, MAX_RUN_LOG_CHARS, DEFAULT_RUN_LOG_TAIL_CHARS, memory2, persistTimers2, PERSIST_DEBOUNCE_MS2;
|
|
8303
8747
|
var init_run_log = __esm({
|
|
8304
8748
|
"src/store/run-log.ts"() {
|
|
8305
8749
|
"use strict";
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8750
|
+
import_node_crypto8 = require("crypto");
|
|
8751
|
+
import_node_fs15 = require("fs");
|
|
8752
|
+
import_node_path18 = require("path");
|
|
8309
8753
|
init_worktree_labels();
|
|
8310
8754
|
init_setup_log();
|
|
8311
8755
|
init_paths();
|
|
@@ -8323,441 +8767,6 @@ var init_run_log = __esm({
|
|
|
8323
8767
|
}
|
|
8324
8768
|
});
|
|
8325
8769
|
|
|
8326
|
-
// src/store/schedule-when.ts
|
|
8327
|
-
function parseDurationMs(every) {
|
|
8328
|
-
const m = every.trim().match(DURATION_RE);
|
|
8329
|
-
if (!m) return null;
|
|
8330
|
-
const n = Number.parseInt(m[1], 10);
|
|
8331
|
-
if (!Number.isFinite(n) || n <= 0) return null;
|
|
8332
|
-
const unit = m[2].toLowerCase();
|
|
8333
|
-
return n * UNIT_MS[unit];
|
|
8334
|
-
}
|
|
8335
|
-
function dayIndex(token) {
|
|
8336
|
-
const text7 = token.trim().toLowerCase();
|
|
8337
|
-
if (/^[0-6]$/.test(text7)) return Number(text7);
|
|
8338
|
-
return DAY_ALIASES[text7];
|
|
8339
|
-
}
|
|
8340
|
-
function normalizeWeekdays(days) {
|
|
8341
|
-
const set = /* @__PURE__ */ new Set();
|
|
8342
|
-
for (const day of days) {
|
|
8343
|
-
if (!Number.isInteger(day) || day < 0 || day > 6) {
|
|
8344
|
-
throw new Error("Days must be 0 (Sunday) through 6 (Saturday)");
|
|
8345
|
-
}
|
|
8346
|
-
set.add(day);
|
|
8347
|
-
}
|
|
8348
|
-
if (set.size === 0) throw new Error("Pick at least one day");
|
|
8349
|
-
return [...set].sort((a, b) => a - b);
|
|
8350
|
-
}
|
|
8351
|
-
function parseWeeklyDays(raw) {
|
|
8352
|
-
const text7 = raw.trim().toLowerCase();
|
|
8353
|
-
if (!text7) throw new Error("Pick at least one day");
|
|
8354
|
-
if (text7 === "daily" || text7 === "all" || text7 === "every day" || text7 === "everyday") {
|
|
8355
|
-
return [0, 1, 2, 3, 4, 5, 6];
|
|
8356
|
-
}
|
|
8357
|
-
if (text7 === "weekdays" || text7 === "weekday") return [1, 2, 3, 4, 5];
|
|
8358
|
-
if (text7 === "weekends" || text7 === "weekend") return [0, 6];
|
|
8359
|
-
const days = [];
|
|
8360
|
-
for (const part of text7.split(/[\s,]+/).filter(Boolean)) {
|
|
8361
|
-
const range = part.split("-");
|
|
8362
|
-
if (range.length === 2 && range[0] && range[1]) {
|
|
8363
|
-
const start = dayIndex(range[0]);
|
|
8364
|
-
const end = dayIndex(range[1]);
|
|
8365
|
-
if (start === void 0 || end === void 0) {
|
|
8366
|
-
throw new Error(`Unknown day: ${part} (use mon,tue, weekdays, weekends, or daily)`);
|
|
8367
|
-
}
|
|
8368
|
-
if (start <= end) {
|
|
8369
|
-
for (let d = start; d <= end; d++) days.push(d);
|
|
8370
|
-
} else {
|
|
8371
|
-
for (let d = start; d <= 6; d++) days.push(d);
|
|
8372
|
-
for (let d = 0; d <= end; d++) days.push(d);
|
|
8373
|
-
}
|
|
8374
|
-
continue;
|
|
8375
|
-
}
|
|
8376
|
-
const n = dayIndex(part);
|
|
8377
|
-
if (n === void 0) {
|
|
8378
|
-
throw new Error(`Unknown day: ${part} (use mon,tue, weekdays, weekends, or daily)`);
|
|
8379
|
-
}
|
|
8380
|
-
days.push(n);
|
|
8381
|
-
}
|
|
8382
|
-
return normalizeWeekdays(days);
|
|
8383
|
-
}
|
|
8384
|
-
function normalizeWeeklyTime(raw) {
|
|
8385
|
-
const m = raw.trim().match(TIME_RE);
|
|
8386
|
-
if (!m) throw new Error(`Invalid time: ${raw} (use HH:mm, 24-hour)`);
|
|
8387
|
-
return `${m[1]}:${m[2]}`;
|
|
8388
|
-
}
|
|
8389
|
-
function formatWeeklyDays(days) {
|
|
8390
|
-
const key = normalizeWeekdays(days).join(",");
|
|
8391
|
-
if (key === "0,1,2,3,4,5,6") return "daily";
|
|
8392
|
-
if (key === "1,2,3,4,5") return "weekdays";
|
|
8393
|
-
if (key === "0,6") return "weekends";
|
|
8394
|
-
return normalizeWeekdays(days).map((day) => WEEKDAY_LABELS[day]).join(", ");
|
|
8395
|
-
}
|
|
8396
|
-
function weeklyCronExpr(when) {
|
|
8397
|
-
const time = normalizeWeeklyTime(when.time);
|
|
8398
|
-
const [hh, mm] = time.split(":");
|
|
8399
|
-
const days = normalizeWeekdays(when.days);
|
|
8400
|
-
return `${Number(mm)} ${Number(hh)} * * ${days.join(",")}`;
|
|
8401
|
-
}
|
|
8402
|
-
function computeNextRunAt(when, from = /* @__PURE__ */ new Date()) {
|
|
8403
|
-
if (when.kind === "once") {
|
|
8404
|
-
const at = new Date(when.at);
|
|
8405
|
-
if (Number.isNaN(at.getTime())) {
|
|
8406
|
-
throw new Error(`Invalid once-at datetime: ${when.at}`);
|
|
8407
|
-
}
|
|
8408
|
-
return at;
|
|
8409
|
-
}
|
|
8410
|
-
if (when.kind === "every") {
|
|
8411
|
-
const ms = parseDurationMs(when.every);
|
|
8412
|
-
if (!ms) {
|
|
8413
|
-
throw new Error(`Invalid interval: ${when.every} (use 15m, 1h, 6h, 1d)`);
|
|
8414
|
-
}
|
|
8415
|
-
return new Date(from.getTime() + ms);
|
|
8416
|
-
}
|
|
8417
|
-
if (when.kind === "weekly") {
|
|
8418
|
-
return computeNextRunAt(
|
|
8419
|
-
{ kind: "cron", expr: weeklyCronExpr(when), tz: when.tz },
|
|
8420
|
-
from
|
|
8421
|
-
);
|
|
8422
|
-
}
|
|
8423
|
-
try {
|
|
8424
|
-
const job = new import_croner.Cron(when.expr, {
|
|
8425
|
-
timezone: when.tz?.trim() || void 0,
|
|
8426
|
-
paused: true
|
|
8427
|
-
});
|
|
8428
|
-
const next = job.nextRun(from);
|
|
8429
|
-
if (!next) {
|
|
8430
|
-
throw new Error(`Cron expression has no next run: ${when.expr}`);
|
|
8431
|
-
}
|
|
8432
|
-
return next;
|
|
8433
|
-
} catch (err) {
|
|
8434
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
8435
|
-
throw new Error(`Invalid cron: ${message}`);
|
|
8436
|
-
}
|
|
8437
|
-
}
|
|
8438
|
-
function formatScheduleWhen(when) {
|
|
8439
|
-
if (when.kind === "once") return `once at ${when.at}`;
|
|
8440
|
-
if (when.kind === "every") return `every ${when.every}`;
|
|
8441
|
-
if (when.kind === "weekly") {
|
|
8442
|
-
const label = `${formatWeeklyDays(when.days)} at ${normalizeWeeklyTime(when.time)}`;
|
|
8443
|
-
const tz2 = when.tz?.trim();
|
|
8444
|
-
return tz2 ? `${label} (${tz2})` : label;
|
|
8445
|
-
}
|
|
8446
|
-
const tz = when.tz?.trim();
|
|
8447
|
-
return tz ? `cron ${when.expr} (${tz})` : `cron ${when.expr}`;
|
|
8448
|
-
}
|
|
8449
|
-
function normalizeWhen(raw) {
|
|
8450
|
-
if (!raw || typeof raw !== "object") {
|
|
8451
|
-
throw new Error("Schedule is missing `when`");
|
|
8452
|
-
}
|
|
8453
|
-
const rec = raw;
|
|
8454
|
-
const kind = rec.kind;
|
|
8455
|
-
if (kind === "once" && typeof rec.at === "string") {
|
|
8456
|
-
return { kind: "once", at: rec.at };
|
|
8457
|
-
}
|
|
8458
|
-
if (kind === "every" && typeof rec.every === "string") {
|
|
8459
|
-
return { kind: "every", every: rec.every };
|
|
8460
|
-
}
|
|
8461
|
-
if (kind === "cron" && typeof rec.expr === "string") {
|
|
8462
|
-
return {
|
|
8463
|
-
kind: "cron",
|
|
8464
|
-
expr: rec.expr,
|
|
8465
|
-
tz: typeof rec.tz === "string" && rec.tz.trim() ? rec.tz.trim() : void 0
|
|
8466
|
-
};
|
|
8467
|
-
}
|
|
8468
|
-
if (kind === "weekly" && Array.isArray(rec.days) && typeof rec.time === "string") {
|
|
8469
|
-
return {
|
|
8470
|
-
kind: "weekly",
|
|
8471
|
-
days: normalizeWeekdays(rec.days.map((day) => Number(day))),
|
|
8472
|
-
time: normalizeWeeklyTime(rec.time),
|
|
8473
|
-
tz: typeof rec.tz === "string" && rec.tz.trim() ? rec.tz.trim() : void 0
|
|
8474
|
-
};
|
|
8475
|
-
}
|
|
8476
|
-
throw new Error("Schedule `when` must be once, every, weekly, or cron");
|
|
8477
|
-
}
|
|
8478
|
-
var import_croner, WEEKDAY_LABELS, DURATION_RE, UNIT_MS, DAY_ALIASES, TIME_RE;
|
|
8479
|
-
var init_schedule_when = __esm({
|
|
8480
|
-
"src/store/schedule-when.ts"() {
|
|
8481
|
-
"use strict";
|
|
8482
|
-
import_croner = require("croner");
|
|
8483
|
-
WEEKDAY_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
8484
|
-
DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
8485
|
-
UNIT_MS = {
|
|
8486
|
-
s: 1e3,
|
|
8487
|
-
m: 6e4,
|
|
8488
|
-
h: 36e5,
|
|
8489
|
-
d: 864e5
|
|
8490
|
-
};
|
|
8491
|
-
DAY_ALIASES = {
|
|
8492
|
-
sun: 0,
|
|
8493
|
-
sunday: 0,
|
|
8494
|
-
mon: 1,
|
|
8495
|
-
monday: 1,
|
|
8496
|
-
tue: 2,
|
|
8497
|
-
tues: 2,
|
|
8498
|
-
tuesday: 2,
|
|
8499
|
-
wed: 3,
|
|
8500
|
-
wednesday: 3,
|
|
8501
|
-
thu: 4,
|
|
8502
|
-
thur: 4,
|
|
8503
|
-
thurs: 4,
|
|
8504
|
-
thursday: 4,
|
|
8505
|
-
fri: 5,
|
|
8506
|
-
friday: 5,
|
|
8507
|
-
sat: 6,
|
|
8508
|
-
saturday: 6
|
|
8509
|
-
};
|
|
8510
|
-
TIME_RE = /^([01]\d|2[0-3]):([0-5]\d)(?::[0-5]\d)?$/;
|
|
8511
|
-
}
|
|
8512
|
-
});
|
|
8513
|
-
|
|
8514
|
-
// src/store/schedules.ts
|
|
8515
|
-
function schedulesPath() {
|
|
8516
|
-
return (0, import_node_path18.join)(appDataDir(), "schedules.json");
|
|
8517
|
-
}
|
|
8518
|
-
function defaultScheduleName(prompt) {
|
|
8519
|
-
const line = prompt.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
8520
|
-
if (!line) return "Untitled automation";
|
|
8521
|
-
return line.length > 60 ? `${line.slice(0, 57).trimEnd()}\u2026` : line;
|
|
8522
|
-
}
|
|
8523
|
-
function resolveScheduleThreadId(raw, env = process.env) {
|
|
8524
|
-
const value = raw?.trim() || "";
|
|
8525
|
-
if (!value) return null;
|
|
8526
|
-
if (value.toLowerCase() === "self") {
|
|
8527
|
-
return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || env.SIDEBOARD_THREAD_ID?.trim() || null;
|
|
8528
|
-
}
|
|
8529
|
-
return value;
|
|
8530
|
-
}
|
|
8531
|
-
function nowIso2(d = /* @__PURE__ */ new Date()) {
|
|
8532
|
-
return d.toISOString();
|
|
8533
|
-
}
|
|
8534
|
-
function normalizeOptionalBool(raw) {
|
|
8535
|
-
if (raw === true || raw === false) return raw;
|
|
8536
|
-
return null;
|
|
8537
|
-
}
|
|
8538
|
-
function normalizeAutonomy2(raw) {
|
|
8539
|
-
return raw === "default" || raw === "full" ? raw : null;
|
|
8540
|
-
}
|
|
8541
|
-
function normalizeAttachments(raw) {
|
|
8542
|
-
if (!Array.isArray(raw)) return [];
|
|
8543
|
-
const out = [];
|
|
8544
|
-
for (const item of raw) {
|
|
8545
|
-
if (!item || typeof item !== "object") continue;
|
|
8546
|
-
const row2 = item;
|
|
8547
|
-
if (typeof row2.id !== "string" || !row2.id.trim()) continue;
|
|
8548
|
-
if (typeof row2.name !== "string" || !row2.name) continue;
|
|
8549
|
-
if (typeof row2.content !== "string") continue;
|
|
8550
|
-
if (!ATTACHMENT_KINDS.has(row2.kind)) continue;
|
|
8551
|
-
const next = {
|
|
8552
|
-
id: row2.id,
|
|
8553
|
-
name: row2.name,
|
|
8554
|
-
kind: row2.kind,
|
|
8555
|
-
content: row2.content
|
|
8556
|
-
};
|
|
8557
|
-
if (typeof row2.path === "string" && row2.path) next.path = row2.path;
|
|
8558
|
-
if (typeof row2.previewDataUrl === "string" && row2.previewDataUrl) {
|
|
8559
|
-
next.previewDataUrl = row2.previewDataUrl;
|
|
8560
|
-
}
|
|
8561
|
-
out.push(next);
|
|
8562
|
-
}
|
|
8563
|
-
return out;
|
|
8564
|
-
}
|
|
8565
|
-
function normalizeTask(raw) {
|
|
8566
|
-
const when = normalizeWhen(raw.when);
|
|
8567
|
-
const agent = raw.agent && isOrchestratorCapableAgent(raw.agent) ? raw.agent : null;
|
|
8568
|
-
return {
|
|
8569
|
-
id: raw.id,
|
|
8570
|
-
name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : defaultScheduleName(raw.prompt),
|
|
8571
|
-
prompt: String(raw.prompt ?? ""),
|
|
8572
|
-
enabled: Boolean(raw.enabled),
|
|
8573
|
-
when,
|
|
8574
|
-
threadId: raw.threadId?.trim() || null,
|
|
8575
|
-
agent,
|
|
8576
|
-
model: raw.model?.trim() || null,
|
|
8577
|
-
effort: normalizeThinkingEffort(raw.effort),
|
|
8578
|
-
fast: normalizeOptionalBool(raw.fast),
|
|
8579
|
-
planMode: normalizeOptionalBool(raw.planMode),
|
|
8580
|
-
autonomy: normalizeAutonomy2(raw.autonomy),
|
|
8581
|
-
attachments: normalizeAttachments(raw.attachments),
|
|
8582
|
-
archiveChat: raw.archiveChat !== false,
|
|
8583
|
-
nextRunAt: raw.nextRunAt,
|
|
8584
|
-
lastRunAt: raw.lastRunAt ?? null,
|
|
8585
|
-
lastThreadId: raw.lastThreadId ?? null,
|
|
8586
|
-
lastError: raw.lastError ?? null,
|
|
8587
|
-
createdBy: raw.createdBy === "mcp" || raw.createdBy === "cli" || raw.createdBy === "ui" ? raw.createdBy : "ui",
|
|
8588
|
-
createdAt: raw.createdAt,
|
|
8589
|
-
updatedAt: raw.updatedAt
|
|
8590
|
-
};
|
|
8591
|
-
}
|
|
8592
|
-
function readAll() {
|
|
8593
|
-
const path2 = schedulesPath();
|
|
8594
|
-
if (!(0, import_node_fs15.existsSync)(path2)) return [];
|
|
8595
|
-
try {
|
|
8596
|
-
const parsed = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
|
|
8597
|
-
if (!Array.isArray(parsed)) return [];
|
|
8598
|
-
return parsed.map((row2) => {
|
|
8599
|
-
try {
|
|
8600
|
-
return normalizeTask(row2);
|
|
8601
|
-
} catch {
|
|
8602
|
-
return null;
|
|
8603
|
-
}
|
|
8604
|
-
}).filter((row2) => Boolean(row2?.id && row2.prompt));
|
|
8605
|
-
} catch {
|
|
8606
|
-
return [];
|
|
8607
|
-
}
|
|
8608
|
-
}
|
|
8609
|
-
function writeAll(rows) {
|
|
8610
|
-
writePrivateFile(schedulesPath(), `${JSON.stringify(rows, null, 2)}
|
|
8611
|
-
`);
|
|
8612
|
-
}
|
|
8613
|
-
function buildTask(input, now) {
|
|
8614
|
-
const prompt = input.prompt.trim();
|
|
8615
|
-
if (!prompt) throw new Error("Schedule prompt is required");
|
|
8616
|
-
const when = normalizeWhen(input.when);
|
|
8617
|
-
const nextRunAt = computeNextRunAt(when, now).toISOString();
|
|
8618
|
-
const ts = nowIso2(now);
|
|
8619
|
-
const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
|
|
8620
|
-
return {
|
|
8621
|
-
id: (0, import_node_crypto8.randomUUID)(),
|
|
8622
|
-
name: input.name?.trim() || defaultScheduleName(prompt),
|
|
8623
|
-
prompt,
|
|
8624
|
-
enabled: input.enabled !== false,
|
|
8625
|
-
when,
|
|
8626
|
-
threadId: input.threadId?.trim() || null,
|
|
8627
|
-
agent,
|
|
8628
|
-
model: input.model?.trim() || null,
|
|
8629
|
-
effort: input.effort != null ? normalizeThinkingEffort(input.effort) : null,
|
|
8630
|
-
fast: normalizeOptionalBool(input.fast),
|
|
8631
|
-
planMode: normalizeOptionalBool(input.planMode),
|
|
8632
|
-
autonomy: normalizeAutonomy2(input.autonomy),
|
|
8633
|
-
attachments: normalizeAttachments(input.attachments),
|
|
8634
|
-
archiveChat: input.archiveChat !== false,
|
|
8635
|
-
nextRunAt,
|
|
8636
|
-
lastRunAt: null,
|
|
8637
|
-
lastThreadId: null,
|
|
8638
|
-
lastError: null,
|
|
8639
|
-
createdBy: input.createdBy,
|
|
8640
|
-
createdAt: ts,
|
|
8641
|
-
updatedAt: ts
|
|
8642
|
-
};
|
|
8643
|
-
}
|
|
8644
|
-
function listSchedules() {
|
|
8645
|
-
return readAll().sort((a, b) => a.nextRunAt.localeCompare(b.nextRunAt));
|
|
8646
|
-
}
|
|
8647
|
-
function hasEnabledSchedules() {
|
|
8648
|
-
return listSchedules().some((row2) => row2.enabled);
|
|
8649
|
-
}
|
|
8650
|
-
function scheduleNeedsCaffeinate(task, now = /* @__PURE__ */ new Date()) {
|
|
8651
|
-
if (!task.enabled) return false;
|
|
8652
|
-
const at = new Date(task.nextRunAt);
|
|
8653
|
-
if (Number.isNaN(at.getTime())) return false;
|
|
8654
|
-
return at.getTime() > now.getTime();
|
|
8655
|
-
}
|
|
8656
|
-
function ensureCaffeinateForFutureSchedule(task) {
|
|
8657
|
-
if (!scheduleNeedsCaffeinate(task)) return;
|
|
8658
|
-
if (caffeinateWhileSchedulesEnabled()) return;
|
|
8659
|
-
updateAdvancedSettings({ caffeinateWhileSchedules: true });
|
|
8660
|
-
}
|
|
8661
|
-
function getSchedule(id) {
|
|
8662
|
-
const key = id.trim();
|
|
8663
|
-
if (!key) return null;
|
|
8664
|
-
return readAll().find(
|
|
8665
|
-
(row2) => row2.id === key || row2.id.startsWith(key) && key.length >= 8
|
|
8666
|
-
) ?? null;
|
|
8667
|
-
}
|
|
8668
|
-
function createSchedule(input) {
|
|
8669
|
-
const task = buildTask(input, /* @__PURE__ */ new Date());
|
|
8670
|
-
const rows = readAll();
|
|
8671
|
-
rows.push(task);
|
|
8672
|
-
writeAll(rows);
|
|
8673
|
-
ensureCaffeinateForFutureSchedule(task);
|
|
8674
|
-
return task;
|
|
8675
|
-
}
|
|
8676
|
-
function updateSchedule(id, patch) {
|
|
8677
|
-
const rows = readAll();
|
|
8678
|
-
const idx = rows.findIndex((row2) => row2.id === id || id.length >= 8 && row2.id.startsWith(id));
|
|
8679
|
-
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
8680
|
-
const prev = rows[idx];
|
|
8681
|
-
const when = patch.when ? normalizeWhen(patch.when) : prev.when;
|
|
8682
|
-
const prompt = patch.prompt !== void 0 ? patch.prompt.trim() : prev.prompt;
|
|
8683
|
-
if (!prompt) throw new Error("Schedule prompt is required");
|
|
8684
|
-
const whenChanged = patch.when !== void 0;
|
|
8685
|
-
const next = {
|
|
8686
|
-
...prev,
|
|
8687
|
-
name: patch.name !== void 0 ? patch.name.trim() || defaultScheduleName(prompt) : prev.name,
|
|
8688
|
-
prompt,
|
|
8689
|
-
enabled: patch.enabled ?? prev.enabled,
|
|
8690
|
-
when,
|
|
8691
|
-
threadId: patch.threadId !== void 0 ? patch.threadId?.trim() || null : prev.threadId,
|
|
8692
|
-
agent: patch.agent !== void 0 ? patch.agent ? coerceOrchestratorAgent(patch.agent) : null : prev.agent,
|
|
8693
|
-
model: patch.model !== void 0 ? patch.model?.trim() || null : prev.model,
|
|
8694
|
-
effort: patch.effort !== void 0 ? normalizeThinkingEffort(patch.effort) : prev.effort,
|
|
8695
|
-
fast: patch.fast !== void 0 ? normalizeOptionalBool(patch.fast) : prev.fast,
|
|
8696
|
-
planMode: patch.planMode !== void 0 ? normalizeOptionalBool(patch.planMode) : prev.planMode,
|
|
8697
|
-
autonomy: patch.autonomy !== void 0 ? normalizeAutonomy2(patch.autonomy) : prev.autonomy,
|
|
8698
|
-
attachments: patch.attachments !== void 0 ? normalizeAttachments(patch.attachments) : prev.attachments,
|
|
8699
|
-
archiveChat: patch.archiveChat !== void 0 ? patch.archiveChat !== false : prev.archiveChat,
|
|
8700
|
-
nextRunAt: whenChanged ? computeNextRunAt(when).toISOString() : prev.nextRunAt,
|
|
8701
|
-
lastError: whenChanged ? null : prev.lastError,
|
|
8702
|
-
updatedAt: nowIso2()
|
|
8703
|
-
};
|
|
8704
|
-
rows[idx] = next;
|
|
8705
|
-
writeAll(rows);
|
|
8706
|
-
ensureCaffeinateForFutureSchedule(next);
|
|
8707
|
-
return next;
|
|
8708
|
-
}
|
|
8709
|
-
function deleteSchedule(id) {
|
|
8710
|
-
const rows = readAll();
|
|
8711
|
-
const next = rows.filter(
|
|
8712
|
-
(row2) => row2.id !== id && !(id.length >= 8 && row2.id.startsWith(id))
|
|
8713
|
-
);
|
|
8714
|
-
if (next.length === rows.length) throw new Error(`Automation not found: ${id}`);
|
|
8715
|
-
writeAll(next);
|
|
8716
|
-
}
|
|
8717
|
-
function recordScheduleRun(id, result) {
|
|
8718
|
-
const rows = readAll();
|
|
8719
|
-
const idx = rows.findIndex((row2) => row2.id === id);
|
|
8720
|
-
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
8721
|
-
const prev = rows[idx];
|
|
8722
|
-
const firedAt = result.firedAt ?? /* @__PURE__ */ new Date();
|
|
8723
|
-
const next = {
|
|
8724
|
-
...prev,
|
|
8725
|
-
enabled: prev.when.kind === "once" ? false : prev.enabled,
|
|
8726
|
-
nextRunAt: prev.when.kind === "once" ? prev.nextRunAt : computeNextRunAt(prev.when, firedAt).toISOString(),
|
|
8727
|
-
lastRunAt: nowIso2(firedAt),
|
|
8728
|
-
lastThreadId: result.lastThreadId !== void 0 ? result.lastThreadId : prev.lastThreadId,
|
|
8729
|
-
lastError: result.lastError ?? null,
|
|
8730
|
-
updatedAt: nowIso2(firedAt)
|
|
8731
|
-
};
|
|
8732
|
-
rows[idx] = next;
|
|
8733
|
-
writeAll(rows);
|
|
8734
|
-
return next;
|
|
8735
|
-
}
|
|
8736
|
-
var import_node_crypto8, import_node_fs15, import_node_path18, ATTACHMENT_KINDS;
|
|
8737
|
-
var init_schedules = __esm({
|
|
8738
|
-
"src/store/schedules.ts"() {
|
|
8739
|
-
"use strict";
|
|
8740
|
-
import_node_crypto8 = require("crypto");
|
|
8741
|
-
import_node_fs15 = require("fs");
|
|
8742
|
-
import_node_path18 = require("path");
|
|
8743
|
-
init_schedule_when();
|
|
8744
|
-
init_orchestrator_capable();
|
|
8745
|
-
init_thinking_effort();
|
|
8746
|
-
init_paths();
|
|
8747
|
-
init_private_file();
|
|
8748
|
-
init_app_settings();
|
|
8749
|
-
init_schedule_when();
|
|
8750
|
-
ATTACHMENT_KINDS = /* @__PURE__ */ new Set([
|
|
8751
|
-
"transcript",
|
|
8752
|
-
"file",
|
|
8753
|
-
"issue",
|
|
8754
|
-
"workspace",
|
|
8755
|
-
"diff-comment",
|
|
8756
|
-
"code-ref"
|
|
8757
|
-
]);
|
|
8758
|
-
}
|
|
8759
|
-
});
|
|
8760
|
-
|
|
8761
8770
|
// src/store/desktop-host.ts
|
|
8762
8771
|
function desktopHostPidPath() {
|
|
8763
8772
|
return (0, import_node_path19.join)(appDataDir(), "desktop-host.pid");
|
|
@@ -13153,7 +13162,7 @@ var init_coordinator_prompt = __esm({
|
|
|
13153
13162
|
"- get_viewer_context / update_viewer_context \u2014 read or replace Settings \u2192 Agents (account) and Settings \u2192 Projects (per-repo) context. You can update a project: pass scope=project and repoPath from list_projects (this cwd is not a project). update_viewer_context requires confirmed=true after ask_user. Never write context unprompted.",
|
|
13154
13163
|
"- list_env / set_env / delete_env \u2014 Settings \u2192 Environment. scope=project requires repoPath from list_projects and stores the key under that project prefix (the project name, uppercased, plus _). APPLE_ID for sideboard is SIDEBOARD_APPLE_ID. scope=account is shared by every project and is not prefixed. list_env returns names only.",
|
|
13155
13164
|
"- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for phone remote / away-from-keyboard work, overnight schedules, or when the user will be away. Turn OFF when they say they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
|
|
13156
|
-
"- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 automations that send a prompt to a chat (chatId or self) or start a new Global chat (omit chatId). One-shot `at`, interval `every` (15m/1h/6h/1d), clock time `time` + `days` (07:30 and weekdays, or mon,wed), or 5-field `cron`. Recurring jobs without chatId open a new chat each run and archive it when that run finishes unless archiveChat is false (leave the chat open to keep talking). History keeps the last 5 archived runs for that automation. Worktree agents have the same tools (`chatId=self` continues that coding chat). Jobs fire only while Sideboard.app is running; sleep skips until wake. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled (or call set_caffeinate). The desktop lists them in the sidebar after Board.",
|
|
13165
|
+
"- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 automations that send a prompt to a chat (chatId or self) or start a new Global chat (omit chatId). A job bound to a chat is removed when that chat is archived. Omit chatId only for a Global automation that should outlive the chat. One-shot `at`, interval `every` (15m/1h/6h/1d), clock time `time` + `days` (07:30 and weekdays, or mon,wed), or 5-field `cron`. Recurring jobs without chatId open a new chat each run and archive it when that run finishes unless archiveChat is false (leave the chat open to keep talking). History keeps the last 5 archived runs for that automation. Worktree agents have the same tools (`chatId=self` continues that coding chat and is removed when that chat is archived). Jobs fire only while Sideboard.app is running; sleep skips until wake. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled (or call set_caffeinate). The desktop lists them in the sidebar after Board.",
|
|
13157
13166
|
"Projects:",
|
|
13158
13167
|
"- add_project / remove_project \u2014 register or unregister a git repo",
|
|
13159
13168
|
"Workspaces and chats:",
|
|
@@ -31373,7 +31382,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
31373
31382
|
lines.push(formatDevAccessHint(opts?.activeRuns));
|
|
31374
31383
|
lines.push("");
|
|
31375
31384
|
lines.push(
|
|
31376
|
-
"Automations (sidebar, after Board): `create_schedule` / `list_schedules` (`at` / `every` / `cron` / `time`+`days`). `archiveChat=false` keeps the new chat. `chatId=self`
|
|
31385
|
+
"Automations (sidebar, after Board): `create_schedule` / `list_schedules` (`at` / `every` / `cron` / `time`+`days`). `archiveChat=false` keeps the new chat. `chatId=self` is removed when this chat is archived. Fires only while Sideboard.app is running. A future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled."
|
|
31377
31386
|
);
|
|
31378
31387
|
lines.push(
|
|
31379
31388
|
"`set_workspace_tags` labels this checkout (omit ref; replace, add, or remove). Not another checkout."
|
|
@@ -31393,7 +31402,7 @@ function connectedOrchestratorTurnReminder(thread, find) {
|
|
|
31393
31402
|
return formatConnectedOrchestratorReminder(connectedOrchestrator(thread, find));
|
|
31394
31403
|
}
|
|
31395
31404
|
function formatWorktreeReminder() {
|
|
31396
|
-
return "Sideboard workspace: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push. Automations: create_schedule (at / every / cron, or time + days such as weekdays at 07:30; archiveChat=false leaves the new chat open; chatId=self
|
|
31405
|
+
return "Sideboard workspace: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push. Automations: create_schedule (at / every / cron, or time + days such as weekdays at 07:30; archiveChat=false leaves the new chat open; chatId=self ends with the chat). set_workspace_tags updates labels on this workspace (omit ref).";
|
|
31397
31406
|
}
|
|
31398
31407
|
function formatClaudeSubagentReminder() {
|
|
31399
31408
|
return 'Claude subagents: if Task/Agent workers will edit files, write a short plan in this chat and continue in the same turn. Do not ask the user whether to isolate, and do not set worktree.bgIsolation to none. One writer may edit this workspace. Every other writer is an Agent with isolation "worktree" and a disjoint file list (read-only explore agents may overlap). While those agents run, leave their files alone. Merge each returned branch into this workspace, then remove the temporary worktree. You stay in this cwd. If Claude says another write-capable agent is in this directory, or that writes to the shared checkout are blocked, re-spawn that agent with isolation "worktree" or make the edit yourself. That note is another worker in this chat, or a worker Claude still has marked running. Do not mention it to the user.';
|
|
@@ -35451,7 +35460,15 @@ async function fireSchedule(id) {
|
|
|
35451
35460
|
const deps = fireHooks ?? await defaultDeps();
|
|
35452
35461
|
const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
|
|
35453
35462
|
const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
|
|
35454
|
-
if (
|
|
35463
|
+
if (schedule.threadId && (!target || target.status === "archived")) {
|
|
35464
|
+
deleteSchedule(schedule.id);
|
|
35465
|
+
return {
|
|
35466
|
+
...schedule,
|
|
35467
|
+
enabled: false,
|
|
35468
|
+
lastError: "Removed because its chat is archived or gone."
|
|
35469
|
+
};
|
|
35470
|
+
}
|
|
35471
|
+
if (target) {
|
|
35455
35472
|
const sent = await deps.send(target.id, prompt, {
|
|
35456
35473
|
attachments: schedule.attachments,
|
|
35457
35474
|
options: scheduleSendOptions(schedule)
|
|
@@ -35461,8 +35478,7 @@ async function fireSchedule(id) {
|
|
|
35461
35478
|
lastError: null
|
|
35462
35479
|
});
|
|
35463
35480
|
}
|
|
35464
|
-
const
|
|
35465
|
-
const archiveFresh = schedule.archiveChat !== false && !pinReplacement;
|
|
35481
|
+
const archiveFresh = schedule.archiveChat !== false;
|
|
35466
35482
|
const created = await deps.startOrchestration({
|
|
35467
35483
|
goal: prompt,
|
|
35468
35484
|
agent: pickAgent(schedule),
|
|
@@ -35475,9 +35491,6 @@ async function fireSchedule(id) {
|
|
|
35475
35491
|
...archiveFresh ? { ephemeralAutomationId: schedule.id } : {},
|
|
35476
35492
|
ephemeralTitle: schedule.name
|
|
35477
35493
|
});
|
|
35478
|
-
if (pinReplacement) {
|
|
35479
|
-
updateSchedule(schedule.id, { threadId: created.id });
|
|
35480
|
-
}
|
|
35481
35494
|
return recordScheduleRun(schedule.id, {
|
|
35482
35495
|
lastThreadId: created.id,
|
|
35483
35496
|
lastError: null
|
|
@@ -35894,6 +35907,7 @@ __export(index_exports, {
|
|
|
35894
35907
|
defaultScheduleName: () => defaultScheduleName,
|
|
35895
35908
|
deleteBranchOnPurgeEnabled: () => deleteBranchOnPurgeEnabled,
|
|
35896
35909
|
deleteSchedule: () => deleteSchedule,
|
|
35910
|
+
deleteSchedulesForThread: () => deleteSchedulesForThread,
|
|
35897
35911
|
deleteThreadRecord: () => deleteThreadRecord,
|
|
35898
35912
|
deriveTaskState: () => deriveTaskState,
|
|
35899
35913
|
desktopHostPidPath: () => desktopHostPidPath,
|
|
@@ -45361,7 +45375,7 @@ function whenFromUpdate(id, args) {
|
|
|
45361
45375
|
}
|
|
45362
45376
|
function createdHint(schedule) {
|
|
45363
45377
|
const awake = scheduleNeedsCaffeinate(schedule) ? " Caffeinate while automations are enabled is now on so the Mac can stay awake until this job is due." : "";
|
|
45364
|
-
const fresh = schedule.threadId ? "" : schedule.archiveChat === false ? " This job leaves the new chat open so you can keep talking." : " A new Global chat is archived when the run finishes (History keeps the last 5 runs). Pass archiveChat=false to leave it open.";
|
|
45378
|
+
const fresh = schedule.threadId ? " This job is removed when that chat is archived." : schedule.archiveChat === false ? " This job leaves the new chat open so you can keep talking." : " A new Global chat is archived when the run finishes (History keeps the last 5 runs). Pass archiveChat=false to leave it open.";
|
|
45365
45379
|
return `Fires while Sideboard.app is running.${fresh}${awake}`;
|
|
45366
45380
|
}
|
|
45367
45381
|
function registerScheduleTools(server) {
|
|
@@ -45379,7 +45393,7 @@ function registerScheduleTools(server) {
|
|
|
45379
45393
|
);
|
|
45380
45394
|
server.tool(
|
|
45381
45395
|
"create_schedule",
|
|
45382
|
-
"Create a local automation that, when due, sends a prompt to an existing chat (chatId) or starts a new Global orchestration chat (omit chatId). Pass chatId=self to continue this chat.
|
|
45396
|
+
"Create a local automation that, when due, sends a prompt to an existing chat (chatId) or starts a new Global orchestration chat (omit chatId). Pass chatId=self to continue this chat. A job bound to a chat is removed when that chat is archived or gone; it does not start a new Global chat. Omit chatId only for a Global automation that should outlive this chat. Exactly one of at (ISO datetime), every (15m/1h/6h/1d), time (HH:mm, with days such as weekdays or mon,wed), or cron (5-field). Recurring jobs without chatId open a new Global chat each run and archive it when that run finishes unless archiveChat is false (leave the chat open to keep talking, for example a morning start-my-day run). History keeps the last 5 archived runs for that automation. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled so the Mac stays awake until due. Sideboard.app must be running for the job to fire.",
|
|
45383
45397
|
{
|
|
45384
45398
|
prompt: import_zod10.z.string().describe("User message / goal queued when the automation fires"),
|
|
45385
45399
|
name: import_zod10.z.string().optional(),
|
|
@@ -45393,7 +45407,7 @@ function registerScheduleTools(server) {
|
|
|
45393
45407
|
"Archive a new Global chat when the run finishes. Default true. Pass false to leave the chat open."
|
|
45394
45408
|
),
|
|
45395
45409
|
chatId: import_zod10.z.string().optional().describe(
|
|
45396
|
-
'Existing chat id
|
|
45410
|
+
'Existing chat id, or "self" for this chat. That job is removed when the chat is archived. Omit only for a Global automation that should outlive this chat.'
|
|
45397
45411
|
),
|
|
45398
45412
|
threadId: import_zod10.z.string().optional().describe("Legacy alias for chatId."),
|
|
45399
45413
|
agent: import_zod10.z.enum(["claude", "cursor", "codex", "opencode"]).optional().describe("Agent for a new Global chat (omit for Account default)"),
|
|
@@ -45445,7 +45459,7 @@ function registerScheduleTools(server) {
|
|
|
45445
45459
|
tz: import_zod10.z.string().optional(),
|
|
45446
45460
|
archiveChat: import_zod10.z.boolean().optional().describe("Archive a new Global chat when the run finishes. False leaves it open."),
|
|
45447
45461
|
chatId: import_zod10.z.string().optional().describe(
|
|
45448
|
-
'Existing chat
|
|
45462
|
+
'Existing chat, "self", or empty string for a Global chat each run. A bound job is removed when that chat is archived.'
|
|
45449
45463
|
),
|
|
45450
45464
|
threadId: import_zod10.z.string().optional().describe("Legacy alias for chatId."),
|
|
45451
45465
|
agent: import_zod10.z.enum(["claude", "cursor", "codex", "opencode"]).optional(),
|
|
@@ -50039,6 +50053,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
50039
50053
|
defaultScheduleName,
|
|
50040
50054
|
deleteBranchOnPurgeEnabled,
|
|
50041
50055
|
deleteSchedule,
|
|
50056
|
+
deleteSchedulesForThread,
|
|
50042
50057
|
deleteThreadRecord,
|
|
50043
50058
|
deriveTaskState,
|
|
50044
50059
|
desktopHostPidPath,
|