@sideboard-ai/core 0.1.318 → 0.1.320
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-TKAFNXCM.js → abletime-CRRLEYTE.js} +6 -4
- package/dist/{abletime-KWOBUL46.js → abletime-ICW6Q2AB.js} +6 -4
- package/dist/{abletime-oauth-S4AXA4WR.js → abletime-oauth-P3KPPJE4.js} +3 -3
- package/dist/{abletime-oauth-IUIAGLFJ.js → abletime-oauth-Q76XBSPG.js} +3 -3
- package/dist/{abletime-rest-RWN4EPY3.js → abletime-rest-DNFAYYLP.js} +3 -3
- package/dist/{abletime-rest-ORBELZQO.js → abletime-rest-DQ3PNKXP.js} +3 -3
- package/dist/{agents-KABJUDPI.js → agents-CJZYJOWP.js} +7 -7
- package/dist/{agents-2AR7I6B6.js → agents-F2E2HACB.js} +7 -7
- package/dist/{app-settings-CZVFMOI5.js → app-settings-KMPVI2B7.js} +1 -1
- package/dist/{app-settings-V6YPYY57.js → app-settings-P3H4SEIK.js} +1 -1
- package/dist/{chunk-YEIHCSZS.js → chunk-4GZC6DDH.js} +2 -0
- package/dist/{chunk-XOZNEAWF.js → chunk-56M6VEXI.js} +3 -3
- package/dist/{chunk-7SCVGGF6.js → chunk-5OQONGHO.js} +5 -5
- package/dist/{chunk-A6C67DY5.js → chunk-5S3YP5KH.js} +4 -4
- package/dist/{chunk-I5CLCWUK.js → chunk-72PUPPV2.js} +9 -5
- package/dist/{chunk-BXTISNKW.js → chunk-B7UL36WH.js} +428 -99
- package/dist/{chunk-W5QZWAUB.js → chunk-BTIXTH4N.js} +9 -5
- package/dist/{chunk-AESO2KJS.js → chunk-CB5Z5C3J.js} +2 -2
- package/dist/{chunk-2HOZMSKQ.js → chunk-DFUXW2IT.js} +2 -2
- package/dist/{chunk-ST2UQBJT.js → chunk-DJZRDTZY.js} +6 -6
- package/dist/{chunk-TUJFCJJU.js → chunk-EDXTP2VR.js} +2 -2
- package/dist/{chunk-I5TESHDN.js → chunk-EQ52JR3Q.js} +5 -5
- package/dist/{chunk-FDXHNROD.js → chunk-EQ5JY3MJ.js} +2 -2
- package/dist/{chunk-E52SQENB.js → chunk-FZKAAAEB.js} +3 -1
- package/dist/{chunk-VZAJVX36.js → chunk-HHPTGIKS.js} +2 -2
- package/dist/{chunk-23ZUL2EX.js → chunk-IDPFLXRY.js} +429 -100
- package/dist/{chunk-GCHSJCCX.js → chunk-IFU4W4C4.js} +3 -1
- package/dist/{chunk-IAPO7ZFG.js → chunk-LLIEU2ZB.js} +5 -5
- package/dist/{chunk-MBYGWNLQ.js → chunk-OAFBHCSM.js} +1 -1
- package/dist/{chunk-NRSC4N5X.js → chunk-P74GXA5V.js} +6 -6
- package/dist/{chunk-A46CIARU.js → chunk-PNLGWAYE.js} +2 -2
- package/dist/{chunk-53OCOGND.js → chunk-QGY3UNNL.js} +2 -2
- package/dist/{chunk-7Q327QF2.js → chunk-QIC2JXHW.js} +5 -5
- package/dist/{chunk-YALFZKSC.js → chunk-RHJPP26T.js} +11 -11
- package/dist/{chunk-AZ4GEEGL.js → chunk-UK2KESBN.js} +2 -2
- package/dist/{chunk-7ADEYEMH.js → chunk-V76MQ7MH.js} +5 -5
- package/dist/{chunk-HOLB6ZFZ.js → chunk-XMHMVEIY.js} +2 -0
- package/dist/{chunk-GH7UMULC.js → chunk-ZYZBCLJR.js} +6 -6
- package/dist/{conductor-MG2RAQNT.js → conductor-FPFY6Z5S.js} +6 -6
- package/dist/{conductor-NIUBJLTS.js → conductor-JA5W3L7C.js} +6 -6
- package/dist/{coordinator-prompt-3CT3D5UM.js → coordinator-prompt-M75TAN43.js} +4 -4
- package/dist/{coordinator-prompt-X74F3JIC.js → coordinator-prompt-NUC2ZXMJ.js} +4 -4
- package/dist/{global-workspace-BUWMRNW5.js → global-workspace-5A4H34AF.js} +4 -4
- package/dist/{global-workspace-FTNJEML3.js → global-workspace-SCLQUNUI.js} +4 -4
- package/dist/index.cjs +861 -475
- package/dist/index.d.cts +56 -13
- package/dist/index.d.ts +56 -13
- package/dist/index.js +54 -31
- package/dist/mcp/run-stdio.cjs +459 -95
- package/dist/mcp/run-stdio.js +23 -23
- package/dist/{optional-cli-EMSZBYDE.js → optional-cli-2V3SLME5.js} +3 -3
- package/dist/{optional-cli-6GGESWGE.js → optional-cli-MRNQKVIR.js} +4 -4
- package/dist/{orchestrator-N54V3B76.js → orchestrator-7BDZ5GWD.js} +10 -10
- package/dist/{orchestrator-2SXK4U65.js → orchestrator-NPFWU3XU.js} +10 -10
- package/dist/{thread-store-PLNIWFZ4.js → thread-store-JWHVXLDX.js} +1 -1
- package/dist/{thread-store-7BBA63KV.js → thread-store-QHYN2ZMQ.js} +1 -1
- package/dist/{workspaces-2V5UYPYC.js → workspaces-5QA3YM4L.js} +4 -4
- package/dist/{workspaces-MGKEAYNM.js → workspaces-KWMBOTQD.js} +4 -4
- package/dist/{worktree-THAXW5U7.js → worktree-7EATHVYQ.js} +3 -3
- package/dist/{worktree-XJKLDYOL.js → worktree-O6BANO2I.js} +3 -3
- package/package.json +1 -1
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -1405,13 +1405,13 @@ function toolDescription(name, input) {
|
|
|
1405
1405
|
else if (/notify_orchestrator$/i.test(name)) return "Notify orchestrator";
|
|
1406
1406
|
else if (/set_workspace_tags$/i.test(name)) return "Set workspace tags";
|
|
1407
1407
|
if (/(?:list|set|delete)_env$/i.test(name)) return /list_env$/i.test(name) ? "List env vars" : /set_env$/i.test(name) ? "Set env var" : "Delete env var";
|
|
1408
|
-
if (/list_schedules$/i.test(name)) return "List
|
|
1408
|
+
if (/list_schedules$/i.test(name)) return "List automations";
|
|
1409
1409
|
if (/create_schedule$/i.test(name)) {
|
|
1410
|
-
return str(input?.name) ? `
|
|
1410
|
+
return str(input?.name) ? `Automation ${str(input?.name)}` : "Create automation";
|
|
1411
1411
|
}
|
|
1412
|
-
if (/update_schedule$/i.test(name)) return "Update
|
|
1413
|
-
if (/delete_schedule$/i.test(name)) return "Delete
|
|
1414
|
-
if (/run_schedule$/i.test(name)) return "Run
|
|
1412
|
+
if (/update_schedule$/i.test(name)) return "Update automation";
|
|
1413
|
+
if (/delete_schedule$/i.test(name)) return "Delete automation";
|
|
1414
|
+
if (/run_schedule$/i.test(name)) return "Run automation";
|
|
1415
1415
|
if (isSkillToolName(name)) {
|
|
1416
1416
|
const cmd = skillCommandFromInput(input);
|
|
1417
1417
|
return cmd ? `Using /${cmd}` : "Using skill";
|
|
@@ -4532,7 +4532,9 @@ function planHistoryRetention(archived, thresholds = {}) {
|
|
|
4532
4532
|
if (archivedUpdatedMs(thread) < cutoff) expiredIds.add(thread.id);
|
|
4533
4533
|
}
|
|
4534
4534
|
}
|
|
4535
|
-
const remaining = oldestFirst.filter(
|
|
4535
|
+
const remaining = oldestFirst.filter(
|
|
4536
|
+
(t) => !expiredIds.has(t.id) && !t.ephemeralAutomationId?.trim()
|
|
4537
|
+
);
|
|
4536
4538
|
const overflow = remaining.length > maxCount ? remaining.slice(0, remaining.length - maxCount) : [];
|
|
4537
4539
|
const stripIds = [];
|
|
4538
4540
|
const purgeIds = [...expiredIds];
|
|
@@ -7638,6 +7640,7 @@ function normalizeThread(raw) {
|
|
|
7638
7640
|
quotaContinuedFromId: raw.quotaContinuedFromId ?? null,
|
|
7639
7641
|
accountId: raw.accountId === null ? null : typeof raw.accountId === "string" && raw.accountId.trim() ? raw.accountId.trim() : void 0,
|
|
7640
7642
|
archivedAt: typeof raw.archivedAt === "string" && raw.archivedAt.trim() ? raw.archivedAt.trim() : void 0,
|
|
7643
|
+
ephemeralAutomationId: typeof raw.ephemeralAutomationId === "string" && raw.ephemeralAutomationId.trim() ? raw.ephemeralAutomationId.trim() : void 0,
|
|
7641
7644
|
compactedMessages: Array.isArray(raw.compactedMessages) ? raw.compactedMessages : void 0
|
|
7642
7645
|
};
|
|
7643
7646
|
}
|
|
@@ -7824,6 +7827,7 @@ function updateThread(id, patch) {
|
|
|
7824
7827
|
} else {
|
|
7825
7828
|
delete next.archivedAt;
|
|
7826
7829
|
}
|
|
7830
|
+
if (!next.ephemeralAutomationId?.trim()) delete next.ephemeralAutomationId;
|
|
7827
7831
|
writeThread(next);
|
|
7828
7832
|
return next;
|
|
7829
7833
|
}
|
|
@@ -10250,7 +10254,7 @@ var init_coordinator_prompt = __esm({
|
|
|
10250
10254
|
"- 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.",
|
|
10251
10255
|
"- 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.",
|
|
10252
10256
|
"- 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.",
|
|
10253
|
-
"- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014
|
|
10257
|
+
"- 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), or 5-field `cron`. Recurring jobs without chatId open a new chat each run and archive it when that run finishes (History keeps the latest run 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.",
|
|
10254
10258
|
"Projects:",
|
|
10255
10259
|
"- add_project / remove_project \u2014 register or unregister a git repo",
|
|
10256
10260
|
"Workspaces and chats:",
|
|
@@ -20060,6 +20064,77 @@ var init_steer_request = __esm({
|
|
|
20060
20064
|
}
|
|
20061
20065
|
});
|
|
20062
20066
|
|
|
20067
|
+
// src/orchestrator/ephemeral-automation.ts
|
|
20068
|
+
function ephemeralRunReadyToArchive(thread) {
|
|
20069
|
+
if (!thread.ephemeralAutomationId?.trim()) return false;
|
|
20070
|
+
if (thread.status !== "idle" && thread.status !== "error") return false;
|
|
20071
|
+
if (thread.queue.length > 0) return false;
|
|
20072
|
+
if (thread.agentBlock?.reason?.trim()) return false;
|
|
20073
|
+
if (thread.quotaResumeAt) return false;
|
|
20074
|
+
return true;
|
|
20075
|
+
}
|
|
20076
|
+
function markEphemeralAutomation(threadId, opts) {
|
|
20077
|
+
const id = opts.ephemeralAutomationId?.trim();
|
|
20078
|
+
const current = readThread(threadId);
|
|
20079
|
+
if (!current) throw new Error(`Thread not found: ${threadId}`);
|
|
20080
|
+
if (!id) return current;
|
|
20081
|
+
const title = opts.ephemeralTitle?.trim();
|
|
20082
|
+
return updateThread(threadId, {
|
|
20083
|
+
ephemeralAutomationId: id,
|
|
20084
|
+
...title ? { title, userSetTitle: true } : {}
|
|
20085
|
+
});
|
|
20086
|
+
}
|
|
20087
|
+
async function archiveEphemeralAutomationIfReady(threadId, archive) {
|
|
20088
|
+
const keep = await withThreadLock(threadId, async () => {
|
|
20089
|
+
const thread = readThread(threadId);
|
|
20090
|
+
if (!thread || !ephemeralRunReadyToArchive(thread)) return null;
|
|
20091
|
+
const automationId = thread.ephemeralAutomationId?.trim();
|
|
20092
|
+
if (!automationId) return null;
|
|
20093
|
+
await archive(thread.id);
|
|
20094
|
+
return {
|
|
20095
|
+
automationId,
|
|
20096
|
+
keepId: archivedContinuationId(automationId, threadId) ?? threadId
|
|
20097
|
+
};
|
|
20098
|
+
});
|
|
20099
|
+
if (keep) forgetOlderEphemeralRuns(keep.automationId, keep.keepId);
|
|
20100
|
+
}
|
|
20101
|
+
function archivedContinuationId(automationId, sourceId) {
|
|
20102
|
+
for (const thread of listThreads({ includeArchived: true })) {
|
|
20103
|
+
if (thread.id === sourceId || thread.status !== "archived") continue;
|
|
20104
|
+
if (thread.ephemeralAutomationId !== automationId) continue;
|
|
20105
|
+
if (thread.quotaContinuedFromId !== sourceId) continue;
|
|
20106
|
+
return thread.id;
|
|
20107
|
+
}
|
|
20108
|
+
return null;
|
|
20109
|
+
}
|
|
20110
|
+
function clearEphemeralAutomation(threadId) {
|
|
20111
|
+
const thread = readThread(threadId);
|
|
20112
|
+
if (!thread?.ephemeralAutomationId?.trim()) return;
|
|
20113
|
+
updateThread(threadId, { ephemeralAutomationId: void 0 });
|
|
20114
|
+
}
|
|
20115
|
+
function forgetOlderEphemeralRuns(automationId, keepId) {
|
|
20116
|
+
const id = automationId.trim();
|
|
20117
|
+
if (!id || !keepId) return [];
|
|
20118
|
+
const removed = [];
|
|
20119
|
+
for (const thread of listThreads({ includeArchived: true })) {
|
|
20120
|
+
if (thread.id === keepId) continue;
|
|
20121
|
+
if (thread.status !== "archived") continue;
|
|
20122
|
+
if (thread.ephemeralAutomationId !== id) continue;
|
|
20123
|
+
try {
|
|
20124
|
+
deleteThreadRecord(thread.id);
|
|
20125
|
+
removed.push(thread.id);
|
|
20126
|
+
} catch {
|
|
20127
|
+
}
|
|
20128
|
+
}
|
|
20129
|
+
return removed;
|
|
20130
|
+
}
|
|
20131
|
+
var init_ephemeral_automation = __esm({
|
|
20132
|
+
"src/orchestrator/ephemeral-automation.ts"() {
|
|
20133
|
+
"use strict";
|
|
20134
|
+
init_thread_store();
|
|
20135
|
+
}
|
|
20136
|
+
});
|
|
20137
|
+
|
|
20063
20138
|
// src/threads/title.ts
|
|
20064
20139
|
var title_exports = {};
|
|
20065
20140
|
__export(title_exports, {
|
|
@@ -22170,6 +22245,7 @@ var init_abletime_projects = __esm({
|
|
|
22170
22245
|
var abletime_exports = {};
|
|
22171
22246
|
__export(abletime_exports, {
|
|
22172
22247
|
ableTimeDependencyTarget: () => ableTimeDependencyTarget,
|
|
22248
|
+
ableTimeStateIsClosed: () => ableTimeStateIsClosed,
|
|
22173
22249
|
commentAbleTimeTask: () => commentAbleTimeTask,
|
|
22174
22250
|
createAbleTimeTask: () => createAbleTimeTask,
|
|
22175
22251
|
downloadAbleTimeAttachment: () => downloadAbleTimeAttachment,
|
|
@@ -22323,9 +22399,12 @@ function issueAttachmentForAbleTimeTask(task) {
|
|
|
22323
22399
|
].filter(Boolean).join("\n")
|
|
22324
22400
|
};
|
|
22325
22401
|
}
|
|
22402
|
+
function ableTimeStateIsClosed(state) {
|
|
22403
|
+
const value = (state ?? "").trim().toLowerCase();
|
|
22404
|
+
return Boolean(value && CLOSED_STATES.has(value));
|
|
22405
|
+
}
|
|
22326
22406
|
function isOpenTask(task) {
|
|
22327
|
-
|
|
22328
|
-
return !state || !CLOSED_STATES.has(state);
|
|
22407
|
+
return !ableTimeStateIsClosed(task.state);
|
|
22329
22408
|
}
|
|
22330
22409
|
async function getAbleTimeOrientation(opts) {
|
|
22331
22410
|
const raw = await callAbleTimeTool("orientation", {}, opts);
|
|
@@ -23301,6 +23380,9 @@ function writeTurnLive(threadId, progress) {
|
|
|
23301
23380
|
}
|
|
23302
23381
|
}
|
|
23303
23382
|
}
|
|
23383
|
+
function readTurnLiveParts(threadId) {
|
|
23384
|
+
return buffers.get(threadId)?.parts.slice() ?? [];
|
|
23385
|
+
}
|
|
23304
23386
|
function readTurnLive(threadId) {
|
|
23305
23387
|
const path = threadLivePath(threadId);
|
|
23306
23388
|
if (!(0, import_node_fs55.existsSync)(path)) return null;
|
|
@@ -23561,17 +23643,23 @@ async function isolateQuotaFailover(run2) {
|
|
|
23561
23643
|
}
|
|
23562
23644
|
}
|
|
23563
23645
|
function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
|
|
23646
|
+
const ephemeralAutomationId = from.ephemeralAutomationId?.trim();
|
|
23647
|
+
const ephemeralTitle = ephemeralAutomationId ? from.title.trim() : "";
|
|
23564
23648
|
const handoff = buildQuotaHandoffAttachment(from, limitText, fallbackAgent);
|
|
23565
23649
|
const tab = createChatTab({
|
|
23566
23650
|
fromThreadId: from.id,
|
|
23567
23651
|
agent: fallbackAgent,
|
|
23568
23652
|
model: null,
|
|
23569
23653
|
attachments: [handoff],
|
|
23654
|
+
...ephemeralTitle ? { title: ephemeralTitle } : {},
|
|
23570
23655
|
...opts && "accountId" in opts ? { accountId: opts.accountId } : {}
|
|
23571
23656
|
});
|
|
23572
23657
|
const patch = {
|
|
23573
23658
|
quotaContinuedFromId: from.id,
|
|
23574
|
-
sourceRef: from.sourceRef
|
|
23659
|
+
sourceRef: from.sourceRef,
|
|
23660
|
+
// The original drain archives as idle. This sibling has to carry the one-off
|
|
23661
|
+
// so it archives when the continued turn finishes and History keeps it.
|
|
23662
|
+
...ephemeralAutomationId ? { ephemeralAutomationId } : {}
|
|
23575
23663
|
};
|
|
23576
23664
|
if (isOrchestratorThread(from)) {
|
|
23577
23665
|
patch.parentThreadId = from.id;
|
|
@@ -25585,6 +25673,41 @@ var init_expand = __esm({
|
|
|
25585
25673
|
}
|
|
25586
25674
|
});
|
|
25587
25675
|
|
|
25676
|
+
// src/composer/agent-has-replied.ts
|
|
25677
|
+
function joinSteerPrompt(base, addition) {
|
|
25678
|
+
const next = addition.trim();
|
|
25679
|
+
if (!next) return base;
|
|
25680
|
+
const head = base.replace(/\s+$/, "");
|
|
25681
|
+
if (!head) return next;
|
|
25682
|
+
return `${head}
|
|
25683
|
+
${next}`;
|
|
25684
|
+
}
|
|
25685
|
+
function trailingUnansweredUserText(messages) {
|
|
25686
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
25687
|
+
const message = messages[i];
|
|
25688
|
+
if (!message || message.origin === "continue" || message.role === "summary") continue;
|
|
25689
|
+
if (message.role === "agent") {
|
|
25690
|
+
const text7 = (message.text ?? "").trim();
|
|
25691
|
+
if (text7 || (message.parts?.length ?? 0) > 0) return null;
|
|
25692
|
+
continue;
|
|
25693
|
+
}
|
|
25694
|
+
if (message.role === "user") return message.text;
|
|
25695
|
+
}
|
|
25696
|
+
return null;
|
|
25697
|
+
}
|
|
25698
|
+
function livePartsShowAgentReply(parts) {
|
|
25699
|
+
for (const part of parts) {
|
|
25700
|
+
if (part.type === "tool") return true;
|
|
25701
|
+
if ((part.type === "text" || part.type === "thinking") && part.text.trim()) return true;
|
|
25702
|
+
}
|
|
25703
|
+
return false;
|
|
25704
|
+
}
|
|
25705
|
+
var init_agent_has_replied = __esm({
|
|
25706
|
+
"src/composer/agent-has-replied.ts"() {
|
|
25707
|
+
"use strict";
|
|
25708
|
+
}
|
|
25709
|
+
});
|
|
25710
|
+
|
|
25588
25711
|
// src/composer/consume-attachments.ts
|
|
25589
25712
|
function consumeComposerAttachments(thread) {
|
|
25590
25713
|
return {
|
|
@@ -25642,6 +25765,142 @@ var init_consume_attachments = __esm({
|
|
|
25642
25765
|
}
|
|
25643
25766
|
});
|
|
25644
25767
|
|
|
25768
|
+
// src/orchestrator/enqueue-thread-send.ts
|
|
25769
|
+
function resolveSendFollowUp(thread, requested) {
|
|
25770
|
+
if (requested === "steer" || requested === "queue") return requested;
|
|
25771
|
+
return isOrchestratorThread(thread) ? followUpBehavior() : "queue";
|
|
25772
|
+
}
|
|
25773
|
+
function rewriteTrailingUserPrompt(threadId, from, to) {
|
|
25774
|
+
if (from === to) return;
|
|
25775
|
+
const thread = readThread(threadId);
|
|
25776
|
+
if (!thread) return;
|
|
25777
|
+
const messages = thread.messages.slice();
|
|
25778
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
25779
|
+
const message = messages[i];
|
|
25780
|
+
if (!message || message.origin === "continue" || message.role === "summary") continue;
|
|
25781
|
+
if (message.role === "user" && message.text === from) {
|
|
25782
|
+
messages[i] = { ...message, text: to };
|
|
25783
|
+
updateThread(threadId, { messages });
|
|
25784
|
+
}
|
|
25785
|
+
return;
|
|
25786
|
+
}
|
|
25787
|
+
}
|
|
25788
|
+
function reuseJoinedUserBubble(reused, threadId, last, promptText) {
|
|
25789
|
+
return reused.delete(threadId) && last?.role === "user" && last.origin !== "continue" && last.text === promptText;
|
|
25790
|
+
}
|
|
25791
|
+
function promptForJoinedSteer(input) {
|
|
25792
|
+
if (input.latestPrompt === input.promptText) return input.agentPrompt;
|
|
25793
|
+
rewriteTrailingUserPrompt(input.threadId, input.promptText, input.latestPrompt);
|
|
25794
|
+
const { agentPrompt: expandedLatest } = expandComposerPrompt(
|
|
25795
|
+
input.worktreePath,
|
|
25796
|
+
expandCanonicalGitRequest(input.latestPrompt),
|
|
25797
|
+
{ attachments: input.attachments }
|
|
25798
|
+
);
|
|
25799
|
+
return input.expandedPrompt && input.agentPrompt.endsWith(input.expandedPrompt) ? input.agentPrompt.slice(0, -input.expandedPrompt.length) + expandedLatest : `${input.agentPrompt}
|
|
25800
|
+
|
|
25801
|
+
${expandedLatest}`;
|
|
25802
|
+
}
|
|
25803
|
+
function clearSendBookkeeping(host, threadId) {
|
|
25804
|
+
host.crashContinued.delete(threadId);
|
|
25805
|
+
host.jobContinueCount.delete(threadId);
|
|
25806
|
+
host.jobContinueNudged.delete(threadId);
|
|
25807
|
+
host.haltDrain.delete(threadId);
|
|
25808
|
+
}
|
|
25809
|
+
async function enqueueThreadSend(host, threadRef, prompt, opts) {
|
|
25810
|
+
const thread = host.requireThread(threadRef);
|
|
25811
|
+
if (thread.status === "archived") {
|
|
25812
|
+
throw new Error(`Thread is archived: ${thread.id}`);
|
|
25813
|
+
}
|
|
25814
|
+
let shouldSteer = false;
|
|
25815
|
+
const sent = await withThreadLock(thread.id, async () => {
|
|
25816
|
+
const current = host.requireThread(thread.id);
|
|
25817
|
+
if (current.status === "archived") {
|
|
25818
|
+
throw new Error(`Thread is archived: ${thread.id}`);
|
|
25819
|
+
}
|
|
25820
|
+
const followUp = resolveSendFollowUp(current, opts?.followUp);
|
|
25821
|
+
const explicit = opts?.attachments;
|
|
25822
|
+
const consumed = explicit !== void 0 ? { attachments: current.attachments, consumed: explicit } : consumeComposerAttachments(current);
|
|
25823
|
+
const inFlightEarly = host.activeTurns.has(thread.id) || host.startingTurns.has(thread.id) || current.status === "running";
|
|
25824
|
+
const agentHasRepliedEarly = livePartsShowAgentReply(readTurnLiveParts(current.id));
|
|
25825
|
+
const draft = host.openSteerPrompt.get(current.id);
|
|
25826
|
+
const queuedHead = !inFlightEarly && current.status === "queued" && current.queue.length > 0 ? current.queue[0] : null;
|
|
25827
|
+
const unanswered = followUp === "steer" && !agentHasRepliedEarly ? draft?.text ?? (inFlightEarly ? trailingUnansweredUserText(current.messages) : queuedHead) : null;
|
|
25828
|
+
if (unanswered != null && (draft ? !draft.spawned : queuedHead != null)) {
|
|
25829
|
+
clearSendBookkeeping(host, thread.id);
|
|
25830
|
+
const combined = joinSteerPrompt(unanswered, prompt);
|
|
25831
|
+
if (draft && !draft.spawned) {
|
|
25832
|
+
draft.text = combined;
|
|
25833
|
+
rewriteTrailingUserPrompt(current.id, unanswered, combined);
|
|
25834
|
+
} else {
|
|
25835
|
+
const queue = current.queue.slice();
|
|
25836
|
+
queue[0] = combined;
|
|
25837
|
+
const queueAttachments = alignQueueAttachments(queue.length, current.queueAttachments);
|
|
25838
|
+
if (consumed.consumed.length > 0) {
|
|
25839
|
+
queueAttachments[0] = [...queueAttachments[0] ?? [], ...consumed.consumed];
|
|
25840
|
+
}
|
|
25841
|
+
const patch2 = { queue, queueAttachments };
|
|
25842
|
+
if (explicit === void 0 && consumed.consumed.length > 0) {
|
|
25843
|
+
patch2.attachments = consumed.attachments;
|
|
25844
|
+
}
|
|
25845
|
+
updateThread(current.id, patch2);
|
|
25846
|
+
host.emit({ type: "queue_changed", threadId: current.id, queue });
|
|
25847
|
+
}
|
|
25848
|
+
if (thisProcessShouldDrainAgentQueues() && !inFlightEarly) {
|
|
25849
|
+
host.armDrain(current.id);
|
|
25850
|
+
}
|
|
25851
|
+
return host.requireThread(current.id);
|
|
25852
|
+
}
|
|
25853
|
+
const promptToQueue = unanswered != null ? joinSteerPrompt(unanswered, prompt) : prompt;
|
|
25854
|
+
if (unanswered != null) {
|
|
25855
|
+
if (draft) draft.text = promptToQueue;
|
|
25856
|
+
rewriteTrailingUserPrompt(current.id, unanswered, promptToQueue);
|
|
25857
|
+
host.reusedUserPrompt.add(current.id);
|
|
25858
|
+
}
|
|
25859
|
+
const queued = appendQueuedItem(
|
|
25860
|
+
current.queue,
|
|
25861
|
+
current.queueAttachments,
|
|
25862
|
+
promptToQueue,
|
|
25863
|
+
consumed.consumed
|
|
25864
|
+
);
|
|
25865
|
+
clearSendBookkeeping(host, thread.id);
|
|
25866
|
+
const inFlight = host.activeTurns.has(thread.id) || host.startingTurns.has(thread.id) || current.status === "running";
|
|
25867
|
+
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
25868
|
+
const patch = queued;
|
|
25869
|
+
if (explicit === void 0 && consumed.consumed.length > 0) {
|
|
25870
|
+
patch.attachments = consumed.attachments;
|
|
25871
|
+
}
|
|
25872
|
+
if (!inFlight) patch.status = "queued";
|
|
25873
|
+
const pid = current.agentPid;
|
|
25874
|
+
if (typeof pid === "number" && pid > 0 && !host.pidAlive(pid)) {
|
|
25875
|
+
patch.agentPid = null;
|
|
25876
|
+
}
|
|
25877
|
+
updateThread(thread.id, patch);
|
|
25878
|
+
host.emit({ type: "queue_changed", threadId: thread.id, queue: queued.queue });
|
|
25879
|
+
if (!inFlight) {
|
|
25880
|
+
host.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
25881
|
+
}
|
|
25882
|
+
if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
|
|
25883
|
+
host.armDrain(thread.id);
|
|
25884
|
+
}
|
|
25885
|
+
return host.requireThread(thread.id);
|
|
25886
|
+
});
|
|
25887
|
+
return { thread: sent, shouldSteer };
|
|
25888
|
+
}
|
|
25889
|
+
var init_enqueue_thread_send = __esm({
|
|
25890
|
+
"src/orchestrator/enqueue-thread-send.ts"() {
|
|
25891
|
+
"use strict";
|
|
25892
|
+
init_agent_git_actions();
|
|
25893
|
+
init_agent_has_replied();
|
|
25894
|
+
init_expand();
|
|
25895
|
+
init_consume_attachments();
|
|
25896
|
+
init_desktop_host();
|
|
25897
|
+
init_thread_store();
|
|
25898
|
+
init_turn_live();
|
|
25899
|
+
init_app_settings();
|
|
25900
|
+
init_global_workspace();
|
|
25901
|
+
}
|
|
25902
|
+
});
|
|
25903
|
+
|
|
25645
25904
|
// src/skills/detached-job-path.ts
|
|
25646
25905
|
function compiledModuleDir() {
|
|
25647
25906
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
@@ -25804,7 +26063,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
25804
26063
|
lines.push(formatDevAccessHint(opts?.activeRuns));
|
|
25805
26064
|
lines.push("");
|
|
25806
26065
|
lines.push(
|
|
25807
|
-
"
|
|
26066
|
+
"Automations (sidebar, after Board): `create_schedule` / `list_schedules` (`at` / `every` / `cron`). `chatId=self` continues this chat; omit chatId for a new Global chat. Fires only while Sideboard.app is running. A future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled."
|
|
25808
26067
|
);
|
|
25809
26068
|
lines.push(
|
|
25810
26069
|
"`set_workspace_tags` labels this checkout (omit ref; replace, add, or remove). Not another checkout."
|
|
@@ -25824,7 +26083,7 @@ function connectedOrchestratorTurnReminder(thread, find) {
|
|
|
25824
26083
|
return formatConnectedOrchestratorReminder(connectedOrchestrator(thread, find));
|
|
25825
26084
|
}
|
|
25826
26085
|
function formatWorktreeReminder() {
|
|
25827
|
-
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.
|
|
26086
|
+
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; chatId=self for this chat). set_workspace_tags updates labels on this workspace (omit ref).";
|
|
25828
26087
|
}
|
|
25829
26088
|
function formatClaudeSubagentReminder() {
|
|
25830
26089
|
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.';
|
|
@@ -26947,7 +27206,7 @@ function parseDurationMs(every) {
|
|
|
26947
27206
|
}
|
|
26948
27207
|
function defaultScheduleName(prompt) {
|
|
26949
27208
|
const line = prompt.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
26950
|
-
if (!line) return "Untitled
|
|
27209
|
+
if (!line) return "Untitled automation";
|
|
26951
27210
|
return line.length > 60 ? `${line.slice(0, 57).trimEnd()}\u2026` : line;
|
|
26952
27211
|
}
|
|
26953
27212
|
function resolveScheduleThreadId(raw, env = process.env) {
|
|
@@ -27012,6 +27271,37 @@ function normalizeWhen(raw) {
|
|
|
27012
27271
|
}
|
|
27013
27272
|
throw new Error("Schedule `when` must be once, every, or cron");
|
|
27014
27273
|
}
|
|
27274
|
+
function normalizeOptionalBool(raw) {
|
|
27275
|
+
if (raw === true || raw === false) return raw;
|
|
27276
|
+
return null;
|
|
27277
|
+
}
|
|
27278
|
+
function normalizeAutonomy2(raw) {
|
|
27279
|
+
return raw === "default" || raw === "full" ? raw : null;
|
|
27280
|
+
}
|
|
27281
|
+
function normalizeAttachments(raw) {
|
|
27282
|
+
if (!Array.isArray(raw)) return [];
|
|
27283
|
+
const out = [];
|
|
27284
|
+
for (const item of raw) {
|
|
27285
|
+
if (!item || typeof item !== "object") continue;
|
|
27286
|
+
const row = item;
|
|
27287
|
+
if (typeof row.id !== "string" || !row.id.trim()) continue;
|
|
27288
|
+
if (typeof row.name !== "string" || !row.name) continue;
|
|
27289
|
+
if (typeof row.content !== "string") continue;
|
|
27290
|
+
if (!ATTACHMENT_KINDS.has(row.kind)) continue;
|
|
27291
|
+
const next = {
|
|
27292
|
+
id: row.id,
|
|
27293
|
+
name: row.name,
|
|
27294
|
+
kind: row.kind,
|
|
27295
|
+
content: row.content
|
|
27296
|
+
};
|
|
27297
|
+
if (typeof row.path === "string" && row.path) next.path = row.path;
|
|
27298
|
+
if (typeof row.previewDataUrl === "string" && row.previewDataUrl) {
|
|
27299
|
+
next.previewDataUrl = row.previewDataUrl;
|
|
27300
|
+
}
|
|
27301
|
+
out.push(next);
|
|
27302
|
+
}
|
|
27303
|
+
return out;
|
|
27304
|
+
}
|
|
27015
27305
|
function normalizeTask(raw) {
|
|
27016
27306
|
const when = normalizeWhen(raw.when);
|
|
27017
27307
|
const agent = raw.agent && isOrchestratorCapableAgent(raw.agent) ? raw.agent : null;
|
|
@@ -27024,6 +27314,11 @@ function normalizeTask(raw) {
|
|
|
27024
27314
|
threadId: raw.threadId?.trim() || null,
|
|
27025
27315
|
agent,
|
|
27026
27316
|
model: raw.model?.trim() || null,
|
|
27317
|
+
effort: normalizeThinkingEffort(raw.effort),
|
|
27318
|
+
fast: normalizeOptionalBool(raw.fast),
|
|
27319
|
+
planMode: normalizeOptionalBool(raw.planMode),
|
|
27320
|
+
autonomy: normalizeAutonomy2(raw.autonomy),
|
|
27321
|
+
attachments: normalizeAttachments(raw.attachments),
|
|
27027
27322
|
nextRunAt: raw.nextRunAt,
|
|
27028
27323
|
lastRunAt: raw.lastRunAt ?? null,
|
|
27029
27324
|
lastThreadId: raw.lastThreadId ?? null,
|
|
@@ -27070,6 +27365,11 @@ function buildTask(input, now) {
|
|
|
27070
27365
|
threadId: input.threadId?.trim() || null,
|
|
27071
27366
|
agent,
|
|
27072
27367
|
model: input.model?.trim() || null,
|
|
27368
|
+
effort: input.effort != null ? normalizeThinkingEffort(input.effort) : null,
|
|
27369
|
+
fast: normalizeOptionalBool(input.fast),
|
|
27370
|
+
planMode: normalizeOptionalBool(input.planMode),
|
|
27371
|
+
autonomy: normalizeAutonomy2(input.autonomy),
|
|
27372
|
+
attachments: normalizeAttachments(input.attachments),
|
|
27073
27373
|
nextRunAt,
|
|
27074
27374
|
lastRunAt: null,
|
|
27075
27375
|
lastThreadId: null,
|
|
@@ -27111,7 +27411,7 @@ function createSchedule(input) {
|
|
|
27111
27411
|
function updateSchedule(id, patch) {
|
|
27112
27412
|
const rows = readAll2();
|
|
27113
27413
|
const idx = rows.findIndex((row) => row.id === id || id.length >= 8 && row.id.startsWith(id));
|
|
27114
|
-
if (idx < 0) throw new Error(`
|
|
27414
|
+
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
27115
27415
|
const prev = rows[idx];
|
|
27116
27416
|
const when = patch.when ? normalizeWhen(patch.when) : prev.when;
|
|
27117
27417
|
const prompt = patch.prompt !== void 0 ? patch.prompt.trim() : prev.prompt;
|
|
@@ -27126,6 +27426,11 @@ function updateSchedule(id, patch) {
|
|
|
27126
27426
|
threadId: patch.threadId !== void 0 ? patch.threadId?.trim() || null : prev.threadId,
|
|
27127
27427
|
agent: patch.agent !== void 0 ? patch.agent ? coerceOrchestratorAgent(patch.agent) : null : prev.agent,
|
|
27128
27428
|
model: patch.model !== void 0 ? patch.model?.trim() || null : prev.model,
|
|
27429
|
+
effort: patch.effort !== void 0 ? normalizeThinkingEffort(patch.effort) : prev.effort,
|
|
27430
|
+
fast: patch.fast !== void 0 ? normalizeOptionalBool(patch.fast) : prev.fast,
|
|
27431
|
+
planMode: patch.planMode !== void 0 ? normalizeOptionalBool(patch.planMode) : prev.planMode,
|
|
27432
|
+
autonomy: patch.autonomy !== void 0 ? normalizeAutonomy2(patch.autonomy) : prev.autonomy,
|
|
27433
|
+
attachments: patch.attachments !== void 0 ? normalizeAttachments(patch.attachments) : prev.attachments,
|
|
27129
27434
|
nextRunAt: whenChanged ? computeNextRunAt(when).toISOString() : prev.nextRunAt,
|
|
27130
27435
|
lastError: whenChanged ? null : prev.lastError,
|
|
27131
27436
|
updatedAt: nowIso2()
|
|
@@ -27140,13 +27445,13 @@ function deleteSchedule(id) {
|
|
|
27140
27445
|
const next = rows.filter(
|
|
27141
27446
|
(row) => row.id !== id && !(id.length >= 8 && row.id.startsWith(id))
|
|
27142
27447
|
);
|
|
27143
|
-
if (next.length === rows.length) throw new Error(`
|
|
27448
|
+
if (next.length === rows.length) throw new Error(`Automation not found: ${id}`);
|
|
27144
27449
|
writeAll2(next);
|
|
27145
27450
|
}
|
|
27146
27451
|
function recordScheduleRun(id, result) {
|
|
27147
27452
|
const rows = readAll2();
|
|
27148
27453
|
const idx = rows.findIndex((row) => row.id === id);
|
|
27149
|
-
if (idx < 0) throw new Error(`
|
|
27454
|
+
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
27150
27455
|
const prev = rows[idx];
|
|
27151
27456
|
const firedAt = result.firedAt ?? /* @__PURE__ */ new Date();
|
|
27152
27457
|
const next = {
|
|
@@ -27162,7 +27467,7 @@ function recordScheduleRun(id, result) {
|
|
|
27162
27467
|
writeAll2(rows);
|
|
27163
27468
|
return next;
|
|
27164
27469
|
}
|
|
27165
|
-
var import_node_crypto17, import_node_fs65, import_node_path64, import_croner, DURATION_RE, UNIT_MS;
|
|
27470
|
+
var import_node_crypto17, import_node_fs65, import_node_path64, import_croner, DURATION_RE, UNIT_MS, ATTACHMENT_KINDS;
|
|
27166
27471
|
var init_schedules = __esm({
|
|
27167
27472
|
"src/store/schedules.ts"() {
|
|
27168
27473
|
"use strict";
|
|
@@ -27171,6 +27476,7 @@ var init_schedules = __esm({
|
|
|
27171
27476
|
import_node_path64 = require("path");
|
|
27172
27477
|
import_croner = require("croner");
|
|
27173
27478
|
init_orchestrator_capable();
|
|
27479
|
+
init_thinking_effort();
|
|
27174
27480
|
init_paths();
|
|
27175
27481
|
init_private_file();
|
|
27176
27482
|
init_app_settings();
|
|
@@ -27181,6 +27487,14 @@ var init_schedules = __esm({
|
|
|
27181
27487
|
h: 36e5,
|
|
27182
27488
|
d: 864e5
|
|
27183
27489
|
};
|
|
27490
|
+
ATTACHMENT_KINDS = /* @__PURE__ */ new Set([
|
|
27491
|
+
"transcript",
|
|
27492
|
+
"file",
|
|
27493
|
+
"issue",
|
|
27494
|
+
"workspace",
|
|
27495
|
+
"diff-comment",
|
|
27496
|
+
"code-ref"
|
|
27497
|
+
]);
|
|
27184
27498
|
}
|
|
27185
27499
|
});
|
|
27186
27500
|
|
|
@@ -27194,17 +27508,52 @@ async function defaultDeps() {
|
|
|
27194
27508
|
const orch = getOrchestrator2();
|
|
27195
27509
|
return {
|
|
27196
27510
|
findThread: (id) => findThreadByRef(id),
|
|
27197
|
-
send: (id, prompt) =>
|
|
27511
|
+
send: async (id, prompt, opts) => {
|
|
27512
|
+
if (opts?.options && Object.keys(opts.options).length > 0) {
|
|
27513
|
+
try {
|
|
27514
|
+
orch.setThreadOptions(id, opts.options);
|
|
27515
|
+
} catch {
|
|
27516
|
+
const rest = scheduleOptionsAfterRefusedAgentSwitch(opts.options);
|
|
27517
|
+
if (Object.keys(rest).length > 0) {
|
|
27518
|
+
try {
|
|
27519
|
+
orch.setThreadOptions(id, rest);
|
|
27520
|
+
} catch {
|
|
27521
|
+
}
|
|
27522
|
+
}
|
|
27523
|
+
}
|
|
27524
|
+
}
|
|
27525
|
+
const thread = findThreadByRef(id);
|
|
27526
|
+
const attachments = thread ? persistPendingFileAttachments(thread.worktreePath, opts?.attachments ?? []) : opts?.attachments ?? [];
|
|
27527
|
+
return orch.send(id, prompt, { attachments });
|
|
27528
|
+
},
|
|
27198
27529
|
startOrchestration: (opts) => startOrchestration2(opts)
|
|
27199
27530
|
};
|
|
27200
27531
|
}
|
|
27532
|
+
function scheduleOptionsAfterRefusedAgentSwitch(options) {
|
|
27533
|
+
const { agent: _agent, model: _model, ...rest } = options;
|
|
27534
|
+
return rest;
|
|
27535
|
+
}
|
|
27536
|
+
function scheduleSendOptions(schedule) {
|
|
27537
|
+
const patch = {};
|
|
27538
|
+
if (schedule.agent) {
|
|
27539
|
+
patch.agent = schedule.agent;
|
|
27540
|
+
patch.model = schedule.model;
|
|
27541
|
+
} else if (schedule.model) {
|
|
27542
|
+
patch.model = schedule.model;
|
|
27543
|
+
}
|
|
27544
|
+
if (schedule.effort) patch.effort = schedule.effort;
|
|
27545
|
+
if (schedule.fast != null) patch.fast = schedule.fast;
|
|
27546
|
+
if (schedule.planMode != null) patch.planMode = schedule.planMode;
|
|
27547
|
+
if (schedule.autonomy) patch.autonomy = schedule.autonomy;
|
|
27548
|
+
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
27549
|
+
}
|
|
27201
27550
|
function pickAgent(schedule) {
|
|
27202
27551
|
if (schedule.agent) return schedule.agent;
|
|
27203
27552
|
return coerceOrchestratorAgent(resolveOrchestratorDefaults().agent);
|
|
27204
27553
|
}
|
|
27205
27554
|
async function fireSchedule(id) {
|
|
27206
27555
|
const schedule = getSchedule(id);
|
|
27207
|
-
if (!schedule) throw new Error(`
|
|
27556
|
+
if (!schedule) throw new Error(`Automation not found: ${id}`);
|
|
27208
27557
|
if (firing.has(schedule.id)) return schedule;
|
|
27209
27558
|
firing.add(schedule.id);
|
|
27210
27559
|
try {
|
|
@@ -27212,18 +27561,28 @@ async function fireSchedule(id) {
|
|
|
27212
27561
|
const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
|
|
27213
27562
|
const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
|
|
27214
27563
|
if (target && target.status !== "archived") {
|
|
27215
|
-
const sent = await deps.send(target.id, prompt
|
|
27564
|
+
const sent = await deps.send(target.id, prompt, {
|
|
27565
|
+
attachments: schedule.attachments,
|
|
27566
|
+
options: scheduleSendOptions(schedule)
|
|
27567
|
+
});
|
|
27216
27568
|
return recordScheduleRun(schedule.id, {
|
|
27217
27569
|
lastThreadId: sent.id,
|
|
27218
27570
|
lastError: null
|
|
27219
27571
|
});
|
|
27220
27572
|
}
|
|
27573
|
+
const pinReplacement = Boolean(schedule.threadId) && schedule.when.kind !== "once";
|
|
27221
27574
|
const created = await deps.startOrchestration({
|
|
27222
27575
|
goal: prompt,
|
|
27223
27576
|
agent: pickAgent(schedule),
|
|
27224
|
-
model: schedule.model
|
|
27577
|
+
model: schedule.model,
|
|
27578
|
+
...schedule.effort ? { effort: schedule.effort } : {},
|
|
27579
|
+
...schedule.fast != null ? { fast: schedule.fast } : {},
|
|
27580
|
+
...schedule.planMode != null ? { planMode: schedule.planMode } : {},
|
|
27581
|
+
...schedule.autonomy ? { autonomy: schedule.autonomy } : {},
|
|
27582
|
+
attachments: schedule.attachments,
|
|
27583
|
+
...pinReplacement ? {} : { ephemeralAutomationId: schedule.id, ephemeralTitle: schedule.name }
|
|
27225
27584
|
});
|
|
27226
|
-
if (
|
|
27585
|
+
if (pinReplacement) {
|
|
27227
27586
|
updateSchedule(schedule.id, { threadId: created.id });
|
|
27228
27587
|
}
|
|
27229
27588
|
return recordScheduleRun(schedule.id, {
|
|
@@ -27293,6 +27652,7 @@ var init_schedule_runner = __esm({
|
|
|
27293
27652
|
init_desktop_host();
|
|
27294
27653
|
init_app_settings();
|
|
27295
27654
|
init_schedules();
|
|
27655
|
+
init_stage_files();
|
|
27296
27656
|
init_thread_store();
|
|
27297
27657
|
SET_TIMEOUT_MAX = 2147483647;
|
|
27298
27658
|
fireHooks = null;
|
|
@@ -27385,10 +27745,6 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
27385
27745
|
}
|
|
27386
27746
|
return true;
|
|
27387
27747
|
}
|
|
27388
|
-
function resolveSendFollowUp(thread, requested) {
|
|
27389
|
-
if (requested === "steer" || requested === "queue") return requested;
|
|
27390
|
-
return isOrchestratorThread(thread) ? followUpBehavior() : "queue";
|
|
27391
|
-
}
|
|
27392
27748
|
function resolveOrchChildFollowUp(requested) {
|
|
27393
27749
|
if (requested === "steer" || requested === "queue") return requested;
|
|
27394
27750
|
return followUpBehavior();
|
|
@@ -27429,10 +27785,11 @@ async function startOrchestration(opts) {
|
|
|
27429
27785
|
planMode: opts.planMode,
|
|
27430
27786
|
attachments: opts.attachments
|
|
27431
27787
|
});
|
|
27788
|
+
const ready2 = markEphemeralAutomation(thread2.id, opts);
|
|
27432
27789
|
if (goal) {
|
|
27433
|
-
return orch.send(
|
|
27790
|
+
return orch.send(ready2.id, goal);
|
|
27434
27791
|
}
|
|
27435
|
-
return
|
|
27792
|
+
return ready2;
|
|
27436
27793
|
}
|
|
27437
27794
|
const { titleFromPrompt: titleFromPrompt2 } = await Promise.resolve().then(() => (init_title(), title_exports));
|
|
27438
27795
|
const title = titleFromPrompt2(goal) || "Orchestration";
|
|
@@ -27467,10 +27824,11 @@ async function startOrchestration(opts) {
|
|
|
27467
27824
|
sourceType: "orchestration",
|
|
27468
27825
|
sourceRef: goal
|
|
27469
27826
|
});
|
|
27827
|
+
const ready = markEphemeralAutomation(updated.id, opts);
|
|
27470
27828
|
if (goal) {
|
|
27471
|
-
return orch.send(
|
|
27829
|
+
return orch.send(ready.id, goal);
|
|
27472
27830
|
}
|
|
27473
|
-
return
|
|
27831
|
+
return ready;
|
|
27474
27832
|
}
|
|
27475
27833
|
var import_node_events, import_node_crypto18, import_node_fs67, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton2;
|
|
27476
27834
|
var init_orchestrator = __esm({
|
|
@@ -27511,6 +27869,7 @@ var init_orchestrator = __esm({
|
|
|
27511
27869
|
init_child_halt();
|
|
27512
27870
|
init_stop_reason();
|
|
27513
27871
|
init_steer_request();
|
|
27872
|
+
init_ephemeral_automation();
|
|
27514
27873
|
init_wait_for_job();
|
|
27515
27874
|
init_agent_purpose_title();
|
|
27516
27875
|
init_create();
|
|
@@ -27538,6 +27897,7 @@ var init_orchestrator = __esm({
|
|
|
27538
27897
|
init_read_worktree_tail();
|
|
27539
27898
|
init_discover();
|
|
27540
27899
|
init_expand();
|
|
27900
|
+
init_enqueue_thread_send();
|
|
27541
27901
|
init_consume_attachments();
|
|
27542
27902
|
init_stage_files();
|
|
27543
27903
|
init_context_compact();
|
|
@@ -27555,6 +27915,7 @@ var init_orchestrator = __esm({
|
|
|
27555
27915
|
init_caffeinate_hold();
|
|
27556
27916
|
init_schedule_runner();
|
|
27557
27917
|
init_coordinator_prompt();
|
|
27918
|
+
init_enqueue_thread_send();
|
|
27558
27919
|
LIVE_TURN_SPAWN_GRACE_MS = 15e3;
|
|
27559
27920
|
RUN_SCRIPT_DESKTOP_ADOPT_MS = 2e4;
|
|
27560
27921
|
STALE_AGENT_PID_WAIT_MS = 2500;
|
|
@@ -27566,6 +27927,13 @@ var init_orchestrator = __esm({
|
|
|
27566
27927
|
draining = /* @__PURE__ */ new Set();
|
|
27567
27928
|
/** Threads past setStatus(running) but not yet in activeTurns (spawn in flight). */
|
|
27568
27929
|
startingTurns = /* @__PURE__ */ new Set();
|
|
27930
|
+
/**
|
|
27931
|
+
* Prompt for the turn that has not been answered yet. Steer follow-ups before
|
|
27932
|
+
* any agent output are joined onto this text instead of starting a second bubble.
|
|
27933
|
+
*/
|
|
27934
|
+
openSteerPrompt = /* @__PURE__ */ new Map();
|
|
27935
|
+
/** Next runTurn should keep the user bubble already rewritten to this prompt. */
|
|
27936
|
+
reusedUserPrompt = /* @__PURE__ */ new Set();
|
|
27569
27937
|
/** Last sync thread-file read for false-stop heal (throttled per thread). */
|
|
27570
27938
|
lastReconcileHealAt = /* @__PURE__ */ new Map();
|
|
27571
27939
|
/** Per-repo timestamp of the last `reconcile(repo, { light: true })`. */
|
|
@@ -28176,54 +28544,29 @@ var init_orchestrator = __esm({
|
|
|
28176
28544
|
return thread;
|
|
28177
28545
|
}
|
|
28178
28546
|
async send(threadRef, prompt, opts) {
|
|
28179
|
-
const
|
|
28180
|
-
|
|
28181
|
-
|
|
28182
|
-
|
|
28183
|
-
|
|
28184
|
-
|
|
28185
|
-
|
|
28186
|
-
|
|
28187
|
-
|
|
28188
|
-
|
|
28189
|
-
|
|
28190
|
-
|
|
28191
|
-
|
|
28192
|
-
|
|
28193
|
-
|
|
28194
|
-
|
|
28195
|
-
|
|
28196
|
-
|
|
28197
|
-
|
|
28198
|
-
|
|
28199
|
-
this.
|
|
28200
|
-
this.jobContinueNudged.delete(thread.id);
|
|
28201
|
-
this.haltDrain.delete(thread.id);
|
|
28202
|
-
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
28203
|
-
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
28204
|
-
const patch = queued;
|
|
28205
|
-
if (explicit === void 0 && consumed.consumed.length > 0) {
|
|
28206
|
-
patch.attachments = consumed.attachments;
|
|
28207
|
-
}
|
|
28208
|
-
if (!inFlight) patch.status = "queued";
|
|
28209
|
-
const pid = current.agentPid;
|
|
28210
|
-
if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
|
|
28211
|
-
patch.agentPid = null;
|
|
28212
|
-
}
|
|
28213
|
-
updateThread(thread.id, patch);
|
|
28214
|
-
this.emit({ type: "queue_changed", threadId: thread.id, queue: queued.queue });
|
|
28215
|
-
if (!inFlight) {
|
|
28216
|
-
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
28217
|
-
}
|
|
28218
|
-
if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
|
|
28219
|
-
this.armDrain(thread.id);
|
|
28220
|
-
}
|
|
28221
|
-
return this.requireThread(thread.id);
|
|
28222
|
-
});
|
|
28223
|
-
if (shouldSteer && sent.queue.length > 0) {
|
|
28224
|
-
return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
|
|
28547
|
+
const sent = await enqueueThreadSend(
|
|
28548
|
+
{
|
|
28549
|
+
activeTurns: this.activeTurns,
|
|
28550
|
+
startingTurns: this.startingTurns,
|
|
28551
|
+
openSteerPrompt: this.openSteerPrompt,
|
|
28552
|
+
reusedUserPrompt: this.reusedUserPrompt,
|
|
28553
|
+
crashContinued: this.crashContinued,
|
|
28554
|
+
jobContinueCount: this.jobContinueCount,
|
|
28555
|
+
jobContinueNudged: this.jobContinueNudged,
|
|
28556
|
+
haltDrain: this.haltDrain,
|
|
28557
|
+
emit: (event) => this.emit(event),
|
|
28558
|
+
armDrain: (id) => this.armDrain(id),
|
|
28559
|
+
requireThread: (ref) => this.requireThread(ref),
|
|
28560
|
+
pidAlive: (pid) => isPidAlive(pid)
|
|
28561
|
+
},
|
|
28562
|
+
threadRef,
|
|
28563
|
+
prompt,
|
|
28564
|
+
opts
|
|
28565
|
+
);
|
|
28566
|
+
if (sent.shouldSteer && sent.thread.queue.length > 0) {
|
|
28567
|
+
return this.sendQueuedMessageNow(sent.thread.id, sent.thread.queue.length - 1);
|
|
28225
28568
|
}
|
|
28226
|
-
return sent;
|
|
28569
|
+
return sent.thread;
|
|
28227
28570
|
}
|
|
28228
28571
|
async fanOut(threadRefs, prompt, opts) {
|
|
28229
28572
|
const results = [];
|
|
@@ -28364,6 +28707,7 @@ var init_orchestrator = __esm({
|
|
|
28364
28707
|
} finally {
|
|
28365
28708
|
this.draining.delete(threadId);
|
|
28366
28709
|
}
|
|
28710
|
+
await archiveEphemeralAutomationIfReady(threadId, (id) => this.archive(id));
|
|
28367
28711
|
}
|
|
28368
28712
|
async runTurn(threadId, prompt) {
|
|
28369
28713
|
const existing = readThread(threadId);
|
|
@@ -28380,6 +28724,10 @@ var init_orchestrator = __esm({
|
|
|
28380
28724
|
this.emit({ type: "status_changed", threadId, status: "running" });
|
|
28381
28725
|
this.emit({ type: "turn_started", threadId, prompt });
|
|
28382
28726
|
try {
|
|
28727
|
+
this.openSteerPrompt.set(threadId, {
|
|
28728
|
+
text: typeof prompt === "string" ? prompt : "",
|
|
28729
|
+
spawned: false
|
|
28730
|
+
});
|
|
28383
28731
|
try {
|
|
28384
28732
|
const baseline = await captureTurnBaseline(thread.worktreePath);
|
|
28385
28733
|
if (baseline) this.turnBaselines.set(threadId, baseline);
|
|
@@ -28405,18 +28753,21 @@ var init_orchestrator = __esm({
|
|
|
28405
28753
|
this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
|
|
28406
28754
|
thread = this.requireThread(threadId);
|
|
28407
28755
|
}
|
|
28408
|
-
const promptText = typeof prompt === "string" ? prompt : "";
|
|
28756
|
+
const promptText = this.openSteerPrompt.get(threadId)?.text ?? (typeof prompt === "string" ? prompt : "");
|
|
28409
28757
|
const autoContinue = isJobContinuePrompt(promptText) || promptText.startsWith("The previous agent process ended before it finished.");
|
|
28410
28758
|
const parked = takePendingTurnAttachments(thread);
|
|
28411
28759
|
const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
|
|
28412
28760
|
if (!autoContinue) clearAgentBlock(threadId);
|
|
28413
|
-
|
|
28414
|
-
|
|
28415
|
-
|
|
28416
|
-
|
|
28417
|
-
|
|
28418
|
-
|
|
28419
|
-
|
|
28761
|
+
const lastShown = this.requireThread(threadId).messages.at(-1);
|
|
28762
|
+
if (!reuseJoinedUserBubble(this.reusedUserPrompt, threadId, lastShown, promptText)) {
|
|
28763
|
+
appendMessage(threadId, {
|
|
28764
|
+
role: "user",
|
|
28765
|
+
text: promptText,
|
|
28766
|
+
...sentAttachments ? { attachments: sentAttachments } : {},
|
|
28767
|
+
...autoContinue ? { origin: "continue" } : {},
|
|
28768
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
28769
|
+
});
|
|
28770
|
+
}
|
|
28420
28771
|
if (!autoContinue) {
|
|
28421
28772
|
const live = this.requireThread(threadId);
|
|
28422
28773
|
const stamp = agentPurposeStamp({
|
|
@@ -28615,11 +28966,22 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
28615
28966
|
].filter(Boolean).join("\n\n---\n\n");
|
|
28616
28967
|
const stderrTail = [];
|
|
28617
28968
|
traceTurn("runTurn.beforeSpawn", { threadId, agent: fresh.agent });
|
|
28969
|
+
const steerDraft = this.openSteerPrompt.get(threadId);
|
|
28970
|
+
if (steerDraft) steerDraft.spawned = true;
|
|
28971
|
+
const promptForAgent = promptForJoinedSteer({
|
|
28972
|
+
threadId,
|
|
28973
|
+
promptText,
|
|
28974
|
+
latestPrompt: steerDraft?.text ?? promptText,
|
|
28975
|
+
agentPrompt,
|
|
28976
|
+
expandedPrompt,
|
|
28977
|
+
worktreePath: fresh.worktreePath,
|
|
28978
|
+
attachments: autoContinue ? [] : sentAttachments ?? []
|
|
28979
|
+
});
|
|
28618
28980
|
const handle = await spawnAgentTurn(
|
|
28619
28981
|
fresh,
|
|
28620
28982
|
{
|
|
28621
28983
|
cachedPrefix,
|
|
28622
|
-
prompt:
|
|
28984
|
+
prompt: promptForAgent,
|
|
28623
28985
|
systemPrompt: turnReminders,
|
|
28624
28986
|
isolateCodexPlugins: fresh.isolateCodexPlugins === true
|
|
28625
28987
|
},
|
|
@@ -28747,7 +29109,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
28747
29109
|
retryThread,
|
|
28748
29110
|
{
|
|
28749
29111
|
cachedPrefix: retryPrefix,
|
|
28750
|
-
prompt:
|
|
29112
|
+
prompt: promptForAgent,
|
|
28751
29113
|
systemPrompt: turnReminders,
|
|
28752
29114
|
isolateCodexPlugins: isolateCodexPluginRetry || retryThread.isolateCodexPlugins === true
|
|
28753
29115
|
},
|
|
@@ -28907,6 +29269,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
28907
29269
|
} finally {
|
|
28908
29270
|
this.startingTurns.delete(threadId);
|
|
28909
29271
|
this.activeTurns.delete(threadId);
|
|
29272
|
+
this.openSteerPrompt.delete(threadId);
|
|
28910
29273
|
this.processes.delete(`${threadId}:agent`);
|
|
28911
29274
|
this.stoppedTurns.delete(threadId);
|
|
28912
29275
|
this.runningCount = Math.max(0, this.runningCount - 1);
|
|
@@ -30178,6 +30541,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
30178
30541
|
if (thread.status !== "archived") {
|
|
30179
30542
|
throw new Error("Thread is not archived");
|
|
30180
30543
|
}
|
|
30544
|
+
clearEphemeralAutomation(thread.id);
|
|
30181
30545
|
if (isGlobalThread(thread)) {
|
|
30182
30546
|
const { globalAgentCwd: globalAgentCwd2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
30183
30547
|
updateThread(thread.id, { worktreePath: globalAgentCwd2() });
|
|
@@ -33730,7 +34094,7 @@ function parseWhen(args) {
|
|
|
33730
34094
|
function registerScheduleTools(server) {
|
|
33731
34095
|
server.tool(
|
|
33732
34096
|
"list_schedules",
|
|
33733
|
-
"List local Sideboard
|
|
34097
|
+
"List local Sideboard automations that trigger a chat when due. Jobs fire only while Sideboard.app is running on this Mac (sleep skips until wake). Shown in the sidebar after Board.",
|
|
33734
34098
|
{},
|
|
33735
34099
|
async () => {
|
|
33736
34100
|
try {
|
|
@@ -33742,9 +34106,9 @@ function registerScheduleTools(server) {
|
|
|
33742
34106
|
);
|
|
33743
34107
|
server.tool(
|
|
33744
34108
|
"create_schedule",
|
|
33745
|
-
"Create a local
|
|
34109
|
+
"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. If that chat is missing or archived when the job fires, Sideboard starts a new Global chat (recurring jobs then continue that chat). Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without chatId open a new Global chat each run and archive it when that run finishes. History keeps the latest run 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.",
|
|
33746
34110
|
{
|
|
33747
|
-
prompt: import_zod10.z.string().describe("User message / goal queued when the
|
|
34111
|
+
prompt: import_zod10.z.string().describe("User message / goal queued when the automation fires"),
|
|
33748
34112
|
name: import_zod10.z.string().optional(),
|
|
33749
34113
|
at: import_zod10.z.string().optional().describe("ISO datetime for a one-shot"),
|
|
33750
34114
|
every: import_zod10.z.string().optional().describe("Interval such as 15m, 1h, 6h, 1d"),
|
|
@@ -33780,7 +34144,7 @@ function registerScheduleTools(server) {
|
|
|
33780
34144
|
});
|
|
33781
34145
|
return text6({
|
|
33782
34146
|
schedule,
|
|
33783
|
-
hint: scheduleNeedsCaffeinate(schedule) ? "Fires while Sideboard.app is running. Recurring jobs without chatId create a new orchestration chat each run. Caffeinate while
|
|
34147
|
+
hint: scheduleNeedsCaffeinate(schedule) ? "Fires while Sideboard.app is running. Recurring jobs without chatId create a new orchestration chat each run and archive it when that run finishes (History keeps the latest). Caffeinate while automations are enabled is now on so the Mac can stay awake until this job is due." : "Fires while Sideboard.app is running. Recurring jobs without chatId create a new orchestration chat each run and archive it when that run finishes (History keeps the latest)."
|
|
33784
34148
|
});
|
|
33785
34149
|
} catch (err) {
|
|
33786
34150
|
return fail4(err);
|
|
@@ -33789,7 +34153,7 @@ function registerScheduleTools(server) {
|
|
|
33789
34153
|
);
|
|
33790
34154
|
server.tool(
|
|
33791
34155
|
"update_schedule",
|
|
33792
|
-
"Update a local
|
|
34156
|
+
"Update a local automation (prompt, cadence, target chat, enabled). Pass id from list_schedules.",
|
|
33793
34157
|
{
|
|
33794
34158
|
id: import_zod10.z.string(),
|
|
33795
34159
|
prompt: import_zod10.z.string().optional(),
|
|
@@ -33844,7 +34208,7 @@ function registerScheduleTools(server) {
|
|
|
33844
34208
|
);
|
|
33845
34209
|
server.tool(
|
|
33846
34210
|
"delete_schedule",
|
|
33847
|
-
"Delete a local
|
|
34211
|
+
"Delete a local automation. Pass id from list_schedules.",
|
|
33848
34212
|
{ id: import_zod10.z.string() },
|
|
33849
34213
|
async ({ id }) => {
|
|
33850
34214
|
try {
|
|
@@ -33857,12 +34221,12 @@ function registerScheduleTools(server) {
|
|
|
33857
34221
|
);
|
|
33858
34222
|
server.tool(
|
|
33859
34223
|
"run_schedule",
|
|
33860
|
-
"Fire
|
|
34224
|
+
"Fire an automation now (does not wait for nextRunAt). Queues the prompt on the target chat or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.",
|
|
33861
34225
|
{ id: import_zod10.z.string() },
|
|
33862
34226
|
async ({ id }) => {
|
|
33863
34227
|
try {
|
|
33864
34228
|
if (!getSchedule(id)) {
|
|
33865
|
-
return fail4(new Error(`
|
|
34229
|
+
return fail4(new Error(`Automation not found: ${id}`));
|
|
33866
34230
|
}
|
|
33867
34231
|
const schedule = await fireSchedule(id);
|
|
33868
34232
|
return text6({ schedule });
|