@sideboard-ai/core 0.1.174 → 0.1.176

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 (40) hide show
  1. package/dist/{abletime-PCLL36HW.js → abletime-BFIDZR3O.js} +2 -2
  2. package/dist/{abletime-7VW4EGPT.js → abletime-INEHQH6K.js} +2 -2
  3. package/dist/agents/cursor-runner.cjs +91 -62
  4. package/dist/agents/cursor-runner.js +1 -1
  5. package/dist/{agents-ZWYRGFZB.js → agents-544IX5KA.js} +8 -6
  6. package/dist/{agents-LMPVUPOH.js → agents-UENEQ6J2.js} +7 -5
  7. package/dist/{chunk-ZY7K4T37.js → chunk-3ZFGZ7RT.js} +5 -5
  8. package/dist/{chunk-HJPGIETB.js → chunk-4ELBAYFW.js} +19 -14
  9. package/dist/{chunk-M267JPEA.js → chunk-AN3THU7F.js} +1 -1
  10. package/dist/{chunk-AQPVBVJE.js → chunk-BBNUL4IE.js} +1 -1
  11. package/dist/{chunk-VCVBICMZ.js → chunk-FJWQCZ74.js} +5 -5
  12. package/dist/{chunk-LZ6QMEQC.js → chunk-HVIEYTUK.js} +1 -1
  13. package/dist/{chunk-XD2BAANL.js → chunk-IEEAVWAP.js} +6 -6
  14. package/dist/{chunk-YEPVWJ3R.js → chunk-JUA7XEXR.js} +16 -11
  15. package/dist/{chunk-ELBYOGVA.js → chunk-N7WZ6NIN.js} +10 -1
  16. package/dist/{chunk-CUA4S537.js → chunk-NIB6BTC6.js} +9 -5
  17. package/dist/{chunk-XXIH6XYR.js → chunk-NQTKRAUF.js} +167 -35
  18. package/dist/{chunk-CMJ2FBBV.js → chunk-RE2YWFUQ.js} +1 -1
  19. package/dist/{chunk-6GN5WPYZ.js → chunk-VKQGAWHY.js} +10 -1
  20. package/dist/{chunk-TPPZXZTA.js → chunk-W44EKPIR.js} +228 -95
  21. package/dist/{chunk-S42XV45P.js → chunk-Y4MIXGPA.js} +1 -1
  22. package/dist/{connected-teams-DBWAMP7G.js → connected-teams-ON2KIKQX.js} +3 -3
  23. package/dist/{connected-teams-WGONUQOF.js → connected-teams-WOYCH7FR.js} +3 -3
  24. package/dist/{coordinator-prompt-K3HXEPFD.js → coordinator-prompt-BE2FERYE.js} +1 -1
  25. package/dist/{coordinator-prompt-LJKA2ODR.js → coordinator-prompt-PRM5ARWG.js} +1 -1
  26. package/dist/{global-workspace-VDFSU3DD.js → global-workspace-3HIWNQ3B.js} +1 -1
  27. package/dist/{global-workspace-KA7T26F5.js → global-workspace-J737XNUX.js} +1 -1
  28. package/dist/index.cjs +584 -379
  29. package/dist/index.d.cts +53 -10
  30. package/dist/index.d.ts +53 -10
  31. package/dist/index.js +76 -27
  32. package/dist/mcp/run-stdio.cjs +778 -576
  33. package/dist/mcp/run-stdio.js +78 -27
  34. package/dist/{oauth-A7XXI2TM.js → oauth-6ZQ4Q4XN.js} +2 -2
  35. package/dist/{oauth-YJBAURIJ.js → oauth-O7UGLZOY.js} +2 -2
  36. package/dist/{orchestrator-DMSSC4SV.js → orchestrator-2KZD7N4X.js} +6 -6
  37. package/dist/{orchestrator-VMUZJFTZ.js → orchestrator-GDKEVLFK.js} +7 -7
  38. package/dist/{workspaces-GOGBPATJ.js → workspaces-DR4UNOQC.js} +1 -1
  39. package/dist/{workspaces-UR7YEFMZ.js → workspaces-ULHYXM4Y.js} +1 -1
  40. package/package.json +1 -1
@@ -4,7 +4,7 @@ import {
4
4
  loadBrightsyConfig,
5
5
  refreshBrightsyAccessToken,
6
6
  saveBrightsyConfig
7
- } from "./chunk-M267JPEA.js";
7
+ } from "./chunk-AN3THU7F.js";
8
8
  import {
9
9
  appDataDir
10
10
  } from "./chunk-EFVFB2AH.js";
