@sideboard-ai/core 0.1.284 → 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.
Files changed (42) hide show
  1. package/dist/{abletime-WLDBJJUI.js → abletime-4CH2IOX5.js} +4 -4
  2. package/dist/{abletime-X64E3GUJ.js → abletime-I4RODUKT.js} +4 -4
  3. package/dist/{abletime-oauth-AXR676W5.js → abletime-oauth-7OZZ3ABX.js} +3 -3
  4. package/dist/{abletime-oauth-UWOCEICP.js → abletime-oauth-C2HN2Q6F.js} +3 -3
  5. package/dist/{abletime-rest-S4XWEXV2.js → abletime-rest-E4LBRFLM.js} +3 -3
  6. package/dist/{abletime-rest-LPUDJUEP.js → abletime-rest-WFI2HWBU.js} +3 -3
  7. package/dist/agents/cursor-runner.cjs +48 -11
  8. package/dist/agents/cursor-runner.js +48 -11
  9. package/dist/{agents-PM5ICSO3.js → agents-FKMYAKFD.js} +4 -4
  10. package/dist/{agents-6U2RQK7P.js → agents-ITNCZ6CA.js} +4 -4
  11. package/dist/chunk-2GPQZZLY.js +59 -0
  12. package/dist/{chunk-OEJQK7CY.js → chunk-2K723QZH.js} +3 -3
  13. package/dist/{chunk-ROPGQRPU.js → chunk-33KDPEK4.js} +1 -1
  14. package/dist/{chunk-I6HSGKMZ.js → chunk-5T4YWFLD.js} +2 -2
  15. package/dist/{chunk-U7HAVAGJ.js → chunk-6CVVNAIU.js} +2 -2
  16. package/dist/{chunk-TQRSVE7D.js → chunk-7IAMHN2N.js} +1 -1
  17. package/dist/{chunk-WQ4M2L44.js → chunk-C6NVTLZK.js} +5 -5
  18. package/dist/{chunk-VA55JG2I.js → chunk-DEJALWKM.js} +5 -5
  19. package/dist/{chunk-XTPQEZZA.js → chunk-IJMUYHPT.js} +3 -3
  20. package/dist/chunk-JAT3JFOS.js +61 -0
  21. package/dist/{chunk-DGPROCE5.js → chunk-LS4FFCPL.js} +3 -3
  22. package/dist/{chunk-P2BSMNHB.js → chunk-PXMLMBMI.js} +1 -1
  23. package/dist/{chunk-BS3QLVPL.js → chunk-TMM4FEZ5.js} +3 -3
  24. package/dist/{chunk-BSN6DJ4L.js → chunk-TXHZJESB.js} +3 -3
  25. package/dist/{chunk-GWFVCCJZ.js → chunk-VGNLMGBK.js} +6 -6
  26. package/dist/{chunk-PY4UCMRI.js → chunk-VQEARG5H.js} +5 -5
  27. package/dist/{chunk-COQLZNKQ.js → chunk-XSPOJFTV.js} +3 -3
  28. package/dist/{connected-teams-JIUOSZ6C.js → connected-teams-AB7ZHJVO.js} +3 -3
  29. package/dist/{connected-teams-RU6VATCM.js → connected-teams-BJ6PMIST.js} +3 -3
  30. package/dist/index.cjs +209 -112
  31. package/dist/index.d.cts +9 -2
  32. package/dist/index.d.ts +9 -2
  33. package/dist/index.js +171 -96
  34. package/dist/mcp/run-stdio.cjs +36 -17
  35. package/dist/mcp/run-stdio.js +8 -8
  36. package/dist/{oauth-S3M7B475.js → oauth-DP4ZV2M2.js} +2 -2
  37. package/dist/{oauth-K6CWZEQO.js → oauth-WCUZ6Z5G.js} +2 -2
  38. package/dist/{orchestrator-6YVY6T5I.js → orchestrator-F7KXYDQW.js} +5 -5
  39. package/dist/{orchestrator-CRBIW2RG.js → orchestrator-VUIRO6NC.js} +5 -5
  40. package/package.json +1 -1
  41. package/dist/chunk-N7WZ6NIN.js +0 -41
  42. package/dist/chunk-VKQGAWHY.js +0 -40
