@sideboard-ai/core 0.1.283 → 0.1.285
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-WLDBJJUI.js → abletime-4CH2IOX5.js} +4 -4
- package/dist/{abletime-X64E3GUJ.js → abletime-I4RODUKT.js} +4 -4
- package/dist/{abletime-oauth-AXR676W5.js → abletime-oauth-7OZZ3ABX.js} +3 -3
- package/dist/{abletime-oauth-UWOCEICP.js → abletime-oauth-C2HN2Q6F.js} +3 -3
- package/dist/{abletime-rest-S4XWEXV2.js → abletime-rest-E4LBRFLM.js} +3 -3
- package/dist/{abletime-rest-LPUDJUEP.js → abletime-rest-WFI2HWBU.js} +3 -3
- package/dist/agents/cursor-runner.cjs +54 -14
- package/dist/agents/cursor-runner.js +51 -14
- package/dist/{agents-XA2E64AW.js → agents-FKMYAKFD.js} +5 -5
- package/dist/{agents-2IE4HKHA.js → agents-ITNCZ6CA.js} +7 -7
- package/dist/chunk-2GPQZZLY.js +59 -0
- package/dist/{chunk-BYZ7F2BQ.js → chunk-2K723QZH.js} +12 -10
- package/dist/{chunk-ROPGQRPU.js → chunk-33KDPEK4.js} +1 -1
- package/dist/{chunk-W7HIK2A6.js → chunk-5QOLFOAX.js} +19 -3
- package/dist/{chunk-I6HSGKMZ.js → chunk-5T4YWFLD.js} +2 -2
- package/dist/{chunk-U7HAVAGJ.js → chunk-6CVVNAIU.js} +2 -2
- package/dist/{chunk-TQRSVE7D.js → chunk-7IAMHN2N.js} +1 -1
- package/dist/{chunk-DQZPF6WL.js → chunk-BMUVNTT4.js} +3 -3
- package/dist/{chunk-2KNO2GJQ.js → chunk-C6NVTLZK.js} +16 -14
- package/dist/{chunk-VA55JG2I.js → chunk-DEJALWKM.js} +5 -5
- package/dist/{chunk-XTPQEZZA.js → chunk-IJMUYHPT.js} +3 -3
- package/dist/chunk-JAT3JFOS.js +61 -0
- package/dist/{chunk-EIEAR62M.js → chunk-LMWPVC5L.js} +2 -2
- package/dist/{chunk-DGPROCE5.js → chunk-LS4FFCPL.js} +3 -3
- package/dist/{chunk-P2BSMNHB.js → chunk-PXMLMBMI.js} +1 -1
- package/dist/{chunk-UZUXWBXK.js → chunk-S2OOM7AU.js} +1 -1
- package/dist/{chunk-BS3QLVPL.js → chunk-TMM4FEZ5.js} +3 -3
- package/dist/{chunk-ADXVTKLC.js → chunk-TXHZJESB.js} +4 -4
- package/dist/{chunk-K2S33ZCB.js → chunk-U6QDXT4K.js} +20 -4
- package/dist/{chunk-GWFVCCJZ.js → chunk-VGNLMGBK.js} +6 -6
- package/dist/{chunk-IFURHRAR.js → chunk-VOIWX5HA.js} +1 -1
- package/dist/{chunk-PY4UCMRI.js → chunk-VQEARG5H.js} +5 -5
- package/dist/{chunk-BDAUPNHL.js → chunk-XSDCLM3F.js} +1 -1
- package/dist/{chunk-OCUIZD4Y.js → chunk-XSPOJFTV.js} +6 -6
- package/dist/{conductor-U776JSXQ.js → conductor-GBX6LSP2.js} +3 -3
- package/dist/{conductor-CNSCOC54.js → conductor-MU3TYVCD.js} +2 -2
- package/dist/{connected-teams-JIUOSZ6C.js → connected-teams-AB7ZHJVO.js} +3 -3
- package/dist/{connected-teams-RU6VATCM.js → connected-teams-BJ6PMIST.js} +3 -3
- package/dist/index.cjs +241 -120
- package/dist/index.d.cts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +176 -101
- package/dist/mcp/run-stdio.cjs +68 -25
- package/dist/mcp/run-stdio.js +10 -10
- package/dist/{oauth-S3M7B475.js → oauth-DP4ZV2M2.js} +2 -2
- package/dist/{oauth-K6CWZEQO.js → oauth-WCUZ6Z5G.js} +2 -2
- package/dist/{orchestrator-FPGVKEID.js → orchestrator-F7KXYDQW.js} +9 -9
- package/dist/{orchestrator-HWJHK5NL.js → orchestrator-VUIRO6NC.js} +7 -7
- package/package.json +1 -1
- package/dist/chunk-N7WZ6NIN.js +0 -41
- package/dist/chunk-VKQGAWHY.js +0 -40
package/dist/index.cjs
CHANGED
|
@@ -4812,6 +4812,30 @@ var init_thread_store = __esm({
|
|
|
4812
4812
|
}
|
|
4813
4813
|
});
|
|
4814
4814
|
|
|
4815
|
+
// src/agents/cursor-stream-cutoff.ts
|
|
4816
|
+
function looksLikeCursorStreamCutOff(text7) {
|
|
4817
|
+
return CURSOR_STREAM_CUTOFF.test(text7.trim());
|
|
4818
|
+
}
|
|
4819
|
+
function cursorStreamCutOffContinueLimit(detail) {
|
|
4820
|
+
if (looksLikeCursorStreamCutOff(detail) || /connection stalled/i.test(detail)) {
|
|
4821
|
+
return CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
|
|
4822
|
+
}
|
|
4823
|
+
return null;
|
|
4824
|
+
}
|
|
4825
|
+
function nextCrashContinueCount(detail, used) {
|
|
4826
|
+
const limit = cursorStreamCutOffContinueLimit(detail) ?? 1;
|
|
4827
|
+
if (used >= limit) return null;
|
|
4828
|
+
return used + 1;
|
|
4829
|
+
}
|
|
4830
|
+
var CURSOR_STREAM_CUTOFF, CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
|
|
4831
|
+
var init_cursor_stream_cutoff = __esm({
|
|
4832
|
+
"src/agents/cursor-stream-cutoff.ts"() {
|
|
4833
|
+
"use strict";
|
|
4834
|
+
CURSOR_STREAM_CUTOFF = /nghttp2|premature close|\[unavailable\]\s+error\b|http\/2 stream closed|\bcancel \(0x8\)|error code cancel\b/i;
|
|
4835
|
+
CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT = 3;
|
|
4836
|
+
}
|
|
4837
|
+
});
|
|
4838
|
+
|
|
4815
4839
|
// src/agents/error-detail.ts
|
|
4816
4840
|
function formatUnknownDetail(err) {
|
|
4817
4841
|
if (err == null) return "";
|
|
@@ -5002,9 +5026,6 @@ function looksLikeInvalidAgentSession(text7) {
|
|
|
5002
5026
|
if (!lower) return false;
|
|
5003
5027
|
return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || /\brun\b.{0,80}\bnot found for agent\b/.test(lower);
|
|
5004
5028
|
}
|
|
5005
|
-
function looksLikeCursorStreamCutOff(text7) {
|
|
5006
|
-
return /nghttp2|premature close|\[unavailable\]\s+error\b/i.test(text7.trim());
|
|
5007
|
-
}
|
|
5008
5029
|
function looksLikeBrightsyEmptyCompletion(text7) {
|
|
5009
5030
|
const core = text7.trim().replace(/^exit\s*\d+:\s*/i, "").replace(/^error:\s*/i, "").trim();
|
|
5010
5031
|
return /^i did not receive a valid model response\. please try again\.$/i.test(core);
|
|
@@ -5178,6 +5199,8 @@ var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, HOMEBREW_LIBUV_SUMMARY, BUNDLE
|
|
|
5178
5199
|
var init_error_detail = __esm({
|
|
5179
5200
|
"src/agents/error-detail.ts"() {
|
|
5180
5201
|
"use strict";
|
|
5202
|
+
init_cursor_stream_cutoff();
|
|
5203
|
+
init_cursor_stream_cutoff();
|
|
5181
5204
|
NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
|
|
5182
5205
|
NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
|
|
5183
5206
|
HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 24 LTS (`brew install node@24`) and retry.";
|
|
@@ -11976,30 +11999,49 @@ var init_config = __esm({
|
|
|
11976
11999
|
function setHttpFetchImpl(fetchImpl) {
|
|
11977
12000
|
injected = fetchImpl;
|
|
11978
12001
|
}
|
|
11979
|
-
function
|
|
11980
|
-
|
|
11981
|
-
return TLS_ISSUER_RE.test(text7) ? TLS_ISSUER_HINT : "";
|
|
12002
|
+
function isTlsIssuerFailure(code, message) {
|
|
12003
|
+
return TLS_ISSUER_RE.test(`${code ?? ""} ${message}`);
|
|
11982
12004
|
}
|
|
11983
|
-
function
|
|
11984
|
-
if (
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
|
|
12005
|
+
function describeCause(cause, depth = 0) {
|
|
12006
|
+
if (depth > 5 || cause == null) return null;
|
|
12007
|
+
if (cause instanceof AggregateError) {
|
|
12008
|
+
for (const item of cause.errors) {
|
|
12009
|
+
const found = describeCause(item, depth + 1);
|
|
12010
|
+
if (found && (found.code || found.message)) return found;
|
|
12011
|
+
}
|
|
12012
|
+
return cause.message ? { message: cause.message } : null;
|
|
12013
|
+
}
|
|
11988
12014
|
if (cause instanceof Error) {
|
|
11989
12015
|
const code = typeof cause.code === "string" ? cause.code : void 0;
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
}
|
|
11996
|
-
|
|
12016
|
+
const nested = describeCause(cause.cause, depth + 1);
|
|
12017
|
+
if ((!cause.message || cause.message === "fetch failed") && nested) return nested;
|
|
12018
|
+
if (cause.message || code) return { code, message: cause.message };
|
|
12019
|
+
return nested;
|
|
12020
|
+
}
|
|
12021
|
+
return { message: String(cause) };
|
|
12022
|
+
}
|
|
12023
|
+
function causeSuffix(detail) {
|
|
12024
|
+
if (!detail) return "";
|
|
12025
|
+
if (detail.code && detail.message) return ` [${detail.code}: ${detail.message}]`;
|
|
12026
|
+
if (detail.code) return ` [${detail.code}]`;
|
|
12027
|
+
if (detail.message) return ` [${detail.message}]`;
|
|
12028
|
+
return "";
|
|
12029
|
+
}
|
|
12030
|
+
function formatFetchError(err, url, opts) {
|
|
12031
|
+
if (!(err instanceof Error)) return `${String(err)} (${url})`;
|
|
12032
|
+
const detail = describeCause(err.cause);
|
|
12033
|
+
const hintSource = `${err.message} ${detail?.code ?? ""} ${detail?.message ?? ""}`;
|
|
12034
|
+
const tls2 = isTlsIssuerFailure(detail?.code, hintSource);
|
|
12035
|
+
const hint = tls2 ? opts?.tlsHint ?? TLS_ISSUER_HINT : "";
|
|
12036
|
+
return `${err.message}${causeSuffix(detail)} (${url})${hint}`;
|
|
12037
|
+
}
|
|
12038
|
+
function currentHttpFetch() {
|
|
12039
|
+
return injected ?? globalThis.fetch.bind(globalThis);
|
|
11997
12040
|
}
|
|
11998
12041
|
async function httpFetch(input, init) {
|
|
11999
12042
|
const url = typeof input === "string" ? input : input.href;
|
|
12000
|
-
const fn = injected ?? globalThis.fetch.bind(globalThis);
|
|
12001
12043
|
try {
|
|
12002
|
-
return await
|
|
12044
|
+
return await currentHttpFetch()(url, init);
|
|
12003
12045
|
} catch (err) {
|
|
12004
12046
|
throw new Error(formatFetchError(err, url));
|
|
12005
12047
|
}
|
|
@@ -14696,10 +14738,10 @@ function eventsFromClaudeSystem(obj) {
|
|
|
14696
14738
|
if (subtype === "api_retry") {
|
|
14697
14739
|
const attempt = obj.attempt;
|
|
14698
14740
|
const max = obj.max_retries;
|
|
14699
|
-
const
|
|
14741
|
+
const delay3 = obj.retry_delay_ms;
|
|
14700
14742
|
return {
|
|
14701
14743
|
type: "thinking",
|
|
14702
|
-
data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof
|
|
14744
|
+
data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay3 === "number" ? ` (wait ${delay3}ms)` : ""}`
|
|
14703
14745
|
};
|
|
14704
14746
|
}
|
|
14705
14747
|
if (subtype === "status") {
|
|
@@ -27436,10 +27478,10 @@ var init_orchestrator = __esm({
|
|
|
27436
27478
|
/** Timers for orchestration session-quota auto-resume. */
|
|
27437
27479
|
quotaResumeTimers = /* @__PURE__ */ new Map();
|
|
27438
27480
|
/**
|
|
27439
|
-
*
|
|
27440
|
-
*
|
|
27481
|
+
* Crash-continue count per thread. Cleared on a successful finish or a user
|
|
27482
|
+
* send. Stream cutoffs may resume more than once; other crashes once.
|
|
27441
27483
|
*/
|
|
27442
|
-
crashContinued = /* @__PURE__ */ new
|
|
27484
|
+
crashContinued = /* @__PURE__ */ new Map();
|
|
27443
27485
|
/** Auto-continues after a worktree turn ended while a detached job still runs. */
|
|
27444
27486
|
jobContinueCount = /* @__PURE__ */ new Map();
|
|
27445
27487
|
jobContinueNudged = /* @__PURE__ */ new Set();
|
|
@@ -27721,8 +27763,8 @@ var init_orchestrator = __esm({
|
|
|
27721
27763
|
scheduleQuotaResume(threadId, resumeAt) {
|
|
27722
27764
|
this.clearQuotaResumeTimer(threadId);
|
|
27723
27765
|
updateThread(threadId, { quotaResumeAt: resumeAt.toISOString() });
|
|
27724
|
-
const
|
|
27725
|
-
const capped = Math.min(
|
|
27766
|
+
const delay3 = Math.max(5e3, resumeAt.getTime() - Date.now());
|
|
27767
|
+
const capped = Math.min(delay3, 2147483647);
|
|
27726
27768
|
const timer = setTimeout(() => {
|
|
27727
27769
|
this.quotaResumeTimers.delete(threadId);
|
|
27728
27770
|
void this.resumeAfterQuotaWait(threadId);
|
|
@@ -27878,7 +27920,6 @@ var init_orchestrator = __esm({
|
|
|
27878
27920
|
* next prompt so the same agent can continue instead of sitting on lastError.
|
|
27879
27921
|
*/
|
|
27880
27922
|
maybeEnqueueCrashContinue(threadId, opts) {
|
|
27881
|
-
if (this.crashContinued.has(threadId)) return;
|
|
27882
27923
|
if (this.haltDrain.has(threadId)) return;
|
|
27883
27924
|
if (!shouldFeedErrorBackToAgent({
|
|
27884
27925
|
detail: opts.detail,
|
|
@@ -27887,9 +27928,11 @@ var init_orchestrator = __esm({
|
|
|
27887
27928
|
})) {
|
|
27888
27929
|
return;
|
|
27889
27930
|
}
|
|
27931
|
+
const resumeCount = nextCrashContinueCount(opts.detail, this.crashContinued.get(threadId) ?? 0);
|
|
27932
|
+
if (resumeCount == null) return;
|
|
27890
27933
|
const thread = readThread(threadId);
|
|
27891
27934
|
if (!thread || thread.status === "archived") return;
|
|
27892
|
-
this.crashContinued.
|
|
27935
|
+
this.crashContinued.set(threadId, resumeCount);
|
|
27893
27936
|
const prompt = formatAgentErrorContinuePrompt(opts.detail);
|
|
27894
27937
|
const next = prependQueuedItem(thread.queue, thread.queueAttachments, prompt);
|
|
27895
27938
|
updateThread(threadId, next);
|
|
@@ -30162,14 +30205,14 @@ function armOne(schedule) {
|
|
|
30162
30205
|
if (!schedule.enabled) return;
|
|
30163
30206
|
const at = new Date(schedule.nextRunAt);
|
|
30164
30207
|
if (Number.isNaN(at.getTime())) return;
|
|
30165
|
-
const
|
|
30166
|
-
if (
|
|
30208
|
+
const delay3 = Math.max(0, at.getTime() - Date.now());
|
|
30209
|
+
if (delay3 <= 250) {
|
|
30167
30210
|
void fireSchedule(schedule.id).then(() => {
|
|
30168
30211
|
if (isThisProcessDesktopHost()) armSchedules();
|
|
30169
30212
|
});
|
|
30170
30213
|
return;
|
|
30171
30214
|
}
|
|
30172
|
-
const capped = Math.min(
|
|
30215
|
+
const capped = Math.min(delay3, SET_TIMEOUT_MAX);
|
|
30173
30216
|
const timer = setTimeout(() => {
|
|
30174
30217
|
timers.delete(schedule.id);
|
|
30175
30218
|
const live = getSchedule(schedule.id);
|
|
@@ -39714,10 +39757,7 @@ var import_ws5 = require("ws");
|
|
|
39714
39757
|
init_orchestrator_capable();
|
|
39715
39758
|
init_stage_files();
|
|
39716
39759
|
init_orchestrator();
|
|
39717
|
-
init_ask_user();
|
|
39718
39760
|
init_app_settings();
|
|
39719
|
-
init_global_workspace();
|
|
39720
|
-
init_thread_store();
|
|
39721
39761
|
init_implied_first_prompt();
|
|
39722
39762
|
|
|
39723
39763
|
// src/remote/phone-media.ts
|
|
@@ -40696,7 +40736,13 @@ function deliverPhoneTurn(opts, chatId) {
|
|
|
40696
40736
|
});
|
|
40697
40737
|
}
|
|
40698
40738
|
|
|
40699
|
-
// src/remote/
|
|
40739
|
+
// src/remote/phone-turn.ts
|
|
40740
|
+
init_orchestrator_capable();
|
|
40741
|
+
init_orchestrator();
|
|
40742
|
+
init_ask_user();
|
|
40743
|
+
init_app_settings();
|
|
40744
|
+
init_global_workspace();
|
|
40745
|
+
init_thread_store();
|
|
40700
40746
|
function formatRemotePrompt(text7) {
|
|
40701
40747
|
return `Phone
|
|
40702
40748
|
|
|
@@ -40705,6 +40751,29 @@ ${text7.trim()}`;
|
|
|
40705
40751
|
function isRemoteStopCommand(text7) {
|
|
40706
40752
|
return text7.trim().toLowerCase() === "stop";
|
|
40707
40753
|
}
|
|
40754
|
+
function phoneFollowUpQueues(status) {
|
|
40755
|
+
return followUpBehavior() === "queue" && (status === "running" || status === "queued");
|
|
40756
|
+
}
|
|
40757
|
+
var PHONE_TURN_MS = 14 * 60 * 1e3;
|
|
40758
|
+
function delay2(ms) {
|
|
40759
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
40760
|
+
}
|
|
40761
|
+
async function waitForPhoneTurn(threadId, stillCurrent) {
|
|
40762
|
+
const deadline = Date.now() + PHONE_TURN_MS;
|
|
40763
|
+
while (stillCurrent() && Date.now() < deadline) {
|
|
40764
|
+
const thread2 = readPhoneThread(threadId) ?? readThread(threadId);
|
|
40765
|
+
if (!thread2) return;
|
|
40766
|
+
if (thread2.status === "stopped" && thread2.queue.length > 0) {
|
|
40767
|
+
await delay2(40);
|
|
40768
|
+
continue;
|
|
40769
|
+
}
|
|
40770
|
+
break;
|
|
40771
|
+
}
|
|
40772
|
+
if (!stillCurrent()) return;
|
|
40773
|
+
const thread = readPhoneThread(threadId) ?? readThread(threadId);
|
|
40774
|
+
if (!thread || thread.status !== "running" && thread.status !== "queued") return;
|
|
40775
|
+
await getOrchestrator().waitForTurn(threadId, Math.max(1, deadline - Date.now()));
|
|
40776
|
+
}
|
|
40708
40777
|
var handleChain2 = Promise.resolve();
|
|
40709
40778
|
var inboundGeneration = 0;
|
|
40710
40779
|
function enqueue(fn) {
|
|
@@ -40728,6 +40797,77 @@ function interruptRemoteCoordinator(deviceId, log = () => void 0) {
|
|
|
40728
40797
|
return false;
|
|
40729
40798
|
}
|
|
40730
40799
|
}
|
|
40800
|
+
function runCoordinatorPrompt(opts, body, generation) {
|
|
40801
|
+
const current = () => generation === inboundGeneration;
|
|
40802
|
+
return (async () => {
|
|
40803
|
+
if (!current()) return;
|
|
40804
|
+
const agent = coerceOrchestratorAgent(opts.agent ?? resolveOrchestratorDefaults().agent);
|
|
40805
|
+
if (!body) return;
|
|
40806
|
+
if (isRemoteStopCommand(body)) {
|
|
40807
|
+
if (!current()) return;
|
|
40808
|
+
opts.onOutbound({ type: "assistant", text: REMOTE_STOPPED_REPLY });
|
|
40809
|
+
return;
|
|
40810
|
+
}
|
|
40811
|
+
let thread = ensureRemoteCoordinator(opts.deviceId, agent);
|
|
40812
|
+
thread = readThread(thread.id) ?? thread;
|
|
40813
|
+
const followUp = followUpBehavior();
|
|
40814
|
+
const orch = getOrchestrator();
|
|
40815
|
+
try {
|
|
40816
|
+
await orch.send(thread.id, formatRemotePrompt(body), { followUp });
|
|
40817
|
+
if (!current()) return;
|
|
40818
|
+
await waitForPhoneTurn(thread.id, current);
|
|
40819
|
+
} catch (err) {
|
|
40820
|
+
if (!current()) return;
|
|
40821
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40822
|
+
opts.onOutbound({ type: "assistant", text: `Sideboard failed: ${message}` });
|
|
40823
|
+
return;
|
|
40824
|
+
}
|
|
40825
|
+
if (!current()) return;
|
|
40826
|
+
thread = readThread(thread.id) ?? thread;
|
|
40827
|
+
if (thread.status === "stopped") return;
|
|
40828
|
+
const result = orch.getTurnResult(thread.id);
|
|
40829
|
+
const pending = extractPendingPlanQuestions(
|
|
40830
|
+
[...thread.messages].reverse().find((m) => m.role === "agent")?.parts
|
|
40831
|
+
);
|
|
40832
|
+
if (result.taskState === "input-required" && pending) {
|
|
40833
|
+
opts.onOutbound({
|
|
40834
|
+
type: "ask_user",
|
|
40835
|
+
text: result.text.trim(),
|
|
40836
|
+
questions: pending.questions.map((q) => ({
|
|
40837
|
+
question: q.question,
|
|
40838
|
+
options: q.options.map(
|
|
40839
|
+
(o) => o.description ? { label: o.label, description: o.description } : { label: o.label }
|
|
40840
|
+
)
|
|
40841
|
+
}))
|
|
40842
|
+
});
|
|
40843
|
+
return;
|
|
40844
|
+
}
|
|
40845
|
+
const reply = outboundReplyFromTurn(result, {
|
|
40846
|
+
inputRequired: "Sideboard is waiting for an answer.",
|
|
40847
|
+
canceled: REMOTE_STOPPED_REPLY,
|
|
40848
|
+
completedEmpty: () => "",
|
|
40849
|
+
failed: (detail) => detail ? `Sideboard failed: ${detail}` : "Sideboard failed before producing a result."
|
|
40850
|
+
});
|
|
40851
|
+
if (reply.trim()) opts.onOutbound({ type: "assistant", text: reply.trim() });
|
|
40852
|
+
})();
|
|
40853
|
+
}
|
|
40854
|
+
function beginCoordinatorPrompt(body, opts) {
|
|
40855
|
+
const live = body ? findRemoteCoordinator(opts.deviceId) : null;
|
|
40856
|
+
const fresh = live ? readThread(live.id) ?? live : null;
|
|
40857
|
+
if (body && !isRemoteStopCommand(body) && phoneFollowUpQueues(fresh?.status)) {
|
|
40858
|
+
const generation2 = inboundGeneration;
|
|
40859
|
+
enqueue(() => runCoordinatorPrompt(opts, body, generation2));
|
|
40860
|
+
return;
|
|
40861
|
+
}
|
|
40862
|
+
const generation = ++inboundGeneration;
|
|
40863
|
+
if (body && isRemoteStopCommand(body)) {
|
|
40864
|
+
interruptRemoteCoordinator(opts.deviceId, opts.onLog ?? (() => void 0));
|
|
40865
|
+
}
|
|
40866
|
+
const task = runCoordinatorPrompt(opts, body, generation);
|
|
40867
|
+
enqueue(() => task);
|
|
40868
|
+
}
|
|
40869
|
+
|
|
40870
|
+
// src/remote/listen.ts
|
|
40731
40871
|
function emitOpened(opts, opened) {
|
|
40732
40872
|
setPhoneOpenChat(opened.chat.id);
|
|
40733
40873
|
emitControl(opts, { op: "opened", ...opened });
|
|
@@ -40997,23 +41137,27 @@ function handlePhoneControl(cmd, opts) {
|
|
|
40997
41137
|
return;
|
|
40998
41138
|
}
|
|
40999
41139
|
const chatId = cmd.chatId;
|
|
41140
|
+
const existing = readPhoneThread(chatId);
|
|
41141
|
+
if (phoneFollowUpQueues(existing?.status)) {
|
|
41142
|
+
deliverPhoneTurn(opts, chatId);
|
|
41143
|
+
const generation2 = chatGeneration.get(chatId) ?? bumpChat(chatId);
|
|
41144
|
+
enqueueChat(chatId, () => runPhonePrompt(opts, cmd, chatId, generation2));
|
|
41145
|
+
return;
|
|
41146
|
+
}
|
|
41000
41147
|
const generation = bumpChat(chatId);
|
|
41001
41148
|
phoneTurnGen.set(chatId, generation);
|
|
41002
|
-
|
|
41003
|
-
enqueueChat(chatId,
|
|
41004
|
-
|
|
41149
|
+
const task = runPhonePrompt(opts, cmd, chatId, generation);
|
|
41150
|
+
enqueueChat(chatId, () => task);
|
|
41151
|
+
}
|
|
41152
|
+
function runPhonePrompt(opts, cmd, chatId, generation) {
|
|
41153
|
+
const current = () => chatGeneration.get(chatId) === generation;
|
|
41154
|
+
return (async () => {
|
|
41155
|
+
if (!current()) return;
|
|
41005
41156
|
const thread = readPhoneThread(chatId);
|
|
41006
41157
|
if (!thread) {
|
|
41007
41158
|
emitControl(opts, { op: "error", chatId, message: "That agent is not on this Mac." });
|
|
41008
41159
|
return;
|
|
41009
41160
|
}
|
|
41010
|
-
if (thread.status === "running" || thread.status === "queued") {
|
|
41011
|
-
try {
|
|
41012
|
-
getOrchestrator().stop(thread.id, { clearQueue: true });
|
|
41013
|
-
} catch {
|
|
41014
|
-
}
|
|
41015
|
-
}
|
|
41016
|
-
if (chatGeneration.get(chatId) !== generation) return;
|
|
41017
41161
|
const stopStream = watchPhoneStream(opts, chatId, thread.id, generation);
|
|
41018
41162
|
try {
|
|
41019
41163
|
try {
|
|
@@ -41021,14 +41165,19 @@ function handlePhoneControl(cmd, opts) {
|
|
|
41021
41165
|
} catch (err) {
|
|
41022
41166
|
emitControl(opts, { op: "error", chatId, message: phoneError(err) });
|
|
41023
41167
|
}
|
|
41168
|
+
if (!current()) return;
|
|
41024
41169
|
const live = readPhoneThread(thread.id) ?? thread;
|
|
41170
|
+
const followUp = followUpBehavior();
|
|
41025
41171
|
const staged = stagePhoneTurnFiles(live.worktreePath, cmd);
|
|
41026
41172
|
const text7 = cmd.text.trim() || (staged.length ? "See the attached files." : "");
|
|
41027
|
-
|
|
41028
|
-
|
|
41029
|
-
|
|
41173
|
+
await getOrchestrator().send(thread.id, formatRemotePrompt(text7), {
|
|
41174
|
+
attachments: staged,
|
|
41175
|
+
followUp
|
|
41176
|
+
});
|
|
41177
|
+
if (!current()) return;
|
|
41178
|
+
await waitForPhoneTurn(thread.id, current);
|
|
41030
41179
|
} catch (err) {
|
|
41031
|
-
if (
|
|
41180
|
+
if (!current()) return;
|
|
41032
41181
|
const message = err instanceof Error ? err.message : String(err);
|
|
41033
41182
|
emitControl(opts, { op: "error", chatId, message: `Sideboard failed: ${message}` });
|
|
41034
41183
|
return;
|
|
@@ -41036,12 +41185,11 @@ function handlePhoneControl(cmd, opts) {
|
|
|
41036
41185
|
stopStream();
|
|
41037
41186
|
finishPhoneTurn(chatId, generation);
|
|
41038
41187
|
}
|
|
41039
|
-
if (
|
|
41188
|
+
if (!current()) return;
|
|
41040
41189
|
emitChatTurn(opts, chatId, thread.id);
|
|
41041
|
-
});
|
|
41190
|
+
})();
|
|
41042
41191
|
}
|
|
41043
41192
|
function handleRemoteInbound(text7, opts) {
|
|
41044
|
-
const log = opts.onLog ?? (() => void 0);
|
|
41045
41193
|
const body = text7.trim();
|
|
41046
41194
|
const control = takePhoneControl(body);
|
|
41047
41195
|
if (control) {
|
|
@@ -41052,64 +41200,7 @@ function handleRemoteInbound(text7, opts) {
|
|
|
41052
41200
|
handlePhoneControl(control, opts);
|
|
41053
41201
|
return;
|
|
41054
41202
|
}
|
|
41055
|
-
|
|
41056
|
-
if (body) interruptRemoteCoordinator(opts.deviceId, log);
|
|
41057
|
-
enqueue(async () => {
|
|
41058
|
-
if (generation !== inboundGeneration) return;
|
|
41059
|
-
const agent = coerceOrchestratorAgent(opts.agent ?? resolveOrchestratorDefaults().agent);
|
|
41060
|
-
if (!body) return;
|
|
41061
|
-
if (isRemoteStopCommand(body)) {
|
|
41062
|
-
if (generation !== inboundGeneration) return;
|
|
41063
|
-
opts.onOutbound({ type: "assistant", text: REMOTE_STOPPED_REPLY });
|
|
41064
|
-
return;
|
|
41065
|
-
}
|
|
41066
|
-
let thread = ensureRemoteCoordinator(opts.deviceId, agent);
|
|
41067
|
-
const fresh = readThread(thread.id) ?? thread;
|
|
41068
|
-
if (fresh.status === "running" || fresh.status === "queued") {
|
|
41069
|
-
try {
|
|
41070
|
-
getOrchestrator().stop(fresh.id, { clearQueue: true });
|
|
41071
|
-
} catch {
|
|
41072
|
-
}
|
|
41073
|
-
}
|
|
41074
|
-
if (generation !== inboundGeneration) return;
|
|
41075
|
-
const orch = getOrchestrator();
|
|
41076
|
-
try {
|
|
41077
|
-
await orch.send(thread.id, formatRemotePrompt(body));
|
|
41078
|
-
await orch.waitForTurn(thread.id, 14 * 60 * 1e3);
|
|
41079
|
-
} catch (err) {
|
|
41080
|
-
if (generation !== inboundGeneration) return;
|
|
41081
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
41082
|
-
opts.onOutbound({ type: "assistant", text: `Sideboard failed: ${message}` });
|
|
41083
|
-
return;
|
|
41084
|
-
}
|
|
41085
|
-
if (generation !== inboundGeneration) return;
|
|
41086
|
-
thread = readThread(thread.id) ?? thread;
|
|
41087
|
-
if (thread.status === "stopped") return;
|
|
41088
|
-
const result = orch.getTurnResult(thread.id);
|
|
41089
|
-
const pending = extractPendingPlanQuestions(
|
|
41090
|
-
[...thread.messages].reverse().find((m) => m.role === "agent")?.parts
|
|
41091
|
-
);
|
|
41092
|
-
if (result.taskState === "input-required" && pending) {
|
|
41093
|
-
opts.onOutbound({
|
|
41094
|
-
type: "ask_user",
|
|
41095
|
-
text: result.text.trim(),
|
|
41096
|
-
questions: pending.questions.map((q) => ({
|
|
41097
|
-
question: q.question,
|
|
41098
|
-
options: q.options.map(
|
|
41099
|
-
(o) => o.description ? { label: o.label, description: o.description } : { label: o.label }
|
|
41100
|
-
)
|
|
41101
|
-
}))
|
|
41102
|
-
});
|
|
41103
|
-
return;
|
|
41104
|
-
}
|
|
41105
|
-
const reply = outboundReplyFromTurn(result, {
|
|
41106
|
-
inputRequired: "Sideboard is waiting for an answer.",
|
|
41107
|
-
canceled: REMOTE_STOPPED_REPLY,
|
|
41108
|
-
completedEmpty: () => "",
|
|
41109
|
-
failed: (detail) => detail ? `Sideboard failed: ${detail}` : "Sideboard failed before producing a result."
|
|
41110
|
-
});
|
|
41111
|
-
if (reply.trim()) opts.onOutbound({ type: "assistant", text: reply.trim() });
|
|
41112
|
-
});
|
|
41203
|
+
beginCoordinatorPrompt(body, opts);
|
|
41113
41204
|
}
|
|
41114
41205
|
|
|
41115
41206
|
// src/remote/phone-board-sync.ts
|
|
@@ -41449,6 +41540,7 @@ function runRemoteHost(opts) {
|
|
|
41449
41540
|
|
|
41450
41541
|
// src/relay/account-login.ts
|
|
41451
41542
|
var import_node_crypto28 = require("crypto");
|
|
41543
|
+
init_fetch();
|
|
41452
41544
|
|
|
41453
41545
|
// src/relay/accounts.ts
|
|
41454
41546
|
var import_node_crypto27 = require("crypto");
|
|
@@ -42049,15 +42141,43 @@ function sleep2(ms, signal) {
|
|
|
42049
42141
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
42050
42142
|
});
|
|
42051
42143
|
}
|
|
42144
|
+
var RELAY_TLS_HINT = " \u2014 the TLS certificate was rejected. A work proxy often does this when Sideboard is not allowlisted, or when the app does not trust the corporate CA.";
|
|
42145
|
+
var RELAY_NETWORK_HINT = " Sideboard could not reach the relay. On a work computer this is often a VPN, a proxy, or an allowlist that does not include Sideboard.";
|
|
42146
|
+
var RELAY_NETWORK_RE = /fetch failed|Failed to fetch|ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH|EAI_AGAIN|EPERM|UND_ERR_|ERR_CONNECTION|ERR_NETWORK|ERR_PROXY|ERR_TUNNEL|ERR_INTERNET|ERR_BLOCKED|ERR_NAME_NOT_RESOLVED|ERR_ADDRESS_UNREACHABLE|ERR_CERT|CERT_|UNABLE_TO_GET_ISSUER|SELF_SIGNED/i;
|
|
42147
|
+
function relayFetchError(err, url) {
|
|
42148
|
+
const formatted = formatFetchError(err, url, { tlsHint: RELAY_TLS_HINT });
|
|
42149
|
+
if (formatted.includes(RELAY_TLS_HINT) || !RELAY_NETWORK_RE.test(formatted)) {
|
|
42150
|
+
return new Error(formatted);
|
|
42151
|
+
}
|
|
42152
|
+
return new Error(`${formatted}${RELAY_NETWORK_HINT}`);
|
|
42153
|
+
}
|
|
42154
|
+
async function relayFetch(fetchImpl, url, init) {
|
|
42155
|
+
const fn = fetchImpl ?? currentHttpFetch();
|
|
42156
|
+
try {
|
|
42157
|
+
return await fn(url, init);
|
|
42158
|
+
} catch (err) {
|
|
42159
|
+
throw relayFetchError(err, url);
|
|
42160
|
+
}
|
|
42161
|
+
}
|
|
42162
|
+
async function readJson3(res, url) {
|
|
42163
|
+
try {
|
|
42164
|
+
return await res.json();
|
|
42165
|
+
} catch {
|
|
42166
|
+
const kind = (res.headers.get("content-type") ?? "").includes("html") ? "an HTML page" : "a non-JSON body";
|
|
42167
|
+
throw new Error(
|
|
42168
|
+
`Relay sign-in returned HTTP ${res.status} with ${kind} (${url}). A work proxy or allowlist often answers with a block page instead of the relay.`
|
|
42169
|
+
);
|
|
42170
|
+
}
|
|
42171
|
+
}
|
|
42052
42172
|
async function startRemoteAccountLogin(opts) {
|
|
42053
42173
|
if (opts.signal?.aborted) throw new RemoteAccountLoginCancelled();
|
|
42054
42174
|
const origin = (opts.origin ?? remoteAccountHttpOrigin()).replace(/\/+$/, "");
|
|
42055
|
-
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
42056
42175
|
const state = (0, import_node_crypto28.randomBytes)(16).toString("hex");
|
|
42057
42176
|
const timeoutMs = opts.timeoutMs ?? 5 * 6e4;
|
|
42058
42177
|
const pollIntervalMs = opts.pollIntervalMs ?? 400;
|
|
42059
42178
|
const linkToken = opts.linkToken?.trim() ?? "";
|
|
42060
|
-
const
|
|
42179
|
+
const startUrl = `${origin}${REMOTE_LOGIN_PATH}`;
|
|
42180
|
+
const started = await relayFetch(opts.fetchImpl, startUrl, {
|
|
42061
42181
|
method: "POST",
|
|
42062
42182
|
headers: { "Content-Type": "application/json" },
|
|
42063
42183
|
body: JSON.stringify({
|
|
@@ -42066,9 +42186,9 @@ async function startRemoteAccountLogin(opts) {
|
|
|
42066
42186
|
...linkToken ? { accountToken: linkToken } : {}
|
|
42067
42187
|
})
|
|
42068
42188
|
});
|
|
42069
|
-
const startBody = await started
|
|
42189
|
+
const startBody = await readJson3(started, startUrl);
|
|
42070
42190
|
if (!started.ok || !startBody.url) {
|
|
42071
|
-
throw new Error(startBody.error ||
|
|
42191
|
+
throw new Error(startBody.error || `Could not start sign-in (HTTP ${started.status}).`);
|
|
42072
42192
|
}
|
|
42073
42193
|
await Promise.resolve(opts.openUrl?.(startBody.url));
|
|
42074
42194
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -42077,9 +42197,11 @@ async function startRemoteAccountLogin(opts) {
|
|
|
42077
42197
|
if (opts.signal?.aborted) throw new RemoteAccountLoginCancelled();
|
|
42078
42198
|
let res;
|
|
42079
42199
|
try {
|
|
42080
|
-
res = await fetchImpl
|
|
42081
|
-
} catch {
|
|
42082
|
-
if (opts.signal?.aborted
|
|
42200
|
+
res = await relayFetch(opts.fetchImpl, resultUrl);
|
|
42201
|
+
} catch (err) {
|
|
42202
|
+
if (opts.signal?.aborted || isRemoteAccountLoginCancelled(err)) {
|
|
42203
|
+
throw new RemoteAccountLoginCancelled();
|
|
42204
|
+
}
|
|
42083
42205
|
await sleep2(pollIntervalMs, opts.signal);
|
|
42084
42206
|
continue;
|
|
42085
42207
|
}
|
|
@@ -42104,8 +42226,7 @@ async function startRemoteAccountLogin(opts) {
|
|
|
42104
42226
|
}
|
|
42105
42227
|
async function disconnectRemoteAccount(opts) {
|
|
42106
42228
|
const origin = (opts.origin ?? remoteAccountHttpOrigin()).replace(/\/+$/, "");
|
|
42107
|
-
|
|
42108
|
-
await fetchImpl(`${origin}${REMOTE_LOGOUT_PATH}`, {
|
|
42229
|
+
await relayFetch(opts.fetchImpl, `${origin}${REMOTE_LOGOUT_PATH}`, {
|
|
42109
42230
|
method: "POST",
|
|
42110
42231
|
headers: { "Content-Type": "application/json" },
|
|
42111
42232
|
body: JSON.stringify({ accountToken: opts.accountToken })
|
package/dist/index.d.cts
CHANGED
|
@@ -3443,8 +3443,14 @@ declare function installOptionalServiceCli(id: OptionalServiceId): Promise<Agent
|
|
|
3443
3443
|
* an opaque `TypeError: fetch failed` or `UNABLE_TO_GET_ISSUER_CERT_LOCALLY`.
|
|
3444
3444
|
*/
|
|
3445
3445
|
declare function setHttpFetchImpl(fetchImpl: typeof fetch | null): void;
|
|
3446
|
-
/**
|
|
3447
|
-
|
|
3446
|
+
/**
|
|
3447
|
+
* Expand undici/Electron `TypeError: fetch failed` with the underlying cause.
|
|
3448
|
+
* `tlsHint` replaces the default Linear certificate note when the failure is a
|
|
3449
|
+
* corporate CA rejection. Pass '' to omit that note.
|
|
3450
|
+
*/
|
|
3451
|
+
declare function formatFetchError(err: unknown, url: string, opts?: {
|
|
3452
|
+
tlsHint?: string;
|
|
3453
|
+
}): string;
|
|
3448
3454
|
declare function httpFetch(input: string | URL, init?: RequestInit): Promise<Response>;
|
|
3449
3455
|
|
|
3450
3456
|
/**
|
|
@@ -5536,8 +5542,8 @@ declare class Orchestrator {
|
|
|
5536
5542
|
/** Timers for orchestration session-quota auto-resume. */
|
|
5537
5543
|
private readonly quotaResumeTimers;
|
|
5538
5544
|
/**
|
|
5539
|
-
*
|
|
5540
|
-
*
|
|
5545
|
+
* Crash-continue count per thread. Cleared on a successful finish or a user
|
|
5546
|
+
* send. Stream cutoffs may resume more than once; other crashes once.
|
|
5541
5547
|
*/
|
|
5542
5548
|
private readonly crashContinued;
|
|
5543
5549
|
/** Auto-continues after a worktree turn ended while a detached job still runs. */
|
|
@@ -8011,6 +8017,7 @@ type RemoteOutbound = {
|
|
|
8011
8017
|
|
|
8012
8018
|
declare function formatRemotePrompt(text: string): string;
|
|
8013
8019
|
declare function isRemoteStopCommand(text: string): boolean;
|
|
8020
|
+
|
|
8014
8021
|
declare function handleRemoteInbound(text: string, opts: {
|
|
8015
8022
|
deviceId: string;
|
|
8016
8023
|
agent?: AgentKind;
|
package/dist/index.d.ts
CHANGED
|
@@ -3443,8 +3443,14 @@ declare function installOptionalServiceCli(id: OptionalServiceId): Promise<Agent
|
|
|
3443
3443
|
* an opaque `TypeError: fetch failed` or `UNABLE_TO_GET_ISSUER_CERT_LOCALLY`.
|
|
3444
3444
|
*/
|
|
3445
3445
|
declare function setHttpFetchImpl(fetchImpl: typeof fetch | null): void;
|
|
3446
|
-
/**
|
|
3447
|
-
|
|
3446
|
+
/**
|
|
3447
|
+
* Expand undici/Electron `TypeError: fetch failed` with the underlying cause.
|
|
3448
|
+
* `tlsHint` replaces the default Linear certificate note when the failure is a
|
|
3449
|
+
* corporate CA rejection. Pass '' to omit that note.
|
|
3450
|
+
*/
|
|
3451
|
+
declare function formatFetchError(err: unknown, url: string, opts?: {
|
|
3452
|
+
tlsHint?: string;
|
|
3453
|
+
}): string;
|
|
3448
3454
|
declare function httpFetch(input: string | URL, init?: RequestInit): Promise<Response>;
|
|
3449
3455
|
|
|
3450
3456
|
/**
|
|
@@ -5536,8 +5542,8 @@ declare class Orchestrator {
|
|
|
5536
5542
|
/** Timers for orchestration session-quota auto-resume. */
|
|
5537
5543
|
private readonly quotaResumeTimers;
|
|
5538
5544
|
/**
|
|
5539
|
-
*
|
|
5540
|
-
*
|
|
5545
|
+
* Crash-continue count per thread. Cleared on a successful finish or a user
|
|
5546
|
+
* send. Stream cutoffs may resume more than once; other crashes once.
|
|
5541
5547
|
*/
|
|
5542
5548
|
private readonly crashContinued;
|
|
5543
5549
|
/** Auto-continues after a worktree turn ended while a detached job still runs. */
|
|
@@ -8011,6 +8017,7 @@ type RemoteOutbound = {
|
|
|
8011
8017
|
|
|
8012
8018
|
declare function formatRemotePrompt(text: string): string;
|
|
8013
8019
|
declare function isRemoteStopCommand(text: string): boolean;
|
|
8020
|
+
|
|
8014
8021
|
declare function handleRemoteInbound(text: string, opts: {
|
|
8015
8022
|
deviceId: string;
|
|
8016
8023
|
agent?: AgentKind;
|