@@ -18,7 +18,7 @@ import { join } from "path";
18
18
 
19
19
  // src/brightsy/accounts.ts
20
20
  async function loadConnectedTeams() {
21
- const { listConnectedBrightsyTeams: listConnectedBrightsyTeams2 } = await import("./connected-teams-DBWAMP7G.js");
21
+ const { listConnectedBrightsyTeams: listConnectedBrightsyTeams2 } = await import("./connected-teams-ON2KIKQX.js");
22
22
  return listConnectedBrightsyTeams2();
23
23
  }
24
24
  async function runBrightsyTeamsJson(args) {
@@ -46,15 +46,15 @@ async function listBrightsyAccounts() {
46
46
  }
47
47
  async function getBrightsySession() {
48
48
  try {
49
- const { ensureBrightsyLocalConfigFresh: ensureBrightsyLocalConfigFresh2 } = await import("./oauth-A7XXI2TM.js");
50
- const { ensureConnectedBrightsyTeamTokens: ensureConnectedBrightsyTeamTokens2 } = await import("./connected-teams-DBWAMP7G.js");
49
+ const { ensureBrightsyLocalConfigFresh: ensureBrightsyLocalConfigFresh2 } = await import("./oauth-6ZQ4Q4XN.js");
50
+ const { ensureConnectedBrightsyTeamTokens: ensureConnectedBrightsyTeamTokens2 } = await import("./connected-teams-ON2KIKQX.js");
51
51
  await ensureBrightsyLocalConfigFresh2();
52
52
  await ensureConnectedBrightsyTeamTokens2();
53
53
  loadBrightsyConfig();
54
54
  const data = await runBrightsyTeamsJson([]);
55
55
  const accounts = Array.isArray(data.teams) ? data.teams : [];
56
56
  const active = data.active ?? accounts.find((a) => a.active) ?? null;
57
- const { ensureCliTeamTracked: ensureCliTeamTracked2 } = await import("./connected-teams-DBWAMP7G.js");
57
+ const { ensureCliTeamTracked: ensureCliTeamTracked2 } = await import("./connected-teams-ON2KIKQX.js");
58
58
  const connectedTeams = ensureCliTeamTracked2(
59
59
  active ? { id: active.id, slug: active.slug, name: active.name } : void 0
60
60
  );
@@ -94,7 +94,7 @@ async function performBrightsyAccountSwitch(accountIdOrSlug) {
94
94
  return { cfg, target: data.active };
95
95
  }
96
96
  async function switchBrightsyAccount(accountIdOrSlug) {
97
- const { connectBrightsyTeam: connectBrightsyTeam2 } = await import("./connected-teams-DBWAMP7G.js");
97
+ const { connectBrightsyTeam: connectBrightsyTeam2 } = await import("./connected-teams-ON2KIKQX.js");
98
98
  await connectBrightsyTeam2(accountIdOrSlug);
99
99
  return getBrightsySession();
100
100
  }
@@ -33,7 +33,7 @@ import {
33
33
  summarizeTurnStderr,
34
34
  toolDescription,
35
35
  turnFailChatText
36
- } from "./chunk-TPPZXZTA.js";
36
+ } from "./chunk-W44EKPIR.js";
37
37
  import {
38
38
  extractPresentedPlan,
39
39
  readPlanFile,
@@ -64,7 +64,7 @@ import {
64
64
  stageAbsolutePathsAsAttachments,
65
65
  stageBuffersAsAttachments,
66
66
  syncWorkspacesFromThreads
67
- } from "./chunk-VCVBICMZ.js";
67
+ } from "./chunk-FJWQCZ74.js";
68
68
  import {
69
69
  addPrStackLayer,
70
70
  allocateTeamName,
@@ -401,7 +401,7 @@ async function continueSourceThread(threadId, prompt) {
401
401
  await continueOnReply(threadId, prompt);
402
402
  return;
403
403
  }
404
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-DMSSC4SV.js");
404
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-2KZD7N4X.js");
405
405
  await getOrchestrator2().send(threadId, prompt);
406
406
  } catch {
407
407
  }
@@ -794,9 +794,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
794
794
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
795
795
  );
796
796
  }
