@sideboard-ai/core 0.1.326 → 0.1.328
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-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-XLVLMQKN.js → chunk-EYDLXVED.js} +40 -25
- 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-NJV5YEKI.js +194 -0
- 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-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-WUCAVIIP.js → chunk-UMXBH344.js} +1 -1
- package/dist/{chunk-GP3RLZ6A.js → chunk-WD222BVP.js} +109 -491
- package/dist/{chunk-46FECFZU.js → chunk-X3XTO45Y.js} +39 -196
- package/dist/{chunk-RZVOX2MT.js → chunk-XBBZZHJY.js} +3 -3
- package/dist/{chunk-2EOLWHXH.js → chunk-XOMVOBPU.js} +127 -477
- package/dist/{chunk-ZSHS46V5.js → chunk-Y6OHM672.js} +476 -20
- package/dist/{chunk-YWQF7WAG.js → chunk-ZPBOWO64.js} +2 -2
- package/dist/{conductor-4GVTHUUB.js → conductor-G6GH5ZMU.js} +7 -7
- package/dist/{conductor-TGWI6ETZ.js → conductor-U5LGJZUJ.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 +605 -508
- package/dist/index.d.cts +23 -11
- package/dist/index.d.ts +23 -11
- 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 +19762 -19682
- 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-RQXRZW7Z.js → orchestrator-3F53AZEN.js} +11 -12
- package/dist/{orchestrator-7FVDBE7Y.js → orchestrator-YY2JUYKD.js} +12 -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
|
}
|
|
@@ -6939,9 +7383,6 @@ function lastTopLevelToolIsAskUser(parts) {
|
|
|
6939
7383
|
}
|
|
6940
7384
|
return false;
|
|
6941
7385
|
}
|
|
6942
|
-
function hasTopLevelTool(parts) {
|
|
6943
|
-
return Boolean(parts?.some((part) => part.type === "tool" && !part.parentId));
|
|
6944
|
-
}
|
|
6945
7386
|
function questionsFromToolPart(part) {
|
|
6946
7387
|
const fromInput = parsePlanQuestionsInput(part.input);
|
|
6947
7388
|
if (fromInput.length) return fromInput;
|
|
@@ -6957,7 +7398,7 @@ function extractPendingPlanQuestions(parts) {
|
|
|
6957
7398
|
if (!parts?.length) return null;
|
|
6958
7399
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
6959
7400
|
const p = parts[i];
|
|
6960
|
-
if (p.type !== "tool" || !isAskUserToolName(p.name)) continue;
|
|
7401
|
+
if (p.type !== "tool" || p.parentId || !isAskUserToolName(p.name)) continue;
|
|
6961
7402
|
const questions2 = questionsFromToolPart(p);
|
|
6962
7403
|
if (!questions2.length) continue;
|
|
6963
7404
|
return {
|
|
@@ -6997,18 +7438,23 @@ function askBlockStillWaiting(block, messages) {
|
|
|
6997
7438
|
}
|
|
6998
7439
|
function latestPendingPlanQuestions(input) {
|
|
6999
7440
|
if (input.userReplied) return null;
|
|
7441
|
+
const dismissed = input.dismissedQuestionSignature?.trim();
|
|
7442
|
+
const accept = (pending) => {
|
|
7443
|
+
if (!pending) return null;
|
|
7444
|
+
if (dismissed && pending.signature === dismissed) return null;
|
|
7445
|
+
return pending;
|
|
7446
|
+
};
|
|
7000
7447
|
const fromBlock = () => pendingFromAskBlock(input.agentBlock, input.dismissedQuestionSignature);
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
}
|
|
7448
|
+
const liveAsk = accept(extractPendingPlanQuestions(input.liveParts));
|
|
7449
|
+
if (liveAsk) return liveAsk;
|
|
7004
7450
|
const last = input.messages[input.messages.length - 1];
|
|
7005
|
-
if (last?.role === "agent"
|
|
7006
|
-
|
|
7451
|
+
if (last?.role === "agent") {
|
|
7452
|
+
const fromTranscript = accept(extractPendingPlanQuestions(last.parts));
|
|
7453
|
+
if (fromTranscript) return fromTranscript;
|
|
7007
7454
|
}
|
|
7008
|
-
if (
|
|
7455
|
+
if ((input.status === "running" || input.status === "queued") && !input.agentBlock?.onScreen) {
|
|
7009
7456
|
return null;
|
|
7010
7457
|
}
|
|
7011
|
-
if (input.status === "running" || input.status === "queued") return null;
|
|
7012
7458
|
const stamped = fromBlock();
|
|
7013
7459
|
if (stamped && askBlockStillWaiting(input.agentBlock, input.messages)) {
|
|
7014
7460
|
return stamped;
|
|
@@ -8038,11 +8484,11 @@ function materialize(mem) {
|
|
|
8038
8484
|
};
|
|
8039
8485
|
}
|
|
8040
8486
|
function setupLogPath(threadId) {
|
|
8041
|
-
return (0,
|
|
8487
|
+
return (0, import_node_path17.join)(threadsDir(), `${threadId}.setup.log.json`);
|
|
8042
8488
|
}
|
|
8043
8489
|
function setupLogKeyForWorktree(worktreePath) {
|
|
8044
8490
|
const norm = normalizeWorktreePath(worktreePath);
|
|
8045
|
-
return `wt-${(0,
|
|
8491
|
+
return `wt-${(0, import_node_crypto7.createHash)("sha1").update(norm).digest("hex").slice(0, 16)}`;
|
|
8046
8492
|
}
|
|
8047
8493
|
function emptySetupLog() {
|
|
8048
8494
|
return { ...EMPTY };
|
|
@@ -8064,7 +8510,7 @@ function persistNow(threadId) {
|
|
|
8064
8510
|
const mem = memory.get(threadId);
|
|
8065
8511
|
if (!mem) return;
|
|
8066
8512
|
try {
|
|
8067
|
-
(0,
|
|
8513
|
+
(0, import_node_fs14.writeFileSync)(
|
|
8068
8514
|
setupLogPath(threadId),
|
|
8069
8515
|
`${JSON.stringify(materialize(mem))}
|
|
8070
8516
|
`,
|
|
@@ -8085,9 +8531,9 @@ function schedulePersist(threadId) {
|
|
|
8085
8531
|
}
|
|
8086
8532
|
function loadFromDisk(threadId) {
|
|
8087
8533
|
const path2 = setupLogPath(threadId);
|
|
8088
|
-
if (!(0,
|
|
8534
|
+
if (!(0, import_node_fs14.existsSync)(path2)) return null;
|
|
8089
8535
|
try {
|
|
8090
|
-
const raw = JSON.parse((0,
|
|
8536
|
+
const raw = JSON.parse((0, import_node_fs14.readFileSync)(path2, "utf8"));
|
|
8091
8537
|
return {
|
|
8092
8538
|
output: typeof raw.output === "string" ? raw.output : "",
|
|
8093
8539
|
running: Boolean(raw.running),
|
|
@@ -8143,13 +8589,13 @@ function finishSetupLog(threadId, exitCode, source) {
|
|
|
8143
8589
|
persistNow(threadId);
|
|
8144
8590
|
return materialize(mem);
|
|
8145
8591
|
}
|
|
8146
|
-
var
|
|
8592
|
+
var import_node_crypto7, import_node_fs14, import_node_path17, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
|
|
8147
8593
|
var init_setup_log = __esm({
|
|
8148
8594
|
"src/store/setup-log.ts"() {
|
|
8149
8595
|
"use strict";
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8596
|
+
import_node_crypto7 = require("crypto");
|
|
8597
|
+
import_node_fs14 = require("fs");
|
|
8598
|
+
import_node_path17 = require("path");
|
|
8153
8599
|
init_worktree_labels();
|
|
8154
8600
|
init_paths();
|
|
8155
8601
|
EMPTY = {
|
|
@@ -8194,11 +8640,11 @@ function safeScriptToken(scriptName) {
|
|
|
8194
8640
|
return token || "dev";
|
|
8195
8641
|
}
|
|
8196
8642
|
function runLogPath(key) {
|
|
8197
|
-
return (0,
|
|
8643
|
+
return (0, import_node_path18.join)(threadsDir(), `${key}.run.log.json`);
|
|
8198
8644
|
}
|
|
8199
8645
|
function runLogKeyForWorktree(worktreePath, scriptName) {
|
|
8200
8646
|
const norm = normalizeWorktreePath(worktreePath);
|
|
8201
|
-
const hash = (0,
|
|
8647
|
+
const hash = (0, import_node_crypto8.createHash)("sha1").update(norm).digest("hex").slice(0, 16);
|
|
8202
8648
|
return `wt-${hash}-run-${safeScriptToken(scriptName)}`;
|
|
8203
8649
|
}
|
|
8204
8650
|
function emptyRunLog() {
|
|
@@ -8222,7 +8668,7 @@ function persistNow2(key) {
|
|
|
8222
8668
|
const mem = memory2.get(key);
|
|
8223
8669
|
if (!mem) return;
|
|
8224
8670
|
try {
|
|
8225
|
-
(0,
|
|
8671
|
+
(0, import_node_fs15.writeFileSync)(runLogPath(key), `${JSON.stringify(materialize2(mem))}
|
|
8226
8672
|
`, "utf8");
|
|
8227
8673
|
} catch {
|
|
8228
8674
|
}
|
|
@@ -8239,9 +8685,9 @@ function schedulePersist2(key) {
|
|
|
8239
8685
|
}
|
|
8240
8686
|
function loadFromDisk2(key) {
|
|
8241
8687
|
const path2 = runLogPath(key);
|
|
8242
|
-
if (!(0,
|
|
8688
|
+
if (!(0, import_node_fs15.existsSync)(path2)) return null;
|
|
8243
8689
|
try {
|
|
8244
|
-
const raw = JSON.parse((0,
|
|
8690
|
+
const raw = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
|
|
8245
8691
|
return {
|
|
8246
8692
|
output: typeof raw.output === "string" ? raw.output : "",
|
|
8247
8693
|
running: Boolean(raw.running),
|
|
@@ -8299,13 +8745,13 @@ function finishRunLog(key, exitCode) {
|
|
|
8299
8745
|
function flushRunLog(key) {
|
|
8300
8746
|
persistNow2(key);
|
|
8301
8747
|
}
|
|
8302
|
-
var
|
|
8748
|
+
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
8749
|
var init_run_log = __esm({
|
|
8304
8750
|
"src/store/run-log.ts"() {
|
|
8305
8751
|
"use strict";
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8752
|
+
import_node_crypto8 = require("crypto");
|
|
8753
|
+
import_node_fs15 = require("fs");
|
|
8754
|
+
import_node_path18 = require("path");
|
|
8309
8755
|
init_worktree_labels();
|
|
8310
8756
|
init_setup_log();
|
|
8311
8757
|
init_paths();
|
|
@@ -8323,441 +8769,6 @@ var init_run_log = __esm({
|
|
|
8323
8769
|
}
|
|
8324
8770
|
});
|
|
8325
8771
|
|
|
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
8772
|
// src/store/desktop-host.ts
|
|
8762
8773
|
function desktopHostPidPath() {
|
|
8763
8774
|
return (0, import_node_path19.join)(appDataDir(), "desktop-host.pid");
|
|
@@ -9165,6 +9176,33 @@ function needsCoordinatorAction(state) {
|
|
|
9165
9176
|
function endedOnAskUser(parts) {
|
|
9166
9177
|
return lastTopLevelToolIsAskUser(parts);
|
|
9167
9178
|
}
|
|
9179
|
+
function turnWaitingOnAskUser(parts, dismissedQuestionSignature) {
|
|
9180
|
+
if (!parts?.length) return false;
|
|
9181
|
+
let ask = null;
|
|
9182
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
9183
|
+
const part = parts[i];
|
|
9184
|
+
if (part.type === "tool" && !part.parentId && isAskUserToolName(part.name)) {
|
|
9185
|
+
ask = part;
|
|
9186
|
+
break;
|
|
9187
|
+
}
|
|
9188
|
+
}
|
|
9189
|
+
if (!ask) return false;
|
|
9190
|
+
const dismissed = dismissedQuestionSignature?.trim();
|
|
9191
|
+
if (!dismissed) return true;
|
|
9192
|
+
const pending = extractPendingPlanQuestions([ask]);
|
|
9193
|
+
if (!pending?.signature) return false;
|
|
9194
|
+
return pending.signature !== dismissed;
|
|
9195
|
+
}
|
|
9196
|
+
function userRepliedAfterAgent(messages, lastAgent) {
|
|
9197
|
+
if (!messages || !lastAgent) return false;
|
|
9198
|
+
const index = messages.lastIndexOf(lastAgent);
|
|
9199
|
+
if (index < 0) return false;
|
|
9200
|
+
for (let i = index + 1; i < messages.length; i++) {
|
|
9201
|
+
const message = messages[i];
|
|
9202
|
+
if (message.role === "user" && message.origin !== "continue") return true;
|
|
9203
|
+
}
|
|
9204
|
+
return false;
|
|
9205
|
+
}
|
|
9168
9206
|
function deriveTaskState(input) {
|
|
9169
9207
|
if (input.stillRunning) {
|
|
9170
9208
|
return input.status === "queued" ? "submitted" : "working";
|
|
@@ -9176,7 +9214,7 @@ function deriveTaskState(input) {
|
|
|
9176
9214
|
case "stopped":
|
|
9177
9215
|
return "canceled";
|
|
9178
9216
|
default:
|
|
9179
|
-
return
|
|
9217
|
+
return !input.userAnswered && turnWaitingOnAskUser(input.lastAgentParts, input.dismissedQuestionSignature) ? "input-required" : "completed";
|
|
9180
9218
|
}
|
|
9181
9219
|
}
|
|
9182
9220
|
var init_task_state = __esm({
|
|
@@ -13153,7 +13191,7 @@ var init_coordinator_prompt = __esm({
|
|
|
13153
13191
|
"- 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
13192
|
"- 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
13193
|
"- 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.",
|
|
13194
|
+
"- 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
13195
|
"Projects:",
|
|
13158
13196
|
"- add_project / remove_project \u2014 register or unregister a git repo",
|
|
13159
13197
|
"Workspaces and chats:",
|
|
@@ -25616,6 +25654,9 @@ function decisionBlockFromParts(parts, planMode, at = (/* @__PURE__ */ new Date(
|
|
|
25616
25654
|
at
|
|
25617
25655
|
);
|
|
25618
25656
|
}
|
|
25657
|
+
function attentionOutranksAsk(existing) {
|
|
25658
|
+
return existing?.source === "reported" || existing?.source === "permission";
|
|
25659
|
+
}
|
|
25619
25660
|
function withStampedQuestions(decision, existing) {
|
|
25620
25661
|
if (decision.source !== "ask_user" || decision.questions?.length) return decision;
|
|
25621
25662
|
if (existing?.source !== "ask_user" || !existing.questions?.length) return decision;
|
|
@@ -25629,12 +25670,37 @@ function agentBlockAfterTurn(input) {
|
|
|
25629
25670
|
if (input.failed) return null;
|
|
25630
25671
|
const decision = decisionBlockFromParts(input.parts, input.planMode);
|
|
25631
25672
|
if (decision) {
|
|
25673
|
+
if (decision.source === "ask_user" && attentionOutranksAsk(input.existing)) {
|
|
25674
|
+
return input.existing ?? null;
|
|
25675
|
+
}
|
|
25632
25676
|
const next = withStampedQuestions(decision, input.existing);
|
|
25633
25677
|
if (isDismissedAskUserBlock(next, input.dismissedQuestionSignature)) {
|
|
25634
25678
|
return input.existing?.source === "reported" ? input.existing : null;
|
|
25635
25679
|
}
|
|
25636
25680
|
return next;
|
|
25637
25681
|
}
|
|
25682
|
+
const pending = extractPendingPlanQuestions(input.parts);
|
|
25683
|
+
if (pending && attentionOutranksAsk(input.existing)) {
|
|
25684
|
+
return input.existing ?? null;
|
|
25685
|
+
}
|
|
25686
|
+
if (pending) {
|
|
25687
|
+
const kept = withStampedQuestions(
|
|
25688
|
+
{
|
|
25689
|
+
...makeAgentBlock(
|
|
25690
|
+
"ask_user",
|
|
25691
|
+
formatAskUserNotifyMessage(pending.questions),
|
|
25692
|
+
input.existing?.source === "ask_user" ? input.existing.at : void 0
|
|
25693
|
+
),
|
|
25694
|
+
onScreen: true,
|
|
25695
|
+
questionSignature: pending.signature,
|
|
25696
|
+
questions: pending.questions
|
|
25697
|
+
},
|
|
25698
|
+
input.existing
|
|
25699
|
+
);
|
|
25700
|
+
if (!isDismissedAskUserBlock(kept, input.dismissedQuestionSignature)) return kept;
|
|
25701
|
+
} else if (input.existing?.source === "ask_user" && input.existing.onScreen && input.existing.questions?.length && !isDismissedAskUserBlock(input.existing, input.dismissedQuestionSignature)) {
|
|
25702
|
+
return input.existing;
|
|
25703
|
+
}
|
|
25638
25704
|
if (input.existing && input.existing.source !== "reported" && lastTopLevelTool(input.parts)) {
|
|
25639
25705
|
return null;
|
|
25640
25706
|
}
|
|
@@ -25663,11 +25729,15 @@ function askBlocksEqual(a, b) {
|
|
|
25663
25729
|
if (!a || !b) return false;
|
|
25664
25730
|
return a.source === b.source && a.reason === b.reason && a.at === b.at && a.onScreen === b.onScreen && a.questionSignature === b.questionSignature;
|
|
25665
25731
|
}
|
|
25666
|
-
function askBlockAfterLiveParts(existing, parts) {
|
|
25732
|
+
function askBlockAfterLiveParts(existing, parts, dismissedQuestionSignature) {
|
|
25733
|
+
if (attentionOutranksAsk(existing)) return existing ?? null;
|
|
25734
|
+
if (isDismissedAskUserBlock(existing, dismissedQuestionSignature)) return null;
|
|
25735
|
+
const dismissed = dismissedQuestionSignature?.trim() ?? "";
|
|
25736
|
+
let pending = extractPendingPlanQuestions(parts);
|
|
25737
|
+
if (dismissed && pending?.signature === dismissed) pending = null;
|
|
25667
25738
|
const last = lastTopLevelTool(parts);
|
|
25668
25739
|
if (last?.type === "tool" && isAskUserToolName(last.name)) {
|
|
25669
25740
|
if (existing?.source === "ask_user" && existing.onScreen) return existing;
|
|
25670
|
-
const pending = extractPendingPlanQuestions(parts);
|
|
25671
25741
|
const questions2 = pending?.questions ?? existing?.questions;
|
|
25672
25742
|
if (!questions2?.length) {
|
|
25673
25743
|
return existing?.source === "ask_user" ? { ...existing, onScreen: true } : existing ?? null;
|
|
@@ -25680,13 +25750,32 @@ function askBlockAfterLiveParts(existing, parts) {
|
|
|
25680
25750
|
questions: questions2
|
|
25681
25751
|
};
|
|
25682
25752
|
}
|
|
25753
|
+
if (pending) {
|
|
25754
|
+
if (existing?.source === "ask_user" && existing.onScreen && existing.questions?.length) {
|
|
25755
|
+
return existing;
|
|
25756
|
+
}
|
|
25757
|
+
const at = existing?.source === "ask_user" ? existing.at : void 0;
|
|
25758
|
+
return {
|
|
25759
|
+
...makeAgentBlock("ask_user", formatAskUserNotifyMessage(pending.questions), at),
|
|
25760
|
+
onScreen: true,
|
|
25761
|
+
questionSignature: pending.signature,
|
|
25762
|
+
questions: pending.questions
|
|
25763
|
+
};
|
|
25764
|
+
}
|
|
25765
|
+
if (existing?.source === "ask_user" && existing.onScreen && existing.questions?.length) {
|
|
25766
|
+
return existing;
|
|
25767
|
+
}
|
|
25683
25768
|
if (last && existing?.source === "ask_user") return null;
|
|
25684
25769
|
return existing ?? null;
|
|
25685
25770
|
}
|
|
25686
25771
|
function syncAskUserBlockFromLive(threadId, parts) {
|
|
25687
25772
|
const thread = readThread(threadId);
|
|
25688
25773
|
if (!thread || thread.status === "archived") return;
|
|
25689
|
-
const next = askBlockAfterLiveParts(
|
|
25774
|
+
const next = askBlockAfterLiveParts(
|
|
25775
|
+
thread.agentBlock,
|
|
25776
|
+
parts,
|
|
25777
|
+
thread.dismissedQuestionSignature
|
|
25778
|
+
);
|
|
25690
25779
|
if (askBlocksEqual(thread.agentBlock, next)) return;
|
|
25691
25780
|
updateThread(threadId, { agentBlock: next });
|
|
25692
25781
|
}
|
|
@@ -31373,7 +31462,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
31373
31462
|
lines.push(formatDevAccessHint(opts?.activeRuns));
|
|
31374
31463
|
lines.push("");
|
|
31375
31464
|
lines.push(
|
|
31376
|
-
"Automations (sidebar, after Board): `create_schedule` / `list_schedules` (`at` / `every` / `cron` / `time`+`days`). `archiveChat=false` keeps the new chat. `chatId=self`
|
|
31465
|
+
"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
31466
|
);
|
|
31378
31467
|
lines.push(
|
|
31379
31468
|
"`set_workspace_tags` labels this checkout (omit ref; replace, add, or remove). Not another checkout."
|
|
@@ -31393,7 +31482,7 @@ function connectedOrchestratorTurnReminder(thread, find) {
|
|
|
31393
31482
|
return formatConnectedOrchestratorReminder(connectedOrchestrator(thread, find));
|
|
31394
31483
|
}
|
|
31395
31484
|
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
|
|
31485
|
+
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
31486
|
}
|
|
31398
31487
|
function formatClaudeSubagentReminder() {
|
|
31399
31488
|
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.';
|
|
@@ -34715,7 +34804,9 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
34715
34804
|
const taskState2 = deriveTaskState({
|
|
34716
34805
|
status: thread.status,
|
|
34717
34806
|
stillRunning,
|
|
34718
|
-
lastAgentParts: lastAgent?.parts
|
|
34807
|
+
lastAgentParts: lastAgent?.parts,
|
|
34808
|
+
dismissedQuestionSignature: thread.dismissedQuestionSignature,
|
|
34809
|
+
userAnswered: userRepliedAfterAgent(thread.messages, lastAgent)
|
|
34719
34810
|
});
|
|
34720
34811
|
const block = thread.agentBlock?.reason?.trim() ? thread.agentBlock : null;
|
|
34721
34812
|
return {
|
|
@@ -35451,7 +35542,15 @@ async function fireSchedule(id) {
|
|
|
35451
35542
|
const deps = fireHooks ?? await defaultDeps();
|
|
35452
35543
|
const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
|
|
35453
35544
|
const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
|
|
35454
|
-
if (
|
|
35545
|
+
if (schedule.threadId && (!target || target.status === "archived")) {
|
|
35546
|
+
deleteSchedule(schedule.id);
|
|
35547
|
+
return {
|
|
35548
|
+
...schedule,
|
|
35549
|
+
enabled: false,
|
|
35550
|
+
lastError: "Removed because its chat is archived or gone."
|
|
35551
|
+
};
|
|
35552
|
+
}
|
|
35553
|
+
if (target) {
|
|
35455
35554
|
const sent = await deps.send(target.id, prompt, {
|
|
35456
35555
|
attachments: schedule.attachments,
|
|
35457
35556
|
options: scheduleSendOptions(schedule)
|
|
@@ -35461,8 +35560,7 @@ async function fireSchedule(id) {
|
|
|
35461
35560
|
lastError: null
|
|
35462
35561
|
});
|
|
35463
35562
|
}
|
|
35464
|
-
const
|
|
35465
|
-
const archiveFresh = schedule.archiveChat !== false && !pinReplacement;
|
|
35563
|
+
const archiveFresh = schedule.archiveChat !== false;
|
|
35466
35564
|
const created = await deps.startOrchestration({
|
|
35467
35565
|
goal: prompt,
|
|
35468
35566
|
agent: pickAgent(schedule),
|
|
@@ -35475,9 +35573,6 @@ async function fireSchedule(id) {
|
|
|
35475
35573
|
...archiveFresh ? { ephemeralAutomationId: schedule.id } : {},
|
|
35476
35574
|
ephemeralTitle: schedule.name
|
|
35477
35575
|
});
|
|
35478
|
-
if (pinReplacement) {
|
|
35479
|
-
updateSchedule(schedule.id, { threadId: created.id });
|
|
35480
|
-
}
|
|
35481
35576
|
return recordScheduleRun(schedule.id, {
|
|
35482
35577
|
lastThreadId: created.id,
|
|
35483
35578
|
lastError: null
|
|
@@ -35894,6 +35989,7 @@ __export(index_exports, {
|
|
|
35894
35989
|
defaultScheduleName: () => defaultScheduleName,
|
|
35895
35990
|
deleteBranchOnPurgeEnabled: () => deleteBranchOnPurgeEnabled,
|
|
35896
35991
|
deleteSchedule: () => deleteSchedule,
|
|
35992
|
+
deleteSchedulesForThread: () => deleteSchedulesForThread,
|
|
35897
35993
|
deleteThreadRecord: () => deleteThreadRecord,
|
|
35898
35994
|
deriveTaskState: () => deriveTaskState,
|
|
35899
35995
|
desktopHostPidPath: () => desktopHostPidPath,
|
|
@@ -45361,7 +45457,7 @@ function whenFromUpdate(id, args) {
|
|
|
45361
45457
|
}
|
|
45362
45458
|
function createdHint(schedule) {
|
|
45363
45459
|
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.";
|
|
45460
|
+
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
45461
|
return `Fires while Sideboard.app is running.${fresh}${awake}`;
|
|
45366
45462
|
}
|
|
45367
45463
|
function registerScheduleTools(server) {
|
|
@@ -45379,7 +45475,7 @@ function registerScheduleTools(server) {
|
|
|
45379
45475
|
);
|
|
45380
45476
|
server.tool(
|
|
45381
45477
|
"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.
|
|
45478
|
+
"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
45479
|
{
|
|
45384
45480
|
prompt: import_zod10.z.string().describe("User message / goal queued when the automation fires"),
|
|
45385
45481
|
name: import_zod10.z.string().optional(),
|
|
@@ -45393,7 +45489,7 @@ function registerScheduleTools(server) {
|
|
|
45393
45489
|
"Archive a new Global chat when the run finishes. Default true. Pass false to leave the chat open."
|
|
45394
45490
|
),
|
|
45395
45491
|
chatId: import_zod10.z.string().optional().describe(
|
|
45396
|
-
'Existing chat id
|
|
45492
|
+
'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
45493
|
),
|
|
45398
45494
|
threadId: import_zod10.z.string().optional().describe("Legacy alias for chatId."),
|
|
45399
45495
|
agent: import_zod10.z.enum(["claude", "cursor", "codex", "opencode"]).optional().describe("Agent for a new Global chat (omit for Account default)"),
|
|
@@ -45445,7 +45541,7 @@ function registerScheduleTools(server) {
|
|
|
45445
45541
|
tz: import_zod10.z.string().optional(),
|
|
45446
45542
|
archiveChat: import_zod10.z.boolean().optional().describe("Archive a new Global chat when the run finishes. False leaves it open."),
|
|
45447
45543
|
chatId: import_zod10.z.string().optional().describe(
|
|
45448
|
-
'Existing chat
|
|
45544
|
+
'Existing chat, "self", or empty string for a Global chat each run. A bound job is removed when that chat is archived.'
|
|
45449
45545
|
),
|
|
45450
45546
|
threadId: import_zod10.z.string().optional().describe("Legacy alias for chatId."),
|
|
45451
45547
|
agent: import_zod10.z.enum(["claude", "cursor", "codex", "opencode"]).optional(),
|
|
@@ -50039,6 +50135,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
50039
50135
|
defaultScheduleName,
|
|
50040
50136
|
deleteBranchOnPurgeEnabled,
|
|
50041
50137
|
deleteSchedule,
|
|
50138
|
+
deleteSchedulesForThread,
|
|
50042
50139
|
deleteThreadRecord,
|
|
50043
50140
|
deriveTaskState,
|
|
50044
50141
|
desktopHostPidPath,
|