package/dist/index.cjs CHANGED
@@ -11999,30 +11999,49 @@ var init_config = __esm({
11999
11999
  function setHttpFetchImpl(fetchImpl) {
12000
12000
  injected = fetchImpl;
12001
12001
  }
12002
- function tlsIssuerHint(code, message) {
12003
- const text7 = `${code ?? ""} ${message}`;
12004
- return TLS_ISSUER_RE.test(text7) ? TLS_ISSUER_HINT : "";
12002
+ function isTlsIssuerFailure(code, message) {
12003
+ return TLS_ISSUER_RE.test(`${code ?? ""} ${message}`);
12005
12004
  }
12006
- function formatFetchError(err, url) {
12007
- if (!(err instanceof Error)) return `${String(err)} (${url})`;
12008
- const cause = err.cause;
12009
- let detail = "";
12010
- let hint = tlsIssuerHint(void 0, err.message);
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
+ }
12011
12014
  if (cause instanceof Error) {
12012
12015
  const code = typeof cause.code === "string" ? cause.code : void 0;
12013
- detail = code ? ` [${code}: ${cause.message}]` : ` [${cause.message}]`;
12014
- hint = tlsIssuerHint(code, `${err.message} ${cause.message}`) || hint;
12015
- } else if (cause != null) {
12016
- detail = ` [${String(cause)}]`;
12017
- hint = tlsIssuerHint(void 0, String(cause)) || hint;
12018
- }
12019
- return `${err.message}${detail} (${url})${hint}`;
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);
12020
12040
  }
12021
12041
  async function httpFetch(input, init) {
12022
12042
  const url = typeof input === "string" ? input : input.href;
12023
- const fn = injected ?? globalThis.fetch.bind(globalThis);
12024
12043
  try {
12025
- return await fn(url, init);
12044
+ return await currentHttpFetch()(url, init);
12026
12045
  } catch (err) {
12027
12046
  throw new Error(formatFetchError(err, url));
12028
12047
  }
@@ -14719,10 +14738,10 @@ function eventsFromClaudeSystem(obj) {
14719
14738
  if (subtype === "api_retry") {
14720
14739
  const attempt = obj.attempt;
14721
14740
  const max = obj.max_retries;
14722
- const delay2 = obj.retry_delay_ms;
14741
+ const delay3 = obj.retry_delay_ms;
14723
14742
  return {
14724
14743
  type: "thinking",
14725
- data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay2 === "number" ? ` (wait ${delay2}ms)` : ""}`
14744
+ data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay3 === "number" ? ` (wait ${delay3}ms)` : ""}`
14726
14745
  };
14727
14746
  }
14728
14747
  if (subtype === "status") {
@@ -27744,8 +27763,8 @@ var init_orchestrator = __esm({
27744
27763
  scheduleQuotaResume(threadId, resumeAt) {
27745
27764
  this.clearQuotaResumeTimer(threadId);
27746
27765
  updateThread(threadId, { quotaResumeAt: resumeAt.toISOString() });
27747
- const delay2 = Math.max(5e3, resumeAt.getTime() - Date.now());
27748
- const capped = Math.min(delay2, 2147483647);
27766
+ const delay3 = Math.max(5e3, resumeAt.getTime() - Date.now());
27767
+ const capped = Math.min(delay3, 2147483647);
27749
27768
  const timer = setTimeout(() => {
27750
27769
  this.quotaResumeTimers.delete(threadId);
27751
27770
  void this.resumeAfterQuotaWait(threadId);
@@ -30186,14 +30205,14 @@ function armOne(schedule) {
30186
30205
  if (!schedule.enabled) return;
30187
30206
  const at = new Date(schedule.nextRunAt);
30188
30207
  if (Number.isNaN(at.getTime())) return;
30189
- const delay2 = Math.max(0, at.getTime() - Date.now());
30190
- if (delay2 <= 250) {
30208
+ const delay3 = Math.max(0, at.getTime() - Date.now());
30209
+ if (delay3 <= 250) {
30191
30210
  void fireSchedule(schedule.id).then(() => {
30192
30211
  if (isThisProcessDesktopHost()) armSchedules();
30193
30212
  });
30194
30213
  return;
30195
30214
  }
30196
- const capped = Math.min(delay2, SET_TIMEOUT_MAX);
30215
+ const capped = Math.min(delay3, SET_TIMEOUT_MAX);
30197
30216
  const timer = setTimeout(() => {
30198
30217
  timers.delete(schedule.id);
30199
30218
  const live = getSchedule(schedule.id);
@@ -39738,10 +39757,7 @@ var import_ws5 = require("ws");
39738
39757
  init_orchestrator_capable();
39739
39758
  init_stage_files();
39740
39759
  init_orchestrator();
39741
- init_ask_user();
39742
39760
  init_app_settings();
39743
- init_global_workspace();
39744
- init_thread_store();
39745
39761
  init_implied_first_prompt();
39746
39762
 
39747
39763
  // src/remote/phone-media.ts
@@ -40720,7 +40736,13 @@ function deliverPhoneTurn(opts, chatId) {
40720
40736
  });
40721
40737
  }
40722
40738
 
40723
- // src/remote/listen.ts
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();
40724
40746
  function formatRemotePrompt(text7) {
40725
40747
  return `Phone
40726
40748
 
@@ -40729,6 +40751,29 @@ ${text7.trim()}`;
40729
40751
  function isRemoteStopCommand(text7) {
40730
40752
  return text7.trim().toLowerCase() === "stop";
40731
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
+ }
40732
40777
  var handleChain2 = Promise.resolve();
40733
40778
  var inboundGeneration = 0;
40734
40779
  function enqueue(fn) {
@@ -40752,6 +40797,77 @@ function interruptRemoteCoordinator(deviceId, log = () => void 0) {
40752
40797
  return false;
40753
40798
  }
40754
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
40755
40871
  function emitOpened(opts, opened) {
40756
40872
  setPhoneOpenChat(opened.chat.id);
40757
40873
  emitControl(opts, { op: "opened", ...opened });
@@ -41021,23 +41137,27 @@ function handlePhoneControl(cmd, opts) {
41021
41137
  return;
41022
41138
  }
41023
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
+ }
41024
41147
  const generation = bumpChat(chatId);
41025
41148
  phoneTurnGen.set(chatId, generation);
41026
- interruptChat(chatId, log);
41027
- enqueueChat(chatId, async () => {
41028
- if (chatGeneration.get(chatId) !== generation) return;
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;
41029
41156
  const thread = readPhoneThread(chatId);
41030
41157
  if (!thread) {
41031
41158
  emitControl(opts, { op: "error", chatId, message: "That agent is not on this Mac." });
41032
41159
  return;
41033
41160
  }
41034
- if (thread.status === "running" || thread.status === "queued") {
41035
- try {
41036
- getOrchestrator().stop(thread.id, { clearQueue: true });
41037
- } catch {
41038
- }
41039
- }
41040
- if (chatGeneration.get(chatId) !== generation) return;
41041
41161
  const stopStream = watchPhoneStream(opts, chatId, thread.id, generation);
41042
41162
  try {
41043
41163
  try {
@@ -41045,14 +41165,19 @@ function handlePhoneControl(cmd, opts) {
41045
41165
  } catch (err) {
41046
41166
  emitControl(opts, { op: "error", chatId, message: phoneError(err) });
41047
41167
  }
41168
+ if (!current()) return;
41048
41169
  const live = readPhoneThread(thread.id) ?? thread;
41170
+ const followUp = followUpBehavior();
41049
41171
  const staged = stagePhoneTurnFiles(live.worktreePath, cmd);
41050
41172
  const text7 = cmd.text.trim() || (staged.length ? "See the attached files." : "");
41051
- const formatted = formatRemotePrompt(text7);
41052
- await getOrchestrator().send(thread.id, formatted, { attachments: staged });
41053
- await getOrchestrator().waitForTurn(thread.id, 14 * 60 * 1e3);
41173
+ await getOrchestrator().send(thread.id, formatRemotePrompt(text7), {
41174
+ attachments: staged,
41175
+ followUp
41176
+ });
41177
+ if (!current()) return;
41178
+ await waitForPhoneTurn(thread.id, current);
41054
41179
  } catch (err) {
41055
- if (chatGeneration.get(chatId) !== generation) return;
41180
+ if (!current()) return;
41056
41181
  const message = err instanceof Error ? err.message : String(err);
41057
41182
  emitControl(opts, { op: "error", chatId, message: `Sideboard failed: ${message}` });
41058
41183
  return;
@@ -41060,12 +41185,11 @@ function handlePhoneControl(cmd, opts) {
41060
41185
  stopStream();
41061
41186
  finishPhoneTurn(chatId, generation);
41062
41187
  }
41063
- if (chatGeneration.get(chatId) !== generation) return;
41188
+ if (!current()) return;
41064
41189
  emitChatTurn(opts, chatId, thread.id);
41065
- });
41190
+ })();
41066
41191
  }
41067
41192
  function handleRemoteInbound(text7, opts) {
41068
- const log = opts.onLog ?? (() => void 0);
41069
41193
  const body = text7.trim();
41070
41194
  const control = takePhoneControl(body);
41071
41195
  if (control) {
@@ -41076,64 +41200,7 @@ function handleRemoteInbound(text7, opts) {
41076
41200
  handlePhoneControl(control, opts);
41077
41201
  return;
41078
41202
  }
41079
- const generation = ++inboundGeneration;
41080
- if (body) interruptRemoteCoordinator(opts.deviceId, log);
41081
- enqueue(async () => {
41082
- if (generation !== inboundGeneration) return;
41083
- const agent = coerceOrchestratorAgent(opts.agent ?? resolveOrchestratorDefaults().agent);
41084
- if (!body) return;
41085
- if (isRemoteStopCommand(body)) {
41086
- if (generation !== inboundGeneration) return;
41087
- opts.onOutbound({ type: "assistant", text: REMOTE_STOPPED_REPLY });
41088
- return;
41089
- }
41090
- let thread = ensureRemoteCoordinator(opts.deviceId, agent);
41091
- const fresh = readThread(thread.id) ?? thread;
41092
- if (fresh.status === "running" || fresh.status === "queued") {
41093
- try {
41094
- getOrchestrator().stop(fresh.id, { clearQueue: true });
41095
- } catch {
41096
- }
41097
- }
41098
- if (generation !== inboundGeneration) return;
41099
- const orch = getOrchestrator();
41100
- try {
41101
- await orch.send(thread.id, formatRemotePrompt(body));
41102
- await orch.waitForTurn(thread.id, 14 * 60 * 1e3);
41103
- } catch (err) {
41104
- if (generation !== inboundGeneration) return;
41105
- const message = err instanceof Error ? err.message : String(err);
41106
- opts.onOutbound({ type: "assistant", text: `Sideboard failed: ${message}` });
41107
- return;
41108
- }
41109
- if (generation !== inboundGeneration) return;
41110
- thread = readThread(thread.id) ?? thread;
41111
- if (thread.status === "stopped") return;
41112
- const result = orch.getTurnResult(thread.id);
41113
- const pending = extractPendingPlanQuestions(
41114
- [...thread.messages].reverse().find((m) => m.role === "agent")?.parts
41115
- );
41116
- if (result.taskState === "input-required" && pending) {
41117
- opts.onOutbound({
41118
- type: "ask_user",
41119
- text: result.text.trim(),
41120
- questions: pending.questions.map((q) => ({
41121
- question: q.question,
41122
- options: q.options.map(
41123
- (o) => o.description ? { label: o.label, description: o.description } : { label: o.label }
41124
- )
41125
- }))
41126
- });
41127
- return;
41128
- }
41129
- const reply = outboundReplyFromTurn(result, {
41130
- inputRequired: "Sideboard is waiting for an answer.",
41131
- canceled: REMOTE_STOPPED_REPLY,
41132
- completedEmpty: () => "",
41133
- failed: (detail) => detail ? `Sideboard failed: ${detail}` : "Sideboard failed before producing a result."
41134
- });
41135
- if (reply.trim()) opts.onOutbound({ type: "assistant", text: reply.trim() });
41136
- });
41203
+ beginCoordinatorPrompt(body, opts);
41137
41204
  }
41138
41205
 
41139
41206
  // src/remote/phone-board-sync.ts
@@ -41473,6 +41540,7 @@ function runRemoteHost(opts) {
41473
41540
 
41474
41541
  // src/relay/account-login.ts
41475
41542
  var import_node_crypto28 = require("crypto");
41543
+ init_fetch();
41476
41544
 
41477
41545
  // src/relay/accounts.ts
41478
41546
  var import_node_crypto27 = require("crypto");
@@ -42073,15 +42141,43 @@ function sleep2(ms, signal) {
42073
42141
  signal?.addEventListener("abort", onAbort, { once: true });
42074
42142
  });
42075
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
+ }
42076
42172
  async function startRemoteAccountLogin(opts) {
42077
42173
  if (opts.signal?.aborted) throw new RemoteAccountLoginCancelled();
42078
42174
  const origin = (opts.origin ?? remoteAccountHttpOrigin()).replace(/\/+$/, "");
42079
- const fetchImpl = opts.fetchImpl ?? fetch;
42080
42175
  const state = (0, import_node_crypto28.randomBytes)(16).toString("hex");
42081
42176
  const timeoutMs = opts.timeoutMs ?? 5 * 6e4;
42082
42177
  const pollIntervalMs = opts.pollIntervalMs ?? 400;
42083
42178
  const linkToken = opts.linkToken?.trim() ?? "";
42084
- const started = await fetchImpl(`${origin}${REMOTE_LOGIN_PATH}`, {
42179
+ const startUrl = `${origin}${REMOTE_LOGIN_PATH}`;
42180
+ const started = await relayFetch(opts.fetchImpl, startUrl, {
42085
42181
  method: "POST",
42086
42182
  headers: { "Content-Type": "application/json" },
42087
42183
  body: JSON.stringify({
@@ -42090,9 +42186,9 @@ async function startRemoteAccountLogin(opts) {
42090
42186
  ...linkToken ? { accountToken: linkToken } : {}
42091
42187
  })
42092
42188
  });
42093
- const startBody = await started.json();
42189
+ const startBody = await readJson3(started, startUrl);
42094
42190
  if (!started.ok || !startBody.url) {
42095
- throw new Error(startBody.error || "Could not start sign-in.");
42191
+ throw new Error(startBody.error || `Could not start sign-in (HTTP ${started.status}).`);
42096
42192
  }
42097
42193
  await Promise.resolve(opts.openUrl?.(startBody.url));
42098
42194
  const deadline = Date.now() + timeoutMs;
@@ -42101,9 +42197,11 @@ async function startRemoteAccountLogin(opts) {
42101
42197
  if (opts.signal?.aborted) throw new RemoteAccountLoginCancelled();
42102
42198
  let res;
42103
42199
  try {
42104
- res = await fetchImpl(resultUrl);
42105
- } catch {
42106
- if (opts.signal?.aborted) throw new RemoteAccountLoginCancelled();
42200
+ res = await relayFetch(opts.fetchImpl, resultUrl);
42201
+ } catch (err) {
42202
+ if (opts.signal?.aborted || isRemoteAccountLoginCancelled(err)) {
42203
+ throw new RemoteAccountLoginCancelled();
42204
+ }
42107
42205
  await sleep2(pollIntervalMs, opts.signal);
42108
42206
  continue;
42109
42207
  }
@@ -42128,8 +42226,7 @@ async function startRemoteAccountLogin(opts) {
42128
42226
  }
42129
42227
  async function disconnectRemoteAccount(opts) {
42130
42228
  const origin = (opts.origin ?? remoteAccountHttpOrigin()).replace(/\/+$/, "");
42131
- const fetchImpl = opts.fetchImpl ?? fetch;
42132
- await fetchImpl(`${origin}${REMOTE_LOGOUT_PATH}`, {
42229
+ await relayFetch(opts.fetchImpl, `${origin}${REMOTE_LOGOUT_PATH}`, {
42133
42230
  method: "POST",
42134
42231
  headers: { "Content-Type": "application/json" },
42135
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
- /** Expand undici/Electron `TypeError: fetch failed` with the underlying cause. */
3447
- declare function formatFetchError(err: unknown, url: string): string;
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
  /**
@@ -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
- /** Expand undici/Electron `TypeError: fetch failed` with the underlying cause. */
3447
- declare function formatFetchError(err: unknown, url: string): string;
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
  /**
@@ -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;