@sideboard-ai/core 0.1.9 → 0.1.15

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/index.cjs CHANGED
@@ -1357,6 +1357,59 @@ var init_worktree_labels = __esm({
1357
1357
  }
1358
1358
  });
1359
1359
 
1360
+ // src/git/gh-errors.ts
1361
+ function isGhRateLimitError(text) {
1362
+ return /API rate limit (already )?exceeded/i.test(text) || /rate limit exceeded/i.test(text);
1363
+ }
1364
+ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
1365
+ const ms = resetEpochSec * 1e3 - nowMs;
1366
+ if (ms <= 0) return "soon";
1367
+ const mins = Math.max(1, Math.ceil(ms / 6e4));
1368
+ if (mins < 60) {
1369
+ return `in about ${mins} minute${mins === 1 ? "" : "s"}`;
1370
+ }
1371
+ const hours = Math.ceil(mins / 60);
1372
+ return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
1373
+ }
1374
+ function extractGhErrorDetail(text) {
1375
+ const trimmed = text.trim();
1376
+ if (!trimmed) return "";
1377
+ const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
1378
+ if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}`;
1379
+ const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
1380
+ if (http?.[1]) return `HTTP: ${http[1].trim()}`;
1381
+ const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
1382
+ if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
1383
+ return lines.slice(1).join(" ").trim() || lines[0];
1384
+ }
1385
+ return trimmed;
1386
+ }
1387
+ function formatGhLandError(raw, opts) {
1388
+ const trimmed = raw.trim();
1389
+ if (trimmed.startsWith("GitHub API rate limit exceeded.")) {
1390
+ return trimmed;
1391
+ }
1392
+ const detail = extractGhErrorDetail(raw);
1393
+ if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
1394
+ const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
1395
+ const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
1396
+ return `GitHub API rate limit exceeded.${pushNote}${when} Or create the pull request in the browser (Push & open on GitHub).`;
1397
+ }
1398
+ return detail || "Failed to create or update pull request";
1399
+ }
1400
+ function formatIpcInvokeError(err) {
1401
+ let msg = err instanceof Error ? err.message : String(err);
1402
+ msg = msg.replace(/^Error invoking remote method '[^']+':\s*/i, "");
1403
+ msg = msg.replace(/^ExecaError:\s*/i, "");
1404
+ msg = msg.replace(/^Error:\s*/i, "");
1405
+ return formatGhLandError(msg);
1406
+ }
1407
+ var init_gh_errors = __esm({
1408
+ "src/git/gh-errors.ts"() {
1409
+ "use strict";
1410
+ }
1411
+ });
1412
+
1360
1413
  // src/agents/path.ts
1361
1414
  function ensureAgentPath(env = process.env) {
1362
1415
  const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
@@ -1551,6 +1604,7 @@ __export(worktree_exports, {
1551
1604
  getPr: () => getPr,
1552
1605
  getPrChecks: () => getPrChecks,
1553
1606
  getPrDetails: () => getPrDetails,
1607
+ getPrMeta: () => getPrMeta,
1554
1608
  isDirty: () => isDirty,
1555
1609
  isPlaceholderBranch: () => isPlaceholderBranch,
1556
1610
  listBranches: () => listBranches,
@@ -1574,6 +1628,24 @@ __export(worktree_exports, {
1574
1628
  worktreeDisplayLabelForGroup: () => worktreeDisplayLabelForGroup,
1575
1629
  worktreeNameFromPath: () => worktreeNameFromPath
1576
1630
  });
1631
+ async function lookupGithubGraphqlReset(cwd) {
1632
+ const result = await gh(["api", "rate_limit"], cwd, { reject: false });
1633
+ if (result.exitCode !== 0 || !result.stdout.trim()) return void 0;
1634
+ try {
1635
+ const data = JSON.parse(result.stdout);
1636
+ const reset = data.resources?.graphql?.reset;
1637
+ return typeof reset === "number" ? reset : void 0;
1638
+ } catch {
1639
+ return void 0;
1640
+ }
1641
+ }
1642
+ async function formatPrCreateFailure(raw, cwd) {
1643
+ if (!isGhRateLimitError(raw)) {
1644
+ return formatGhLandError(raw);
1645
+ }
1646
+ const resetAt = await lookupGithubGraphqlReset(cwd);
1647
+ return formatGhLandError(raw, { resetAt });
1648
+ }
1577
1649
  function slugify(input) {
1578
1650
  return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
1579
1651
  }
@@ -1888,6 +1960,37 @@ async function getPrChecks(cwd, selector) {
1888
1960
  });
1889
1961
  return [...gateRows, ...ciChecks];
1890
1962
  }
1963
+ async function getPrMeta(cwd, selector) {
1964
+ const slug = await resolveGithubRepoSlug(cwd);
1965
+ const viewArgs = [
1966
+ "pr",
1967
+ "view",
1968
+ selector,
1969
+ "--json",
1970
+ "number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName"
1971
+ ];
1972
+ if (slug) viewArgs.push("--repo", slug);
1973
+ const { stdout, exitCode, stderr } = await gh(viewArgs, cwd, { reject: false });
1974
+ if (exitCode !== 0 || !stdout.trim()) {
1975
+ if (/no pull requests found/i.test(stderr)) return null;
1976
+ return null;
1977
+ }
1978
+ try {
1979
+ const view = JSON.parse(stdout);
1980
+ return {
1981
+ number: Number(view.number),
1982
+ title: String(view.title ?? ""),
1983
+ url: String(view.url ?? ""),
1984
+ state: String(view.state ?? ""),
1985
+ isDraft: Boolean(view.isDraft),
1986
+ reviewDecision: typeof view.reviewDecision === "string" && view.reviewDecision ? view.reviewDecision : null,
1987
+ baseRefName: String(view.baseRefName ?? ""),
1988
+ headRefName: String(view.headRefName ?? "")
1989
+ };
1990
+ } catch {
1991
+ return null;
1992
+ }
1993
+ }
1891
1994
  async function getPrDetails(cwd, selector) {
1892
1995
  const slug = await resolveGithubRepoSlug(cwd);
1893
1996
  const viewArgs = [
@@ -1909,7 +2012,6 @@ async function getPrDetails(cwd, selector) {
1909
2012
  "additions",
1910
2013
  "deletions",
1911
2014
  "changedFiles",
1912
- "commits",
1913
2015
  "comments",
1914
2016
  "reviews"
1915
2017
  ].join(",")
@@ -1928,14 +2030,7 @@ async function getPrDetails(cwd, selector) {
1928
2030
  } catch {
1929
2031
  throw new Error(stderr.trim() || "gh pr view returned invalid JSON");
1930
2032
  }
1931
- let checks = [];
1932
- try {
1933
- checks = await getPrChecks(cwd, selector) ?? [];
1934
- } catch {
1935
- checks = [];
1936
- }
1937
2033
  const author = view.author ?? {};
1938
- const commits = Array.isArray(view.commits) ? view.commits : [];
1939
2034
  const comments = Array.isArray(view.comments) ? view.comments : [];
1940
2035
  const reviews = Array.isArray(view.reviews) ? view.reviews : [];
1941
2036
  return {
@@ -1952,19 +2047,8 @@ async function getPrDetails(cwd, selector) {
1952
2047
  additions: Number(view.additions ?? 0),
1953
2048
  deletions: Number(view.deletions ?? 0),
1954
2049
  changedFiles: Number(view.changedFiles ?? 0),
1955
- commits: commits.map((c) => {
1956
- const row = c;
1957
- const authors = Array.isArray(row.authors) ? row.authors.map((a) => {
1958
- const actor = a;
1959
- return { login: actor.login ?? "unknown", name: actor.name ?? null };
1960
- }) : [];
1961
- return {
1962
- oid: String(row.oid ?? ""),
1963
- messageHeadline: String(row.messageHeadline ?? ""),
1964
- committedDate: String(row.committedDate ?? ""),
1965
- authors
1966
- };
1967
- }),
2050
+ // Commits live in Changes; omit from GraphQL to save rate-limit points.
2051
+ commits: [],
1968
2052
  comments: comments.map((c) => {
1969
2053
  const row = c;
1970
2054
  const a = row.author ?? {};
@@ -1984,7 +2068,8 @@ async function getPrDetails(cwd, selector) {
1984
2068
  submittedAt: normalizeGhTime(row.submittedAt)
1985
2069
  };
1986
2070
  }),
1987
- checks
2071
+ // CI lives in Checks tab via getPrChecks — nesting burned GraphQL points.
2072
+ checks: []
1988
2073
  };
1989
2074
  }
1990
2075
  async function fetchPrHead(repoPath, number, localBranch) {
@@ -2214,8 +2299,12 @@ async function createOrUpdatePr(worktreePath, opts) {
2214
2299
  opts.head
2215
2300
  ];
2216
2301
  if (opts.draft) args.push("--draft");
2217
- const { stdout } = await gh(args, worktreePath);
2218
- const url = stdout.trim().split("\n").find((l) => l.startsWith("http")) ?? stdout.trim();
2302
+ const created = await gh(args, worktreePath, { reject: false });
2303
+ if (created.exitCode !== 0) {
2304
+ const raw = created.stderr.trim() || created.stdout.trim() || "gh pr create failed";
2305
+ throw new Error(await formatPrCreateFailure(raw, worktreePath));
2306
+ }
2307
+ const url = created.stdout.trim().split("\n").find((l) => l.startsWith("http")) ?? created.stdout.trim();
2219
2308
  return url;
2220
2309
  }
2221
2310
  function suggestSlug(source) {
@@ -2276,6 +2365,7 @@ var init_worktree = __esm({
2276
2365
  init_thread_store();
2277
2366
  init_teams();
2278
2367
  init_worktree_labels();
2368
+ init_gh_errors();
2279
2369
  init_run();
2280
2370
  init_pr_gates();
2281
2371
  init_teams();
@@ -2596,6 +2686,9 @@ __export(workspaces_exports, {
2596
2686
  function workspacesFile() {
2597
2687
  return (0, import_node_path8.join)(appDataDir(), "workspaces.json");
2598
2688
  }
2689
+ function removedWorkspacesFile() {
2690
+ return (0, import_node_path8.join)(appDataDir(), "removed-workspaces.json");
2691
+ }
2599
2692
  function readAll() {
2600
2693
  const path = workspacesFile();
2601
2694
  if (!(0, import_node_fs7.existsSync)(path)) return [];
@@ -2610,12 +2703,41 @@ function writeAll(list) {
2610
2703
  (0, import_node_fs7.mkdirSync)(appDataDir(), { recursive: true });
2611
2704
  (0, import_node_fs7.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
2612
2705
  }
2706
+ function readRemoved() {
2707
+ const path = removedWorkspacesFile();
2708
+ if (!(0, import_node_fs7.existsSync)(path)) return /* @__PURE__ */ new Set();
2709
+ try {
2710
+ const raw = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf8"));
2711
+ return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
2712
+ } catch {
2713
+ return /* @__PURE__ */ new Set();
2714
+ }
2715
+ }
2716
+ function writeRemoved(paths) {
2717
+ (0, import_node_fs7.mkdirSync)(appDataDir(), { recursive: true });
2718
+ (0, import_node_fs7.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
2719
+ }
2720
+ function rememberRemoved(repoPath) {
2721
+ const next = readRemoved();
2722
+ next.add(repoPath);
2723
+ writeRemoved(next);
2724
+ }
2725
+ function forgetRemoved(repoPath) {
2726
+ const next = readRemoved();
2727
+ if (!next.delete(repoPath)) return;
2728
+ writeRemoved(next);
2729
+ }
2613
2730
  function listWorkspaces() {
2614
- return readAll().sort((a, b) => a.name.localeCompare(b.name));
2731
+ const all = readAll();
2732
+ const valid = all.filter((w) => Boolean(w.path) && w.path !== "/" && w.path !== ".");
2733
+ if (valid.length !== all.length) writeAll(valid);
2734
+ return valid.sort((a, b) => a.name.localeCompare(b.name));
2615
2735
  }
2616
2736
  async function addWorkspace(repoPath) {
2617
2737
  const root = await resolveRepoRoot(repoPath);
2738
+ if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
2618
2739
  if (!(0, import_node_fs7.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
2740
+ forgetRemoved(root);
2619
2741
  const current = readAll();
2620
2742
  const existing = current.find((w) => w.path === root);
2621
2743
  if (existing) return existing;
@@ -2629,16 +2751,20 @@ async function addWorkspace(repoPath) {
2629
2751
  }
2630
2752
  function removeWorkspace(repoPath) {
2631
2753
  writeAll(readAll().filter((w) => w.path !== repoPath));
2754
+ rememberRemoved(repoPath);
2632
2755
  }
2633
2756
  async function ensureWorkspace(repoPath) {
2634
2757
  return addWorkspace(repoPath);
2635
2758
  }
2636
2759
  function syncWorkspacesFromThreads(repoPaths) {
2637
2760
  const current = readAll();
2761
+ const removed = readRemoved();
2638
2762
  const byPath = new Map(current.map((w) => [w.path, w]));
2639
2763
  let dirty = false;
2640
2764
  for (const path of repoPaths) {
2641
- if (!path || isGlobalRepoPath(path) || byPath.has(path)) continue;
2765
+ if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
2766
+ continue;
2767
+ }
2642
2768
  if (!(0, import_node_fs7.existsSync)(path)) continue;
2643
2769
  const ws = {
2644
2770
  path,
@@ -4688,6 +4814,7 @@ __export(index_exports, {
4688
4814
  estimateMessageChars: () => estimateMessageChars,
4689
4815
  estimateThreadChars: () => estimateThreadChars,
4690
4816
  expandComposerPrompt: () => expandComposerPrompt,
4817
+ extractGhErrorDetail: () => extractGhErrorDetail,
4691
4818
  extractiveSummary: () => extractiveSummary,
4692
4819
  fetchPrHead: () => fetchPrHead,
4693
4820
  finalizeParts: () => finalizeParts,
@@ -4700,7 +4827,10 @@ __export(index_exports, {
4700
4827
  forkThreadWorktree: () => forkThreadWorktree,
4701
4828
  formatAgentInstructions: () => formatAgentInstructions,
4702
4829
  formatBrightsyFetchError: () => formatBrightsyFetchError,
4830
+ formatGhLandError: () => formatGhLandError,
4831
+ formatIpcInvokeError: () => formatIpcInvokeError,
4703
4832
  formatMessagesAsTranscript: () => formatMessagesAsTranscript,
4833
+ formatRateLimitResetHint: () => formatRateLimitResetHint,
4704
4834
  formatRenameBranchDirective: () => formatRenameBranchDirective,
4705
4835
  formatTranscriptMarkdown: () => formatTranscriptMarkdown,
4706
4836
  formatWorkspaceInventory: () => formatWorkspaceInventory,
@@ -4717,6 +4847,7 @@ __export(index_exports, {
4717
4847
  getPr: () => getPr,
4718
4848
  getPrChecks: () => getPrChecks,
4719
4849
  getPrDetails: () => getPrDetails,
4850
+ getPrMeta: () => getPrMeta,
4720
4851
  getRepoSetupInfo: () => getRepoSetupInfo,
4721
4852
  getRunMode: () => getRunMode,
4722
4853
  getRunScript: () => getRunScript,
@@ -4737,6 +4868,7 @@ __export(index_exports, {
4737
4868
  isBrightsyNdjsonLine: () => isBrightsyNdjsonLine,
4738
4869
  isCloudCoordinatorThread: () => isCloudCoordinatorThread,
4739
4870
  isDirty: () => isDirty,
4871
+ isGhRateLimitError: () => isGhRateLimitError,
4740
4872
  isGlobalRepoPath: () => isGlobalRepoPath,
4741
4873
  isGlobalThread: () => isGlobalThread,
4742
4874
  isLinearConnected: () => isLinearConnected,
@@ -4870,6 +5002,7 @@ init_thread_store();
4870
5002
  init_workspaces();
4871
5003
  init_global_workspace();
4872
5004
  init_run();
5005
+ init_gh_errors();
4873
5006
  init_worktree();
4874
5007
 
4875
5008
  // src/integrations/github.ts
@@ -6954,6 +7087,7 @@ async function suggestPrMetadata(worktreePath, opts) {
6954
7087
  }
6955
7088
 
6956
7089
  // src/land/land.ts
7090
+ init_gh_errors();
6957
7091
  async function previewLand(thread) {
6958
7092
  if (thread.sourceIsFork) {
6959
7093
  return {
@@ -7017,15 +7151,24 @@ async function confirmLand(thread, opts) {
7017
7151
  const head = headOut.trim();
7018
7152
  const branch = head && head !== "HEAD" ? head : thread.branchName;
7019
7153
  await pushBranch(thread.worktreePath, branch);
7020
- const prUrl = await createOrUpdatePr(thread.worktreePath, {
7021
- title: meta.title,
7022
- body: meta.body,
7023
- base: preview.target,
7024
- head: branch,
7025
- draft: opts?.draft,
7026
- web: opts?.web
7027
- });
7028
- return { prUrl, pushed: true, committed };
7154
+ try {
7155
+ const prUrl = await createOrUpdatePr(thread.worktreePath, {
7156
+ title: meta.title,
7157
+ body: meta.body,
7158
+ base: preview.target,
7159
+ head: branch,
7160
+ draft: opts?.draft,
7161
+ web: opts?.web
7162
+ });
7163
+ return { prUrl, pushed: true, committed };
7164
+ } catch (err) {
7165
+ const raw = err instanceof Error ? err.message : String(err);
7166
+ if (raw.startsWith("GitHub API rate limit exceeded.")) throw err;
7167
+ if (/Command failed with exit code|API rate limit/i.test(raw)) {
7168
+ throw new Error(formatGhLandError(raw));
7169
+ }
7170
+ throw err;
7171
+ }
7029
7172
  }
7030
7173
 
7031
7174
  // src/threads/create.ts
@@ -7923,7 +8066,7 @@ var Orchestrator = class {
7923
8066
  return thread;
7924
8067
  }
7925
8068
  listWorkspaces() {
7926
- const fromThreads = listThreads({ includeArchived: true }).map((t) => t.repoPath);
8069
+ const fromThreads = listThreads({ includeArchived: false }).map((t) => t.repoPath);
7927
8070
  return syncWorkspacesFromThreads(fromThreads);
7928
8071
  }
7929
8072
  async addWorkspace(repoPath) {
@@ -8540,8 +8683,8 @@ var Orchestrator = class {
8540
8683
  if (result.prUrl) {
8541
8684
  const patch = { prUrl: result.prUrl };
8542
8685
  try {
8543
- const details = await getPrDetails(thread.worktreePath, result.prUrl);
8544
- if (details?.title) patch.prTitle = details.title;
8686
+ const meta = await getPrMeta(thread.worktreePath, result.prUrl);
8687
+ if (meta?.title) patch.prTitle = meta.title;
8545
8688
  } catch {
8546
8689
  }
8547
8690
  updateThread(thread.id, patch);
@@ -8574,6 +8717,24 @@ var Orchestrator = class {
8574
8717
  if (!selector) return null;
8575
8718
  return getPrChecks(cwd, selector);
8576
8719
  }
8720
+ async getPrMeta(threadRef) {
8721
+ const { thread, selector, cwd } = await this.withPrSelector(threadRef);
8722
+ if (!selector) return null;
8723
+ const meta = await getPrMeta(cwd, selector);
8724
+ if (meta) {
8725
+ const patch = {};
8726
+ if (meta.url && meta.url !== thread.prUrl) patch.prUrl = meta.url;
8727
+ if (meta.title && meta.title !== thread.prTitle) patch.prTitle = meta.title;
8728
+ if (Object.keys(patch).length > 0) {
8729
+ updateThread(thread.id, patch);
8730
+ const latest = this.requireThread(thread.id);
8731
+ if (!latest.userSetTitle && meta.title && latest.title !== meta.title) {
8732
+ updateThread(thread.id, { title: meta.title });
8733
+ }
8734
+ }
8735
+ }
8736
+ return meta;
8737
+ }
8577
8738
  async getPrDetails(threadRef) {
8578
8739
  const { thread, selector, cwd } = await this.withPrSelector(threadRef);
8579
8740
  if (!selector) return null;
@@ -9763,6 +9924,7 @@ init_injected_mcp();
9763
9924
  estimateMessageChars,
9764
9925
  estimateThreadChars,
9765
9926
  expandComposerPrompt,
9927
+ extractGhErrorDetail,
9766
9928
  extractiveSummary,
9767
9929
  fetchPrHead,
9768
9930
  finalizeParts,
@@ -9775,7 +9937,10 @@ init_injected_mcp();
9775
9937
  forkThreadWorktree,
9776
9938
  formatAgentInstructions,
9777
9939
  formatBrightsyFetchError,
9940
+ formatGhLandError,
9941
+ formatIpcInvokeError,
9778
9942
  formatMessagesAsTranscript,
9943
+ formatRateLimitResetHint,
9779
9944
  formatRenameBranchDirective,
9780
9945
  formatTranscriptMarkdown,
9781
9946
  formatWorkspaceInventory,
@@ -9792,6 +9957,7 @@ init_injected_mcp();
9792
9957
  getPr,
9793
9958
  getPrChecks,
9794
9959
  getPrDetails,
9960
+ getPrMeta,
9795
9961
  getRepoSetupInfo,
9796
9962
  getRunMode,
9797
9963
  getRunScript,
@@ -9812,6 +9978,7 @@ init_injected_mcp();
9812
9978
  isBrightsyNdjsonLine,
9813
9979
  isCloudCoordinatorThread,
9814
9980
  isDirty,
9981
+ isGhRateLimitError,
9815
9982
  isGlobalRepoPath,
9816
9983
  isGlobalThread,
9817
9984
  isLinearConnected,
package/dist/index.d.cts CHANGED
@@ -193,8 +193,20 @@ interface PrDetails {
193
193
  commits: PrCommitInfo[];
194
194
  comments: PrCommentInfo[];
195
195
  reviews: PrReviewInfo[];
196
+ /** Prefer `getPrChecks` — kept for callers; often empty to avoid nested GraphQL. */
196
197
  checks: PrCheckRun[];
197
198
  }
199
+ /** Lightweight PR fields for the sidebar pill (cheap GraphQL). */
200
+ interface PrMeta {
201
+ number: number;
202
+ title: string;
203
+ url: string;
204
+ state: string;
205
+ isDraft: boolean;
206
+ reviewDecision: string | null;
207
+ baseRefName: string;
208
+ headRefName: string;
209
+ }
198
210
  interface IssueInfo {
199
211
  id: string;
200
212
  identifier: string;
@@ -668,6 +680,29 @@ declare function gh(args: string[], cwd: string, opts?: {
668
680
  exitCode: number;
669
681
  }>;
670
682
 
683
+ /** Detect GitHub API / GraphQL rate-limit failures in gh CLI output. */
684
+ declare function isGhRateLimitError(text: string): boolean;
685
+ /** Relative wait hint from a Unix epoch reset timestamp (seconds). */
686
+ declare function formatRateLimitResetHint(resetEpochSec: number, nowMs?: number): string;
687
+ /**
688
+ * Prefer the trailing GraphQL/HTTP detail over the full `gh` command line
689
+ * (which can include a huge --body payload).
690
+ */
691
+ declare function extractGhErrorDetail(text: string): string;
692
+ type FormatGhLandErrorOptions = {
693
+ /** Unix epoch seconds when the GraphQL/core quota resets. */
694
+ resetAt?: number;
695
+ /** Land push already succeeded before PR create failed. Default true for PR-create path. */
696
+ pushed?: boolean;
697
+ nowMs?: number;
698
+ };
699
+ /**
700
+ * Turn noisy `gh pr create` / Execa failures into a short notice for UI/CLI.
701
+ */
702
+ declare function formatGhLandError(raw: string, opts?: FormatGhLandErrorOptions): string;
703
+ /** Strip Electron's IPC invoke wrapper, then humanize known gh failures. */
704
+ declare function formatIpcInvokeError(err: unknown): string;
705
+
671
706
  /**
672
707
  * Memorable worktree / thread labels (Conductor-style nicknames).
673
708
  * Slug is the directory + `thread/<slug>` branch; `name` is the UI title.
@@ -768,7 +803,9 @@ declare function detectLocalMergeConflicts(cwd: string, baseRefName: string | nu
768
803
  * Returns `null` when no PR exists for the selector (so UI can show “link a PR”
769
804
  * instead of “no checks yet”). Returns `[]` when a PR exists but has no checks. */
770
805
  declare function getPrChecks(cwd: string, selector: string): Promise<PrCheckRun[] | null>;
771
- /** PR description / commits / reviews (+ checks) for the Review tab. */
806
+ /** Lightweight PR fields for the sidebar pill avoids nested reviews/checks GraphQL. */
807
+ declare function getPrMeta(cwd: string, selector: string): Promise<PrMeta | null>;
808
+ /** PR description / reviews for the Review tab (no nested CI — use getPrChecks). */
772
809
  declare function getPrDetails(cwd: string, selector: string): Promise<PrDetails | null>;
773
810
  declare function fetchPrHead(repoPath: string, number: number, localBranch: string): Promise<void>;
774
811
  interface CreateWorktreeResult {
@@ -1712,6 +1749,7 @@ declare class Orchestrator {
1712
1749
  /** Resolve PR selector and optionally persist `prUrl` when found. */
1713
1750
  private withPrSelector;
1714
1751
  getPrChecks(threadRef: string): Promise<PrCheckRun[] | null>;
1752
+ getPrMeta(threadRef: string): Promise<PrMeta | null>;
1715
1753
  getPrDetails(threadRef: string): Promise<PrDetails | null>;
1716
1754
  setAutonomy(threadRef: string, autonomy: Autonomy): Thread;
1717
1755
  setThreadOptions(threadRef: string, patch: ThreadOptionsPatch): Thread;
@@ -1967,7 +2005,9 @@ interface IpcApi {
1967
2005
  initializeGit(threadRef: string): Promise<void>;
1968
2006
  /** CI checks for the thread's linked PR (`gh pr checks`). `null` = no PR. */
1969
2007
  getPrChecks(threadRef: string): Promise<PrCheckRun[] | null>;
1970
- /** PR description / commits / reviews for the Review tab. */
2008
+ /** Lightweight PR fields for the sidebar pill (cheap GraphQL). */
2009
+ getPrMeta(threadRef: string): Promise<PrMeta | null>;
2010
+ /** PR description / reviews for the Review tab. */
1971
2011
  getPrDetails(threadRef: string): Promise<PrDetails | null>;
1972
2012
  listFiles(threadRef: string): Promise<string[]>;
1973
2013
  readFile(threadRef: string, relativePath: string): Promise<{
@@ -2112,6 +2152,33 @@ interface IpcApi {
2112
2152
  exitCode: number | null;
2113
2153
  }>;
2114
2154
  openExternal(url: string): Promise<void>;
2155
+ /**
2156
+ * In-app URL preview via BrowserView (top-level navigation — works for
2157
+ * sites that block iframes, e.g. GitHub).
2158
+ */
2159
+ urlPreview: {
2160
+ show(opts: {
2161
+ url: string;
2162
+ bounds: {
2163
+ x: number;
2164
+ y: number;
2165
+ width: number;
2166
+ height: number;
2167
+ };
2168
+ }): Promise<void>;
2169
+ setBounds(bounds: {
2170
+ x: number;
2171
+ y: number;
2172
+ width: number;
2173
+ height: number;
2174
+ }): Promise<void>;
2175
+ navigate(url: string): Promise<void>;
2176
+ reload(): Promise<void>;
2177
+ hide(): Promise<void>;
2178
+ onNavigated(listener: (payload: {
2179
+ url: string;
2180
+ }) => void): () => void;
2181
+ };
2115
2182
  /** Main-process tsserver for real import/type diagnostics in the file UI. */
2116
2183
  tsserver: {
2117
2184
  start(worktreePath?: string): Promise<{
@@ -2281,4 +2348,4 @@ declare function writeInjectedMcpConfig(opts: {
2281
2348
  includeBrightsy?: boolean;
2282
2349
  }): Promise<string | null>;
2283
2350
 
2284
- export { type ActiveRun, type AdoptInput, type AdvancedAppSettings, type AgentAdapter, type AgentEvent, type AgentInstructionFile, type AgentKind, type AgentStatus, type AgentTurnInput, type AnthropicCacheControl, type AppSettings, type ApplyIntoMainResult, type AttachCommand, type Autonomy, BRIGHTSY_MCP_ALLOWED_TOOLS, type BranchInfo, type BrightsyAccount, type BrightsyChatTarget, type BrightsyChatTargets, type BrightsyCloudConnectAgent, type BrightsyHarnessSettings, type BrightsySession, BrightsySideboardApi, type BrightsyTeamTargets, CLOUD_COORDINATOR_BUSY_REPLY, CLOUD_COORDINATOR_STOPPED_REPLY, CLOUD_COORDINATOR_TIMEOUT_REPLY, CLOUD_ORCHESTRATOR_GOAL, CONTEXT_COMPACT_CHARS, CONTEXT_KEEP_RECENT_CHARS, CONTEXT_KEEP_RECENT_MESSAGES, CONTEXT_MIN_MESSAGES, COORDINATOR_TOOL_PLAYBOOK, type ClaudeHarnessSettings, type CleanupOrphansResult, type CloudConnectAgent, type CloudConnectOptions, type CloudConnectStatus, type CompactResult, type CompactThresholds, type ConductorSettings, type ConductorWorkspace, type ConnectedBrightsyTeamInfo, type CreateChatTabInput, type CreateGlobalChatOpts, type CreateThreadInput, type CreateWorktreeResult, type CursorSdkStreamMessage, type CursorTurnRequest, type CursorWorktreesConfig, type DevServerHandle, type DiffCommit, type DiffFile, type DiffResult, type DiffScope, type DiffScopeStat, type ExpandResult, FAMOUS_SOCCER_TEAMS, type ForkChatTabInput, type ForkThreadWorktreeInput, GLOBAL_WORKSPACE_ID, type GetDiffOptions, type GitHubStatus, type GitWorktreeStatus, HARNESS_ENV_KEYS, type HarnessId, type IntegrationsSettings, type IpcApi, type IssueInfo, type IssueSource, type LandPreview, type LandResult, type ListIssuesResult, MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS, type McpServerStatus, type MessagePart, Orchestrator, type OrchestratorEvent, type OrchestratorRuntime, type OrphanWorktree, PLAN_MODE_INSTRUCTION, type PrActor, type PrCheckRun, type PrCommentInfo, type PrCommitInfo, type PrDetails, type PrInfo, type PrReviewInfo, type RepoSettings, type RepoSetupInfo, type RunMode, type RunScript, SIDEBOARD_FORCE_STOP, SIDEBOARD_MCP_ALLOWED_TOOLS, type ScriptHandle, type SkillInfo, type SourceType, type SpawnTurnHandle, type SummarizeResult, type TeamName, type Thread, type ThreadAttachment, type ThreadMessage, type ThreadOptionsPatch, type ThreadStatus, type TokenUsage, type TranscriptToolDetail, type TurnCommand, type Workspace, type WorkspaceInventoryEntry, type WorkspaceScriptEnvOpts, addWorkspace, adoptThread, allAdapters, allocatePort, allocatePortRange, allocateTeamName, allocateTeamSlug, appDataDir, appSettingsPath, appendMessage, applyAgentEvent, applyAppEnvironment, applyCompaction, applyThreadIntoMain, autoCleanupOrphansEnabled, autoRenameBranchEnabled, autoRunAfterSetupEnabled, branchDisplayLabel, brightsyAdapter, brightsyCloudConnectAgent, brightsyCloudConnectEnabled, brightsyConfigPath, brightsyMcpAllowedTools, brightsyMcpServerName, buildCachedUserContent, buildClaudeStreamJsonUserMessage, buildForkTranscriptAttachment, buildSessionSeed, buildWorkspaceScriptEnv, caffeinateWhileCloudConnectEnabled, caffeinateWhileRunningEnabled, captureLoginEnv, captureTurnBaseline, childEnvWithAppSettings, claudeAdapter, claudeChromeEnabled, claudeUserSettingsPath, cleanupOrphanWorktrees, cloneRepoIntoSideboard, codexAdapter, collectTakenTeamSlugs, commitAll, conductorDbPath, confirmLand, connectBrightsyTeam, coordinatorSystemPrompt, coordinatorTurnReminder, copyConfiguredFiles, countCacheControlBlocks, createChatTab, createEmptyThread, createGlobalChat, createOrUpdatePr, createThread, createThreadWorktree, currentBranch, cursorAdapter, cursorSdkMessageToEvents, decodeBrightsyTarget, deleteBranchOnPurgeEnabled, deleteThreadRecord, detectAgents, detectLocalMergeConflicts, disconnectBrightsyTeam, discoverSkills, encodeBrightsyTarget, enrichWorkspacesWithGithub, ensureAgentPath, ensureCloudCoordinator, ensureGlobalCoordinatorCwd, ensureWorkspace, estimateMessageChars, estimateThreadChars, expandComposerPrompt, extractiveSummary, fetchPrHead, finalizeParts, findInvalidCacheControlTtlOrder, findOrphanWorktrees, findThreadByRef, flattenTurnInput, forkChatTab, forkMessageSlice, forkThreadWorktree, formatAgentInstructions, formatBrightsyFetchError, formatMessagesAsTranscript, formatRenameBranchDirective, formatTranscriptMarkdown, formatWorkspaceInventory, formatWorktreeDirective, getAdapter, getBrightsySession, getDefaultRunScript, getDiff, getDiffSummary, getGitHubStatus, getIssueSource, getLinearApiKey, getOrchestrator, getPr, getPrChecks, getPrDetails, getRepoSetupInfo, getRunMode, getRunScript, gh, git, globalAgentCwd, harnessEnvKey, hasConductorHook, hasCursorWorktreeSetup, hasRepoHook, hasWorkspaceHook, healOrchestrationSoccerTitles, importConductorWorkspace, importConductorWorkspaceAsync, initializeGitRepository, inspectGitWorktree, isBrightsyConnected, isBrightsyNdjsonLine, isCloudCoordinatorThread, isDirty, isGlobalRepoPath, isGlobalThread, isLinearConnected, isOrchestratorThread, isPlaceholderBranch, listBranchCommits, listBranches, listBrightsyAccounts, listBrightsyChatTargets, listConductorWorkspaces, listConnectedBrightsyTeams, listGitHubIssues, listGlobalThreads, listIssues, listLinearIssues, listLinearIssuesDirect, listPrs, listRunScripts, listThreads, listWorkspaces, listWorktreeFiles, listWorktrees, loadAgentInstructions, loadAppSettings, loadBrightsyConfig, loadConductorSettings, loadRepoSettings, loadWorkspaceSettings, locksDir, maxConcurrentAgents, maybeCompactContext, mcpAllowTools, mcpAuthWarnings, mergePr, mergeUsage, normalizeParseResult, normalizeThread, normalizeTurnInput, normalizeWorktreePath, opencodeAdapter, orchestrationTitleNeedsSoccerNickname, orchestratorSessionPoisonedByBuiltins, parseCursorRunnerLine, parseForceStopMessage, parseGithubSlugFromRemoteUrl, parseMcpList, partsToAssistantText, permissionMode, previewLand, pushBranch, readSkillBody, readThread, readWorktreeFile, readWorktreeInclude, refreshGitHubAuth, removeWorkspace, removeWorktree, repoSlug, requireAgent, resolveClaudeExecutable, resolveConductorCursorAgentId, resolveDefaultBranch, resolveDiffBaseRef, resolveEffectiveIssueSource, resolveFilesToCopy, resolveGithubRepoSlug, resolvePrSelector, resolveRepoRoot, resolveWorktreeStartPoint, run, runArchiveScript, runCloudConnect, runCursorWorktreeSetup, runSetupScript, sameWorktreePath, sanitizeMcpServerName, saveAppSettings, setStatus, settingsSourceLabel, shouldCompactContext, shouldRunWorktreeCleanup, sideboardHomeDir, sideboardReposDir, sideboardWorkspacesDir, slugify, spawnAgentTurn, splitForCompaction, startDevServer, startMcpServer, startOrchestration, stripBrightsyNdjsonNoise, suggestSlug, summarizeConversation, switchBrightsyAccount, syncWorkspacesFromThreads, takenTeamSlugsForChatTab, takenTeamSlugsForOrchestration, taskMessageText, threadDisplayLabel, threadFilePath, threadLockPath, threadsDir, threadsSharingWorktree, toolDescription, toolDetail, toolFilePath, totalTokens, updateAdvancedSettings, updateAppEnvironment, updateBrightsySettings, updateClaudeSettings, updateIntegrationsSettings, updateThread, validateLinearApiKey, withAgentInstructions, withThreadLock, workspaceSettingsSourceLabel, worktreeCleanupSettings, worktreeDisplayLabel, worktreeDisplayLabelForGroup, worktreeNameFromPath, worktreesRoot, writeInjectedMcpConfig, writeThread, writeWorktreeFile };
2351
+ export { type ActiveRun, type AdoptInput, type AdvancedAppSettings, type AgentAdapter, type AgentEvent, type AgentInstructionFile, type AgentKind, type AgentStatus, type AgentTurnInput, type AnthropicCacheControl, type AppSettings, type ApplyIntoMainResult, type AttachCommand, type Autonomy, BRIGHTSY_MCP_ALLOWED_TOOLS, type BranchInfo, type BrightsyAccount, type BrightsyChatTarget, type BrightsyChatTargets, type BrightsyCloudConnectAgent, type BrightsyHarnessSettings, type BrightsySession, BrightsySideboardApi, type BrightsyTeamTargets, CLOUD_COORDINATOR_BUSY_REPLY, CLOUD_COORDINATOR_STOPPED_REPLY, CLOUD_COORDINATOR_TIMEOUT_REPLY, CLOUD_ORCHESTRATOR_GOAL, CONTEXT_COMPACT_CHARS, CONTEXT_KEEP_RECENT_CHARS, CONTEXT_KEEP_RECENT_MESSAGES, CONTEXT_MIN_MESSAGES, COORDINATOR_TOOL_PLAYBOOK, type ClaudeHarnessSettings, type CleanupOrphansResult, type CloudConnectAgent, type CloudConnectOptions, type CloudConnectStatus, type CompactResult, type CompactThresholds, type ConductorSettings, type ConductorWorkspace, type ConnectedBrightsyTeamInfo, type CreateChatTabInput, type CreateGlobalChatOpts, type CreateThreadInput, type CreateWorktreeResult, type CursorSdkStreamMessage, type CursorTurnRequest, type CursorWorktreesConfig, type DevServerHandle, type DiffCommit, type DiffFile, type DiffResult, type DiffScope, type DiffScopeStat, type ExpandResult, FAMOUS_SOCCER_TEAMS, type ForkChatTabInput, type ForkThreadWorktreeInput, type FormatGhLandErrorOptions, GLOBAL_WORKSPACE_ID, type GetDiffOptions, type GitHubStatus, type GitWorktreeStatus, HARNESS_ENV_KEYS, type HarnessId, type IntegrationsSettings, type IpcApi, type IssueInfo, type IssueSource, type LandPreview, type LandResult, type ListIssuesResult, MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS, type McpServerStatus, type MessagePart, Orchestrator, type OrchestratorEvent, type OrchestratorRuntime, type OrphanWorktree, PLAN_MODE_INSTRUCTION, type PrActor, type PrCheckRun, type PrCommentInfo, type PrCommitInfo, type PrDetails, type PrInfo, type PrMeta, type PrReviewInfo, type RepoSettings, type RepoSetupInfo, type RunMode, type RunScript, SIDEBOARD_FORCE_STOP, SIDEBOARD_MCP_ALLOWED_TOOLS, type ScriptHandle, type SkillInfo, type SourceType, type SpawnTurnHandle, type SummarizeResult, type TeamName, type Thread, type ThreadAttachment, type ThreadMessage, type ThreadOptionsPatch, type ThreadStatus, type TokenUsage, type TranscriptToolDetail, type TurnCommand, type Workspace, type WorkspaceInventoryEntry, type WorkspaceScriptEnvOpts, addWorkspace, adoptThread, allAdapters, allocatePort, allocatePortRange, allocateTeamName, allocateTeamSlug, appDataDir, appSettingsPath, appendMessage, applyAgentEvent, applyAppEnvironment, applyCompaction, applyThreadIntoMain, autoCleanupOrphansEnabled, autoRenameBranchEnabled, autoRunAfterSetupEnabled, branchDisplayLabel, brightsyAdapter, brightsyCloudConnectAgent, brightsyCloudConnectEnabled, brightsyConfigPath, brightsyMcpAllowedTools, brightsyMcpServerName, buildCachedUserContent, buildClaudeStreamJsonUserMessage, buildForkTranscriptAttachment, buildSessionSeed, buildWorkspaceScriptEnv, caffeinateWhileCloudConnectEnabled, caffeinateWhileRunningEnabled, captureLoginEnv, captureTurnBaseline, childEnvWithAppSettings, claudeAdapter, claudeChromeEnabled, claudeUserSettingsPath, cleanupOrphanWorktrees, cloneRepoIntoSideboard, codexAdapter, collectTakenTeamSlugs, commitAll, conductorDbPath, confirmLand, connectBrightsyTeam, coordinatorSystemPrompt, coordinatorTurnReminder, copyConfiguredFiles, countCacheControlBlocks, createChatTab, createEmptyThread, createGlobalChat, createOrUpdatePr, createThread, createThreadWorktree, currentBranch, cursorAdapter, cursorSdkMessageToEvents, decodeBrightsyTarget, deleteBranchOnPurgeEnabled, deleteThreadRecord, detectAgents, detectLocalMergeConflicts, disconnectBrightsyTeam, discoverSkills, encodeBrightsyTarget, enrichWorkspacesWithGithub, ensureAgentPath, ensureCloudCoordinator, ensureGlobalCoordinatorCwd, ensureWorkspace, estimateMessageChars, estimateThreadChars, expandComposerPrompt, extractGhErrorDetail, extractiveSummary, fetchPrHead, finalizeParts, findInvalidCacheControlTtlOrder, findOrphanWorktrees, findThreadByRef, flattenTurnInput, forkChatTab, forkMessageSlice, forkThreadWorktree, formatAgentInstructions, formatBrightsyFetchError, formatGhLandError, formatIpcInvokeError, formatMessagesAsTranscript, formatRateLimitResetHint, formatRenameBranchDirective, formatTranscriptMarkdown, formatWorkspaceInventory, formatWorktreeDirective, getAdapter, getBrightsySession, getDefaultRunScript, getDiff, getDiffSummary, getGitHubStatus, getIssueSource, getLinearApiKey, getOrchestrator, getPr, getPrChecks, getPrDetails, getPrMeta, getRepoSetupInfo, getRunMode, getRunScript, gh, git, globalAgentCwd, harnessEnvKey, hasConductorHook, hasCursorWorktreeSetup, hasRepoHook, hasWorkspaceHook, healOrchestrationSoccerTitles, importConductorWorkspace, importConductorWorkspaceAsync, initializeGitRepository, inspectGitWorktree, isBrightsyConnected, isBrightsyNdjsonLine, isCloudCoordinatorThread, isDirty, isGhRateLimitError, isGlobalRepoPath, isGlobalThread, isLinearConnected, isOrchestratorThread, isPlaceholderBranch, listBranchCommits, listBranches, listBrightsyAccounts, listBrightsyChatTargets, listConductorWorkspaces, listConnectedBrightsyTeams, listGitHubIssues, listGlobalThreads, listIssues, listLinearIssues, listLinearIssuesDirect, listPrs, listRunScripts, listThreads, listWorkspaces, listWorktreeFiles, listWorktrees, loadAgentInstructions, loadAppSettings, loadBrightsyConfig, loadConductorSettings, loadRepoSettings, loadWorkspaceSettings, locksDir, maxConcurrentAgents, maybeCompactContext, mcpAllowTools, mcpAuthWarnings, mergePr, mergeUsage, normalizeParseResult, normalizeThread, normalizeTurnInput, normalizeWorktreePath, opencodeAdapter, orchestrationTitleNeedsSoccerNickname, orchestratorSessionPoisonedByBuiltins, parseCursorRunnerLine, parseForceStopMessage, parseGithubSlugFromRemoteUrl, parseMcpList, partsToAssistantText, permissionMode, previewLand, pushBranch, readSkillBody, readThread, readWorktreeFile, readWorktreeInclude, refreshGitHubAuth, removeWorkspace, removeWorktree, repoSlug, requireAgent, resolveClaudeExecutable, resolveConductorCursorAgentId, resolveDefaultBranch, resolveDiffBaseRef, resolveEffectiveIssueSource, resolveFilesToCopy, resolveGithubRepoSlug, resolvePrSelector, resolveRepoRoot, resolveWorktreeStartPoint, run, runArchiveScript, runCloudConnect, runCursorWorktreeSetup, runSetupScript, sameWorktreePath, sanitizeMcpServerName, saveAppSettings, setStatus, settingsSourceLabel, shouldCompactContext, shouldRunWorktreeCleanup, sideboardHomeDir, sideboardReposDir, sideboardWorkspacesDir, slugify, spawnAgentTurn, splitForCompaction, startDevServer, startMcpServer, startOrchestration, stripBrightsyNdjsonNoise, suggestSlug, summarizeConversation, switchBrightsyAccount, syncWorkspacesFromThreads, takenTeamSlugsForChatTab, takenTeamSlugsForOrchestration, taskMessageText, threadDisplayLabel, threadFilePath, threadLockPath, threadsDir, threadsSharingWorktree, toolDescription, toolDetail, toolFilePath, totalTokens, updateAdvancedSettings, updateAppEnvironment, updateBrightsySettings, updateClaudeSettings, updateIntegrationsSettings, updateThread, validateLinearApiKey, withAgentInstructions, withThreadLock, workspaceSettingsSourceLabel, worktreeCleanupSettings, worktreeDisplayLabel, worktreeDisplayLabelForGroup, worktreeNameFromPath, worktreesRoot, writeInjectedMcpConfig, writeThread, writeWorktreeFile };