797
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-KA7T26F5.js");
797
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-J737XNUX.js");
798
798
  if (isGlobalThread2(thread)) {
799
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-K3HXEPFD.js");
799
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-BE2FERYE.js");
800
800
  ensureGlobalCoordinatorCwd2(
801
801
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
802
802
  );
@@ -991,6 +991,7 @@ var AGENT_GIT_ACTIONS = [
991
991
  "create-draft",
992
992
  "create-web",
993
993
  "resolve-conflicts",
994
+ "ready-for-review",
994
995
  "merge"
995
996
  ];
996
997
  function agentGitPrompt(action, opts) {
@@ -1006,6 +1007,8 @@ function agentGitPrompt(action, opts) {
1006
1007
  const named = base ? ` (${base})` : "";
1007
1008
  return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
1008
1009
  }
1010
+ case "ready-for-review":
1011
+ return "Ready for review.";
1009
1012
  case "merge":
1010
1013
  return "Merge PR.";
1011
1014
  }
@@ -1021,6 +1024,8 @@ function gitActionExpansion(action, base) {
1021
1024
  return "Commit, push, then `gh pr create --web -R <origin-owner/name>`.";
1022
1025
  case "resolve-conflicts":
1023
1026
  return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
1027
+ case "ready-for-review":
1028
+ return "This phrase is the explicit ask to mark this thread's draft pull request ready for review on GitHub (`gh pr ready -R <origin-owner/name>` or `gh pr ready`). Update title/body if the purpose drifted. Do not merge.";
1024
1029
  case "merge":
1025
1030
  return "This phrase is the explicit ask to merge this thread's open pull request on GitHub. If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.";
1026
1031
  }
@@ -3555,7 +3560,7 @@ async function createThread(input, _onSetupLine) {
3555
3560
  let sourceIsFork = false;
3556
3561
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
3557
3562
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
3558
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-PCLL36HW.js");
3563
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-BFIDZR3O.js");
3559
3564
  const task = await ensureAbleTimeTask({
3560
3565
  title: title?.trim() || "Untitled work",
3561
3566
  description: input.prompt?.trim() || void 0
@@ -4063,7 +4068,7 @@ async function adoptThread(input) {
4063
4068
  messages: input.messages ?? []
4064
4069
  });
4065
4070
  writeThread(thread);
4066
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-GOGBPATJ.js");
4071
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-DR4UNOQC.js");
4067
4072
  await ensureWorkspace2(repoPath);
4068
4073
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-N5X5I422.js");
4069
4074
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -5844,7 +5849,7 @@ function formatWorktreeDirective(thread, opts) {
5844
5849
  );
5845
5850
  }
5846
5851
  lines.push(
5847
- '- Sideboard git buttons send short phrases ("Commit and push.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
5852
+ '- Sideboard git buttons send short phrases ("Commit and push.", "Ready for review.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
5848
5853
  );
5849
5854
  lines.push("");
5850
5855
  lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
@@ -6339,7 +6344,7 @@ function formatScheduledPrompt(name, prompt) {
6339
6344
  ${prompt}`;
6340
6345
  }
6341
6346
  async function defaultDeps() {
6342
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-DMSSC4SV.js");
6347
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-2KZD7N4X.js");
6343
6348
  const orch = getOrchestrator2();
6344
6349
  return {
6345
6350
  findThread: (id) => findThreadByRef(id),
@@ -8257,7 +8262,7 @@ var Orchestrator = class {
8257
8262
  "ask_git targets a worktree agent thread (not the orchestrator). Pass a child/worktree thread ref."
8258
8263
  );
8259
8264
  }
8260
- if (action === "merge" && !thread.prUrl) {
8265
+ if ((action === "merge" || action === "ready-for-review") && !thread.prUrl) {
8261
8266
  throw new Error(
8262
8267
  "No pull request linked. Ask the worktree agent to open a draft PR first (ask_git create-draft)."
8263
8268
  );
@@ -8425,7 +8430,7 @@ var Orchestrator = class {
8425
8430
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
8426
8431
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
8427
8432
  try {
8428
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-GOGBPATJ.js");
8433
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-DR4UNOQC.js");
8429
8434
  await ensureWorkspace2(thread.repoPath);
8430
8435
  } catch {
8431
8436
  }
@@ -3,17 +3,26 @@ var injected = null;
3
3
  function setHttpFetchImpl(fetchImpl) {
4
4
  injected = fetchImpl;
5
5
  }
6
+ var TLS_ISSUER_RE = /UNABLE_TO_GET_ISSUER_CERT|UNABLE_TO_VERIFY_LEAF_SIGNATURE|SELF_SIGNED_CERT_IN_CHAIN/i;
7
+ var TLS_ISSUER_HINT = " \u2014 Node rejected the TLS certificate (corporate VPN/proxy CA). Desktop Linear can still work; reconnecting the API key will not fix this.";
8
+ function tlsIssuerHint(code, message) {
9
+ const text = `${code ?? ""} ${message}`;
10
+ return TLS_ISSUER_RE.test(text) ? TLS_ISSUER_HINT : "";
11
+ }
6
12
  function formatFetchError(err, url) {
7
13
  if (!(err instanceof Error)) return `${String(err)} (${url})`;
8
14
  const cause = err.cause;
9
15
  let detail = "";
16
+ let hint = tlsIssuerHint(void 0, err.message);
10
17
  if (cause instanceof Error) {
11
18
  const code = typeof cause.code === "string" ? cause.code : void 0;
12
19
  detail = code ? ` [${code}: ${cause.message}]` : ` [${cause.message}]`;
20
+ hint = tlsIssuerHint(code, `${err.message} ${cause.message}`) || hint;
13
21
  } else if (cause != null) {
14
22
  detail = ` [${String(cause)}]`;
23
+ hint = tlsIssuerHint(void 0, String(cause)) || hint;
15
24
  }
16
- return `${err.message}${detail} (${url})`;
25
+ return `${err.message}${detail} (${url})${hint}`;
17
26
  }
18
27
  async function httpFetch(input, init) {
19
28
  const url = typeof input === "string" ? input : input.href;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isOrchestratorThread
3
- } from "./chunk-ZY7K4T37.js";
3
+ } from "./chunk-3ZFGZ7RT.js";
4
4
  import {
5
5
  codexUnattendedGitConfigArgs,
6
6
  mergeAgentGitAuthEnv,
@@ -12,10 +12,10 @@ import {
12
12
  brightsyMcpServerName,
13
13
  ensureCliTeamTracked,
14
14
  ensureConnectedBrightsyTeamTokens
15
- } from "./chunk-XD2BAANL.js";
15
+ } from "./chunk-IEEAVWAP.js";
16
16
  import {
17
17
  loadBrightsyConfig
18
- } from "./chunk-M267JPEA.js";
18
+ } from "./chunk-AN3THU7F.js";
19
19
  import {
20
20
  applyAgentRunnerHeapEnv,
21
21
  applyNodeLaunch,
@@ -29,7 +29,7 @@ import {
29
29
  packagedMcpStdioPath,
30
30
  parseCursorRunnerLine,
31
31
  resolveNodeLaunch
32
- } from "./chunk-XXIH6XYR.js";
32
+ } from "./chunk-NQTKRAUF.js";
33
33
  import {
34
34
  claudeChromeEnabled,
35
35
  isAbleTimeConnected,
@@ -1898,7 +1898,7 @@ var claudeAdapter = {
1898
1898
  );
1899
1899
  }
1900
1900
  const mode = permissionMode(thread);
1901
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-VDFSU3DD.js");
1901
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3HIWNQ3B.js");
1902
1902
  const isOrchestrator = isOrchestratorThread2(thread);
1903
1903
  const injectedServers = await buildInjectedMcpServers({
1904
1904
  includeSideboard: true,
@@ -2684,6 +2684,9 @@ function resolveCursorApiKey() {
2684
2684
  if (fromEnv) return fromEnv;
2685
2685
  return (loadAppSettings().environment.CURSOR_API_KEY || "").trim();
2686
2686
  }
2687
+ function isCursorApiKeyConfigured() {
2688
+ return Boolean(resolveCursorApiKey());
2689
+ }
2687
2690
  function isCursorAutoModel(model) {
2688
2691
  const id = (model ?? "").trim().toLowerCase();
2689
2692
  return !id || id === "default" || id === "auto";
@@ -3700,6 +3703,7 @@ export {
3700
3703
  userMcpNamesToDisable,
3701
3704
  listCodexModels,
3702
3705
  codexAdapter,
3706
+ isCursorApiKeyConfigured,
3703
3707
  isCursorAutoModel,
3704
3708
  resolveCursorModelId,
3705
3709
  listCursorModels,
@@ -2,6 +2,9 @@ import {
2
2
  isElectronLikeCommand,
3
3
  wrapElectronAsNodeLaunch
4
4
  } from "./chunk-4TR3HZFT.js";
5
+ import {
6
+ appDataDir
7
+ } from "./chunk-EFVFB2AH.js";
5
8
  import {
6
9
  run
7
10
  } from "./chunk-UFHNSFAS.js";
@@ -301,14 +304,139 @@ function formatTurnExitError(exitCode, stderrSummary) {
301
304
  return `exit ${code}: ${detail}`;
302
305
  }
303
306
 
307
+ // src/http/system-ca.ts
308
+ import { spawnSync } from "child_process";
309
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
310
+ import { dirname, join } from "path";
311
+ import tls from "tls";
312
+ var NODE_USE_SYSTEM_CA = "NODE_USE_SYSTEM_CA";
313
+ var NODE_EXTRA_CA_CERTS = "NODE_EXTRA_CA_CERTS";
314
+ var BUNDLE_NAME = "system-ca.pem";
315
+ var BUNDLE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
316
+ var LINUX_CA_FILES = [
317
+ "/etc/ssl/certs/ca-certificates.crt",
318
+ "/etc/pki/tls/certs/ca-bundle.crt",
319
+ "/etc/ssl/ca-bundle.pem",
320
+ "/etc/ssl/cert.pem"
321
+ ];
322
+ var PEM_CERT_RE = /-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g;
323
+ function splitPemCertificates(pem) {
324
+ return pem.match(PEM_CERT_RE) ?? [];
325
+ }
326
+ function readExistingFile(path) {
327
+ try {
328
+ return existsSync(path) ? readFileSync(path, "utf8") : "";
329
+ } catch {
330
+ return "";
331
+ }
332
+ }
333
+ function darwinKeychainPem(spawn) {
334
+ const result = spawn("/usr/bin/security", ["find-certificate", "-a", "-p"], {
335
+ encoding: "utf8",
336
+ maxBuffer: 32 * 1024 * 1024,
337
+ timeout: 15e3
338
+ });
339
+ if (result.status !== 0) return "";
340
+ return typeof result.stdout === "string" ? result.stdout : "";
341
+ }
342
+ function linuxSystemCaPem() {
343
+ for (const path of LINUX_CA_FILES) {
344
+ const pem = readExistingFile(path);
345
+ if (splitPemCertificates(pem).length > 0) return pem;
346
+ }
347
+ return "";
348
+ }
349
+ function collectSystemCaPem(io = {}) {
350
+ const platform = io.platform ?? process.platform;
351
+ if (platform === "darwin") {
352
+ return darwinKeychainPem(io.spawn ?? spawnSync);
353
+ }
354
+ if (platform === "linux") {
355
+ return linuxSystemCaPem();
356
+ }
357
+ return "";
358
+ }
359
+ function systemCaBundlePath(io = {}) {
360
+ return join((io.appData ?? appDataDir)(), BUNDLE_NAME);
361
+ }
362
+ function bundleIsFresh(path, now) {
363
+ try {
364
+ if (!existsSync(path)) return false;
365
+ if (splitPemCertificates(readFileSync(path, "utf8")).length === 0) return false;
366
+ return now - statSync(path).mtimeMs < BUNDLE_MAX_AGE_MS;
367
+ } catch {
368
+ return false;
369
+ }
370
+ }
371
+ function materializeSystemCaBundle(io = {}) {
372
+ const inherited = process.env.NODE_EXTRA_CA_CERTS?.trim();
373
+ if (inherited && splitPemCertificates(readExistingFile(inherited)).length > 0) {
374
+ return inherited;
375
+ }
376
+ const platform = io.platform ?? process.platform;
377
+ if (platform === "linux") {
378
+ for (const path of LINUX_CA_FILES) {
379
+ if (splitPemCertificates(readExistingFile(path)).length > 0) return path;
380
+ }
381
+ }
382
+ const dest = systemCaBundlePath(io);
383
+ const now = (io.now ?? Date.now)();
384
+ if (bundleIsFresh(dest, now)) return dest;
385
+ const pem = collectSystemCaPem(io);
386
+ if (splitPemCertificates(pem).length === 0) {
387
+ return existsSync(dest) && splitPemCertificates(readExistingFile(dest)).length > 0 ? dest : void 0;
388
+ }
389
+ try {
390
+ mkdirSync(dirname(dest), { recursive: true });
391
+ writeFileSync(dest, pem.endsWith("\n") ? pem : `${pem}
392
+ `, { mode: 384 });
393
+ return dest;
394
+ } catch {
395
+ return void 0;
396
+ }
397
+ }
398
+ function applySystemCaEnv(env) {
399
+ if (!String(env[NODE_USE_SYSTEM_CA] ?? "").trim()) {
400
+ env[NODE_USE_SYSTEM_CA] = "1";
401
+ }
402
+ if (String(env[NODE_EXTRA_CA_CERTS] ?? "").trim()) return;
403
+ const inherited = process.env.NODE_EXTRA_CA_CERTS?.trim();
404
+ if (inherited) env[NODE_EXTRA_CA_CERTS] = inherited;
405
+ }
406
+ function extraCertsFromBundle() {
407
+ const path = process.env.NODE_EXTRA_CA_CERTS?.trim();
408
+ if (path) return splitPemCertificates(readExistingFile(path));
409
+ const dest = systemCaBundlePath();
410
+ return splitPemCertificates(readExistingFile(dest));
411
+ }
412
+ function trustSystemCertificates(io = {}) {
413
+ try {
414
+ const api = tls;
415
+ if (typeof api.getCACertificates !== "function" || typeof api.setDefaultCACertificates !== "function") {
416
+ return false;
417
+ }
418
+ const current = api.getCACertificates("default");
419
+ const system = api.getCACertificates("system");
420
+ let extra = extraCertsFromBundle();
421
+ if (system.length === 0 && extra.length === 0) {
422
+ extra = splitPemCertificates(collectSystemCaPem(io));
423
+ }
424
+ if (system.length === 0 && extra.length === 0) return false;
425
+ api.setDefaultCACertificates([...current, ...system, ...extra]);
426
+ return true;
427
+ } catch {
428
+ return false;
429
+ }
430
+ }
431
+
304
432
  // src/agents/node-launch.ts
305
- import { existsSync as existsSync2, readdirSync, realpathSync } from "fs";
433
+ import { existsSync as existsSync3, readdirSync, realpathSync } from "fs";
306
434
  import { homedir } from "os";
307
- import { join as join2 } from "path";
435
+ import { join as join3 } from "path";
308
436
 
309
437
  // src/agents/packaged-runtime.ts
310
- import { existsSync } from "fs";
311
- import { join } from "path";
438
+ import { existsSync as existsSync2 } from "fs";
439
+ import { join as join2 } from "path";
312
440
  function electronResourcesPath() {
313
441
  const resources = process.resourcesPath;
314
442
  if (typeof resources !== "string" || !resources) return null;
@@ -317,36 +445,36 @@ function electronResourcesPath() {
317
445
  function packagedCursorRuntimeDir() {
318
446
  const resources = electronResourcesPath();
319
447
  if (!resources) return null;
320
- const dir = join(resources, "cursor-runtime");
321
- if (!existsSync(join(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
448
+ const dir = join2(resources, "cursor-runtime");
449
+ if (!existsSync2(join2(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
322
450
  return dir;
323
451
  }
324
452
  function packagedCursorRunnerPath() {
325
453
  const dir = packagedCursorRuntimeDir();
326
- return dir ? join(dir, "core-dist", "agents", "cursor-runner.js") : null;
454
+ return dir ? join2(dir, "core-dist", "agents", "cursor-runner.js") : null;
327
455
  }
328
456
  function packagedMcpDir() {
329
457
  const resources = electronResourcesPath();
330
458
  if (!resources) return null;
331
- const dir = join(resources, "sideboard-mcp");
332
- if (!existsSync(join(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
459
+ const dir = join2(resources, "sideboard-mcp");
460
+ if (!existsSync2(join2(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
333
461
  return dir;
334
462
  }
335
463
  function packagedMcpStdioPath() {
336
464
  const dir = packagedMcpDir();
337
- return dir ? join(dir, "core-dist", "mcp", "run-stdio.js") : null;
465
+ return dir ? join2(dir, "core-dist", "mcp", "run-stdio.js") : null;
338
466
  }
339
467
  function packagedBundledNodePath() {
340
468
  const resources = electronResourcesPath();
341
469
  if (!resources) return null;
342
- const bin = join(resources, "node", "bin", "node");
343
- if (!existsSync(bin)) return null;
470
+ const bin = join2(resources, "node", "bin", "node");
471
+ if (!existsSync2(bin)) return null;
344
472
  return bin;
345
473
  }
346
474
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
347
475
  const dir = packagedCursorRuntimeDir();
348
476
  if (!dir) return null;
349
- return join(dir, "node_modules", platformPkg, "bin", binName);
477
+ return join2(dir, "node_modules", platformPkg, "bin", binName);
350
478
  }
351
479
 
352
480
  // src/agents/node-launch.ts
@@ -367,6 +495,7 @@ function applyAgentRunnerHeapEnv(env) {
367
495
  env.NODE_OPTIONS,
368
496
  AGENT_RUNNER_MAX_OLD_SPACE_MB
369
497
  );
498
+ applySystemCaEnv(env);
370
499
  }
371
500
  function envWithAgentHeap(env) {
372
501
  const next = { ...env };
@@ -381,7 +510,7 @@ function unpackedAsarPath(filePath) {
381
510
  if (!isAsarPath(filePath)) return null;
382
511
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
383
512
  if (unpacked === filePath) return null;
384
- return existsSync2(unpacked) ? unpacked : null;
513
+ return existsSync3(unpacked) ? unpacked : null;
385
514
  }
386
515
  function nodeReadableScriptPath(scriptPath) {
387
516
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -422,7 +551,7 @@ function pickPreferredNode(candidates) {
422
551
  return best;
423
552
  }
424
553
  function versionDirNodeBins(root, toBin) {
425
- if (!existsSync2(root)) return [];
554
+ if (!existsSync3(root)) return [];
426
555
  try {
427
556
  return readdirSync(root).map(toBin);
428
557
  } catch {
@@ -431,28 +560,28 @@ function versionDirNodeBins(root, toBin) {
431
560
  }
432
561
  function defaultNodeBinCandidates(home = homedir()) {
433
562
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
434
- (prefix) => PREFERRED_LTS_MAJORS.map((major) => join2(prefix, "opt", `node@${major}`, "bin", "node"))
563
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => join3(prefix, "opt", `node@${major}`, "bin", "node"))
435
564
  );
436
565
  return [
437
566
  ...kegs,
438
567
  "/opt/homebrew/bin/node",
439
568
  "/usr/local/bin/node",
440
- join2(home, ".local/share/fnm/aliases/default/bin/node"),
441
- join2(home, ".nvm/current/bin/node"),
442
- join2(home, ".volta/bin/node"),
443
- join2(home, ".asdf/shims/node"),
444
- join2(home, ".local/share/mise/shims/node"),
569
+ join3(home, ".local/share/fnm/aliases/default/bin/node"),
570
+ join3(home, ".nvm/current/bin/node"),
571
+ join3(home, ".volta/bin/node"),
572
+ join3(home, ".asdf/shims/node"),
573
+ join3(home, ".local/share/mise/shims/node"),
445
574
  ...versionDirNodeBins(
446
- join2(home, ".nvm", "versions", "node"),
447
- (name) => join2(home, ".nvm", "versions", "node", name, "bin", "node")
575
+ join3(home, ".nvm", "versions", "node"),
576
+ (name) => join3(home, ".nvm", "versions", "node", name, "bin", "node")
448
577
  ),
449
578
  ...versionDirNodeBins(
450
- join2(home, ".local/share/fnm", "node-versions"),
451
- (name) => join2(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
579
+ join3(home, ".local/share/fnm", "node-versions"),
580
+ (name) => join3(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
452
581
  ),
453
582
  ...versionDirNodeBins(
454
- join2(home, ".volta", "tools", "image", "node"),
455
- (name) => join2(home, ".volta", "tools", "image", "node", name, "bin", "node")
583
+ join3(home, ".volta", "tools", "image", "node"),
584
+ (name) => join3(home, ".volta", "tools", "image", "node", name, "bin", "node")
456
585
  )
457
586
  ];
458
587
  }
@@ -461,7 +590,7 @@ function uniqueExistingNodeBins(paths) {
461
590
  const out = [];
462
591
  for (const raw of paths) {
463
592
  const p = raw.trim();
464
- if (!p || !existsSync2(p) || isElectronLikeCommand(p)) continue;
593
+ if (!p || !existsSync3(p) || isElectronLikeCommand(p)) continue;
465
594
  let key = p;
466
595
  try {
467
596
  key = realpathSync(p);
@@ -854,9 +983,9 @@ function parseCursorRunnerLine(line) {
854
983
  }
855
984
 
856
985
  // src/agents/cursor-ripgrep.ts
857
- import { existsSync as existsSync3 } from "fs";
986
+ import { existsSync as existsSync4 } from "fs";
858
987
  import { createRequire } from "module";
859
- import { dirname, isAbsolute, join as join3, parse, resolve as resolvePath } from "path";
988
+ import { dirname as dirname2, isAbsolute, join as join4, parse, resolve as resolvePath } from "path";
860
989
  var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
861
990
  function rgBinaryName() {
862
991
  return process.platform === "win32" ? "rg.exe" : "rg";
@@ -868,19 +997,19 @@ function usableRipgrepPath(candidate) {
868
997
  const raw = candidate?.trim();
869
998
  if (!raw || !isAbsolute(raw)) return null;
870
999
  const readable = nodeReadableScriptPath(raw);
871
- if (!existsSync3(readable) || isAsarPath(readable)) return null;
1000
+ if (!existsSync4(readable) || isAsarPath(readable)) return null;
872
1001
  return readable;
873
1002
  }
874
1003
  function walkForBundledRipgrep(startFile) {
875
1004
  if (!startFile) return null;
876
1005
  const pkg = platformRipgrepPackage();
877
1006
  const name = rgBinaryName();
878
- let dir = dirname(resolvePath(startFile));
1007
+ let dir = dirname2(resolvePath(startFile));
879
1008
  const root = parse(dir).root;
880
1009
  while (dir !== root) {
881
- const hit = usableRipgrepPath(join3(dir, "node_modules", pkg, "bin", name));
1010
+ const hit = usableRipgrepPath(join4(dir, "node_modules", pkg, "bin", name));
882
1011
  if (hit) return hit;
883
- const next = dirname(dir);
1012
+ const next = dirname2(dir);
884
1013
  if (next === dir) break;
885
1014
  dir = next;
886
1015
  }
@@ -890,7 +1019,7 @@ function requireResolveBundledRipgrep(fromFile) {
890
1019
  try {
891
1020
  const req = createRequire(fromFile);
892
1021
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
893
- return usableRipgrepPath(join3(dirname(pkgJson), "bin", rgBinaryName()));
1022
+ return usableRipgrepPath(join4(dirname2(pkgJson), "bin", rgBinaryName()));
894
1023
  } catch {
895
1024
  return null;
896
1025
  }
@@ -934,6 +1063,9 @@ export {
934
1063
  shouldFeedErrorBackToAgent,
935
1064
  formatAgentErrorContinuePrompt,
936
1065
  formatTurnExitError,
1066
+ materializeSystemCaBundle,
1067
+ applySystemCaEnv,
1068
+ trustSystemCertificates,
937
1069
  packagedCursorRunnerPath,
938
1070
  packagedMcpDir,
939
1071
  packagedMcpStdioPath,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  httpFetch
3
- } from "./chunk-ELBYOGVA.js";
3
+ } from "./chunk-N7WZ6NIN.js";
4
4
  import {
5
5
  getAbleTimeAccessToken,
6
6
  getAbleTimeHost,
@@ -3,17 +3,26 @@
3
3
 
4
4
  // src/http/fetch.ts
5
5
  var injected = null;
6
+ var TLS_ISSUER_RE = /UNABLE_TO_GET_ISSUER_CERT|UNABLE_TO_VERIFY_LEAF_SIGNATURE|SELF_SIGNED_CERT_IN_CHAIN/i;
7
+ var TLS_ISSUER_HINT = " \u2014 Node rejected the TLS certificate (corporate VPN/proxy CA). Desktop Linear can still work; reconnecting the API key will not fix this.";
8
+ function tlsIssuerHint(code, message) {
9
+ const text = `${code ?? ""} ${message}`;
10
+ return TLS_ISSUER_RE.test(text) ? TLS_ISSUER_HINT : "";
11
+ }
6
12
  function formatFetchError(err, url) {
7
13
  if (!(err instanceof Error)) return `${String(err)} (${url})`;
8
14
  const cause = err.cause;
9
15
  let detail = "";
16
+ let hint = tlsIssuerHint(void 0, err.message);
10
17
  if (cause instanceof Error) {
11
18
  const code = typeof cause.code === "string" ? cause.code : void 0;
12
19
  detail = code ? ` [${code}: ${cause.message}]` : ` [${cause.message}]`;
20
+ hint = tlsIssuerHint(code, `${err.message} ${cause.message}`) || hint;
13
21
  } else if (cause != null) {
14
22
  detail = ` [${String(cause)}]`;
23
+ hint = tlsIssuerHint(void 0, String(cause)) || hint;
15
24
  }
16
- return `${err.message}${detail} (${url})`;
25
+ return `${err.message}${detail} (${url})${hint}`;
17
26
  }
18
27
  async function httpFetch(input, init) {
19
28
  const url = typeof input === "string" ? input : input.href;