@sideboard-ai/core 0.1.320 → 0.1.321

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 (56) hide show
  1. package/dist/agents/cursor-runner.js +2 -2
  2. package/dist/{agents-CJZYJOWP.js → agents-PFVYC36J.js} +8 -8
  3. package/dist/{agents-F2E2HACB.js → agents-ROFDNE7Z.js} +9 -9
  4. package/dist/{chunk-QVN2WOKJ.js → chunk-2TUE6JKQ.js} +12 -0
  5. package/dist/{chunk-B7UL36WH.js → chunk-45UB2J47.js} +335 -65
  6. package/dist/{chunk-DD67JWTN.js → chunk-4YXZOXMT.js} +1 -1
  7. package/dist/{chunk-V5BTGQ6M.js → chunk-6U6QRUHY.js} +1 -1
  8. package/dist/{chunk-QGY3UNNL.js → chunk-7JV5QP5K.js} +1 -1
  9. package/dist/{chunk-DJZRDTZY.js → chunk-BANN5HUX.js} +6 -6
  10. package/dist/{chunk-CB5Z5C3J.js → chunk-BPDVHB4U.js} +1 -1
  11. package/dist/{chunk-RHJPP26T.js → chunk-H6GXYV5Q.js} +14 -11
  12. package/dist/{chunk-4GZC6DDH.js → chunk-IFWGG2M2.js} +7 -0
  13. package/dist/{chunk-LLIEU2ZB.js → chunk-JNEFEA2A.js} +6 -6
  14. package/dist/{chunk-IDPFLXRY.js → chunk-LD2DXHBP.js} +341 -67
  15. package/dist/{chunk-2P4XKWV2.js → chunk-QKHEVSB5.js} +1 -1
  16. package/dist/{chunk-P74GXA5V.js → chunk-RGUZPMTF.js} +6 -6
  17. package/dist/{chunk-UK2KESBN.js → chunk-RHJKZOPQ.js} +3 -3
  18. package/dist/{chunk-HH3VVTEC.js → chunk-S5CJUIPY.js} +5 -5
  19. package/dist/{chunk-5S3YP5KH.js → chunk-SPMIZSKH.js} +14 -11
  20. package/dist/{chunk-EQ5JY3MJ.js → chunk-TEFFR6PB.js} +1 -1
  21. package/dist/{chunk-EDXTP2VR.js → chunk-UWJUARFA.js} +545 -186
  22. package/dist/{chunk-OAFBHCSM.js → chunk-UX6EDDGR.js} +1 -1
  23. package/dist/{chunk-ZYZBCLJR.js → chunk-XDQSHSL6.js} +6 -6
  24. package/dist/{chunk-2UG25RMK.js → chunk-YBTSZ2SW.js} +12 -0
  25. package/dist/{chunk-PNLGWAYE.js → chunk-YWBLQBSN.js} +548 -187
  26. package/dist/{chunk-Y3Y7SZBZ.js → chunk-ZHGMRBSC.js} +1 -1
  27. package/dist/{conductor-FPFY6Z5S.js → conductor-CNT3VL3S.js} +6 -6
  28. package/dist/{conductor-JA5W3L7C.js → conductor-XLXJU24U.js} +6 -6
  29. package/dist/{connected-teams-IHK2WXUI.js → connected-teams-H4LZOJDC.js} +2 -2
  30. package/dist/{connected-teams-IFW3NQ6G.js → connected-teams-XYRZMQO4.js} +2 -2
  31. package/dist/{coordinator-prompt-NUC2ZXMJ.js → coordinator-prompt-D5EE2YTV.js} +5 -5
  32. package/dist/{coordinator-prompt-M75TAN43.js → coordinator-prompt-TU24TQ4I.js} +5 -5
  33. package/dist/{global-workspace-5A4H34AF.js → global-workspace-743TPQNF.js} +5 -5
  34. package/dist/{global-workspace-SCLQUNUI.js → global-workspace-UPMXDQM7.js} +5 -5
  35. package/dist/index.cjs +1577 -471
  36. package/dist/index.d.cts +182 -70
  37. package/dist/index.d.ts +182 -70
  38. package/dist/index.js +480 -62
  39. package/dist/mcp/run-stdio.cjs +1159 -447
  40. package/dist/mcp/run-stdio.js +65 -17
  41. package/dist/{optional-cli-MRNQKVIR.js → optional-cli-2YDQQCCD.js} +4 -4
  42. package/dist/{optional-cli-2V3SLME5.js → optional-cli-USD6PROE.js} +3 -3
  43. package/dist/{orchestrator-NPFWU3XU.js → orchestrator-B4STIW4B.js} +12 -12
  44. package/dist/{orchestrator-7BDZ5GWD.js → orchestrator-VQ4HRYVB.js} +11 -11
  45. package/dist/{run-PCX5QWR4.js → run-7QMRYP3F.js} +3 -1
  46. package/dist/{run-TB7RBII2.js → run-UPNCCRCN.js} +3 -1
  47. package/dist/{thread-store-JWHVXLDX.js → thread-store-3F7GR64A.js} +1 -1
  48. package/dist/{thread-store-QHYN2ZMQ.js → thread-store-JRSL4HQY.js} +1 -1
  49. package/dist/{workspaces-KWMBOTQD.js → workspaces-47WQL5IG.js} +5 -5
  50. package/dist/{workspaces-5QA3YM4L.js → workspaces-75FD4QUR.js} +5 -5
  51. package/dist/{worktree-O6BANO2I.js → worktree-G3E6WP66.js} +10 -8
  52. package/dist/{worktree-7EATHVYQ.js → worktree-PDNPL5CQ.js} +10 -8
  53. package/dist/{worktree-exclude-RXZPTCNH.js → worktree-exclude-INRDQFWV.js} +2 -2
  54. package/dist/{worktree-exclude-5N2KTYIT.js → worktree-exclude-P5NJODWP.js} +2 -2
  55. package/package.json +1 -1
  56. /package/dist/{chunk-XMHMVEIY.js → chunk-B4CDSSRN.js} +0 -0
package/dist/index.js CHANGED
@@ -46,6 +46,7 @@ import {
46
46
  connectedOrchestrator,
47
47
  connectedOrchestratorTurnReminder,
48
48
  consumeComposerAttachments,
49
+ createOrUpdatePr,
49
50
  createPrStack,
50
51
  createSchedule,
51
52
  createThread,
@@ -72,8 +73,10 @@ import {
72
73
  formatAskUserNotifyMessage,
73
74
  formatClaudeSubagentReminder,
74
75
  formatConnectedOrchestratorReminder,
76
+ formatCursorGitDirective,
75
77
  formatDetachedJobInvoke,
76
78
  formatDevAccessHint,
79
+ formatEntireGitDirective,
77
80
  formatFleetArchive,
78
81
  formatGitHubSearchUpdatedSince,
79
82
  formatInjectedNoticesForTurn,
@@ -98,6 +101,7 @@ import {
98
101
  getOrchestrator,
99
102
  getSchedule,
100
103
  getWorktreeDirtyStat,
104
+ ghPrCreateAssigneeArgs,
101
105
  groupHomeBoardWorktrees,
102
106
  hasEnabledSchedules,
103
107
  importConductorWorkspace,
@@ -206,7 +210,7 @@ import {
206
210
  worktreeCleanupSettings,
207
211
  writeAgentBlock,
208
212
  writeWorktreeFile
209
- } from "./chunk-IDPFLXRY.js";
213
+ } from "./chunk-LD2DXHBP.js";
210
214
  import {
211
215
  LEGACY_PLAN_FILE_REL,
212
216
  PLAN_FILE_NAME,
@@ -296,7 +300,7 @@ import {
296
300
  userMcpNamesToDisable,
297
301
  worktreeMcpToolNames,
298
302
  writeInjectedMcpConfig
299
- } from "./chunk-LLIEU2ZB.js";
303
+ } from "./chunk-JNEFEA2A.js";
300
304
  import {
301
305
  brightsyMcpServerName,
302
306
  connectBrightsyTeam,
@@ -306,7 +310,7 @@ import {
306
310
  listBrightsyAccounts,
307
311
  listConnectedBrightsyTeams,
308
312
  switchBrightsyAccount
309
- } from "./chunk-HH3VVTEC.js";
313
+ } from "./chunk-S5CJUIPY.js";
310
314
  import {
311
315
  BRIGHTSY_SUMMARIZE_CONTEXT_TOOL,
312
316
  CHARS_PER_CONTEXT_TOKEN,
@@ -427,7 +431,7 @@ import {
427
431
  workspaceAgentChatSummaries,
428
432
  worktreeRunPortsPath,
429
433
  wrapReviewSkillMarkdown
430
- } from "./chunk-DJZRDTZY.js";
434
+ } from "./chunk-BANN5HUX.js";
431
435
  import {
432
436
  STDERR_EVENT_MAX_CHARS,
433
437
  STDOUT_EVENT_MAX_CHARS,
@@ -549,7 +553,7 @@ import {
549
553
  detectOptionalServiceClis,
550
554
  installOptionalServiceCli,
551
555
  optionalCliPresence
552
- } from "./chunk-UK2KESBN.js";
556
+ } from "./chunk-RHJKZOPQ.js";
553
557
  import {
554
558
  OPTIONAL_SERVICES,
555
559
  OPTIONAL_SERVICE_IDS,
@@ -565,7 +569,7 @@ import {
565
569
  optionalServiceConnected,
566
570
  optionalServiceSpec,
567
571
  verifyOptionalService
568
- } from "./chunk-EQ5JY3MJ.js";
572
+ } from "./chunk-TEFFR6PB.js";
569
573
  import {
570
574
  getAgentSetupInfo,
571
575
  installAgent,
@@ -577,7 +581,7 @@ import {
577
581
  prepareTerminalCommand,
578
582
  resolveLoginCommand,
579
583
  whichOnPath
580
- } from "./chunk-CB5Z5C3J.js";
584
+ } from "./chunk-BPDVHB4U.js";
581
585
  import {
582
586
  CLOUD_COORDINATOR_BUSY_REPLY,
583
587
  CLOUD_COORDINATOR_CANCELED_REPLY,
@@ -630,7 +634,7 @@ import {
630
634
  stageBuffersAsAttachments,
631
635
  syncWorkspacesFromThreads,
632
636
  takenTeamSlugsForOrchestration
633
- } from "./chunk-RHJPP26T.js";
637
+ } from "./chunk-H6GXYV5Q.js";
634
638
  import {
635
639
  GITHUB_PR_BODY_MAX_CHARS,
636
640
  GITHUB_PR_BODY_SAFE_CHARS,
@@ -649,12 +653,12 @@ import {
649
653
  connectedPrSelectors,
650
654
  countUnpushedVsOrigin,
651
655
  createExistingBranchWorktree,
652
- createOrUpdatePr,
653
656
  createThreadWorktree,
654
657
  currentBranch,
655
658
  detectGhStack,
656
659
  detectLocalMergeConflicts,
657
660
  ensureGhPreferOrigin,
661
+ entireUsesTrails,
658
662
  extractGhErrorDetail,
659
663
  fastForwardMainCheckoutIfSafe,
660
664
  fetchOriginForWorktree,
@@ -671,7 +675,6 @@ import {
671
675
  getPrMeta,
672
676
  getPrStack,
673
677
  ghHeadRef,
674
- ghPrCreateAssigneeArgs,
675
678
  ghRepoSelectArgs,
676
679
  githubAgentGitEnv,
677
680
  githubHttpsInsteadOfEntries,
@@ -707,8 +710,10 @@ import {
707
710
  resolveGithubAgentToken,
708
711
  resolveGithubRepoSlug,
709
712
  resolveListPrsOptions,
713
+ resolveOriginRemote,
710
714
  resolvePrSelector,
711
715
  resolvePrSelectors,
716
+ resolveProjectRemoteTag,
712
717
  resolveRepoRoot,
713
718
  resolveWorktreeStartPoint,
714
719
  scrubGithubTokensFromChildEnv,
@@ -718,7 +723,7 @@ import {
718
723
  suggestSlug,
719
724
  switchWorktreeBranch,
720
725
  warmGithubAgentAuth
721
- } from "./chunk-EDXTP2VR.js";
726
+ } from "./chunk-UWJUARFA.js";
722
727
  import {
723
728
  FAMOUS_SOCCER_TEAMS,
724
729
  allocateTeamName,
@@ -745,6 +750,7 @@ import {
745
750
  updateThread,
746
751
  withThreadLock,
747
752
  workspaceNameLabel,
753
+ workspaceRowLabel,
748
754
  workspaceTagsFromGroup,
749
755
  worktreeAnchorLabel,
750
756
  worktreeDisplayLabel,
@@ -752,8 +758,8 @@ import {
752
758
  worktreeNameFromPath,
753
759
  worktreeSlugForTicket,
754
760
  writeThread
755
- } from "./chunk-4GZC6DDH.js";
756
- import "./chunk-2P4XKWV2.js";
761
+ } from "./chunk-IFWGG2M2.js";
762
+ import "./chunk-QKHEVSB5.js";
757
763
  import {
758
764
  BRIGHTSY_OAUTH_CLIENT_ID,
759
765
  BRIGHTSY_OAUTH_REDIRECT,
@@ -808,7 +814,7 @@ import {
808
814
  trustSystemCertificates,
809
815
  turnCostUsdFromCursorUsage,
810
816
  withMaxOldSpaceSize
811
- } from "./chunk-Y3Y7SZBZ.js";
817
+ } from "./chunk-ZHGMRBSC.js";
812
818
  import "./chunk-5XNT6BCG.js";
813
819
  import {
814
820
  ATTACHMENTS_DIR,
@@ -829,13 +835,14 @@ import {
829
835
  isConductorBundledCli,
830
836
  npmGlobalNodeModules,
831
837
  npmGlobalPrefix,
838
+ originCli,
832
839
  posixShellSingleQuote,
833
840
  resolveCommandBinarySync,
834
841
  resolveGhAuthToken,
835
842
  resolveGitDirsForLockRecovery,
836
843
  run,
837
844
  withExportedPath
838
- } from "./chunk-QVN2WOKJ.js";
845
+ } from "./chunk-2TUE6JKQ.js";
839
846
  import {
840
847
  AGENT_RPC_JOB_HOLD_MAX_MS,
841
848
  AGENT_RPC_JOB_SLICE_MS,
@@ -2716,7 +2723,7 @@ function listPhoneSidebar(viewerLogin = phoneViewerLogin()) {
2716
2723
  const badge = classifyWorktreeListBadges(group, viewerLogin, resolveProjectReviewLabel(settings, path2))[0];
2717
2724
  const blockedBy = issueBlockedByIds(group);
2718
2725
  return {
2719
- label: worktreeAnchorLabel(group).title,
2726
+ ...workspaceRowLabel(group),
2720
2727
  chats: group.map(summarize),
2721
2728
  ...tags.length > 0 ? { tags } : {},
2722
2729
  ...blockedBy.length > 0 ? { blockedBy } : {},
@@ -3989,12 +3996,12 @@ async function persistLinearTokens(data, viewer) {
3989
3996
  organizationName: viewer?.organizationName
3990
3997
  });
3991
3998
  }
3992
- async function fetchLinearViewer(accessToken2) {
3999
+ async function fetchLinearViewer(accessToken3) {
3993
4000
  const res = await httpFetch(LINEAR_GRAPHQL, {
3994
4001
  method: "POST",
3995
4002
  headers: {
3996
4003
  "Content-Type": "application/json",
3997
- Authorization: linearAuthorizationHeader(accessToken2)
4004
+ Authorization: linearAuthorizationHeader(accessToken3)
3998
4005
  },
3999
4006
  body: JSON.stringify({
4000
4007
  query: "{ viewer { name organization { name } } }"
@@ -5290,6 +5297,18 @@ async function validateLinearApiKey(apiKey) {
5290
5297
  }
5291
5298
 
5292
5299
  // src/integrations/issues.ts
5300
+ var CURSOR_ISSUES_UNAVAILABLE = "Cursor Origin has no issue tracker. Tickets for this repo come from Linear or AbleTime (Settings \u2192 Issues).";
5301
+ var ENTIRE_ISSUES_ARE_TRAILS = "Entire does not use GitHub Issues. Tickets for this repo are Trails (`entire trail list`). Linear or AbleTime still work when selected in Settings \u2192 Issues.";
5302
+ async function cursorIssuesUnavailableReason(repoPath) {
5303
+ try {
5304
+ const remote = await resolveOriginRemote(repoPath);
5305
+ if (remote?.forge === "cursor") return CURSOR_ISSUES_UNAVAILABLE;
5306
+ if (remote?.forge === "entire") return ENTIRE_ISSUES_ARE_TRAILS;
5307
+ return null;
5308
+ } catch {
5309
+ return null;
5310
+ }
5311
+ }
5293
5312
  function assigneeKey(assignee) {
5294
5313
  return (assignee ?? "").trim().toLowerCase();
5295
5314
  }
@@ -5451,6 +5470,17 @@ async function listIssues(repoPath, opts) {
5451
5470
  ...since ? { since, comments: commentsFromAbleTimeIssues(tasks, issues2, since) } : {}
5452
5471
  };
5453
5472
  }
5473
+ const unavailableReason = await cursorIssuesUnavailableReason(repoPath);
5474
+ if (unavailableReason) {
5475
+ return {
5476
+ source,
5477
+ preferredSource,
5478
+ linearConnected,
5479
+ abletimeConnected,
5480
+ issues: [],
5481
+ unavailableReason
5482
+ };
5483
+ }
5454
5484
  const [issues, login] = await Promise.all([
5455
5485
  listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit, updatedSince: since }),
5456
5486
  githubViewerLogin(repoPath)
@@ -7771,6 +7801,7 @@ import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, realpathSync }
7771
7801
  import { createRequire } from "module";
7772
7802
  import { dirname, join as join3 } from "path";
7773
7803
  var GITHUB_ACCOUNT_ISSUER = "https://github.com";
7804
+ var CURSOR_ACCOUNT_ISSUER = "https://api.cursor.com/v1/origin";
7774
7805
  var RELAY_DEVICE_CAP = 3;
7775
7806
  function thisModuleFile() {
7776
7807
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
@@ -8023,20 +8054,224 @@ var RelayAccountStore = class {
8023
8054
  }
8024
8055
  };
8025
8056
 
8057
+ // src/relay/account-cursor.ts
8058
+ import { createPublicKey, verify } from "crypto";
8059
+ var JWKS_URL = "https://api.cursor.com/v1/origin/keys";
8060
+ var RECEIPT_TYP = "origin-user-confirmation-receipt+jwt";
8061
+ var usedJti = /* @__PURE__ */ new Map();
8062
+ function b64urlJson(segment) {
8063
+ return JSON.parse(b64urlBuf(segment).toString("utf8"));
8064
+ }
8065
+ function b64urlBuf(segment) {
8066
+ const pad = segment.length % 4 === 0 ? "" : "=".repeat(4 - segment.length % 4);
8067
+ return Buffer.from(segment.replace(/-/g, "+").replace(/_/g, "/") + pad, "base64");
8068
+ }
8069
+ function rememberJti(jti, expMs, nowMs) {
8070
+ for (const [id, exp] of usedJti) {
8071
+ if (exp < nowMs) usedJti.delete(id);
8072
+ }
8073
+ if (usedJti.has(jti)) return false;
8074
+ usedJti.set(jti, expMs);
8075
+ return true;
8076
+ }
8077
+ function cursorAuthorizeUrl(clientId, redirectUri, state) {
8078
+ const url = new URL("https://cursor.com/codebase/apps/user-confirmation");
8079
+ url.searchParams.set("client_id", clientId);
8080
+ url.searchParams.set("redirect_uri", redirectUri);
8081
+ url.searchParams.set("state", state);
8082
+ return url.toString();
8083
+ }
8084
+ async function cursorIdentityFromReceipt(receipt, expected, fetchImpl, nowMs = Date.now()) {
8085
+ const parts = receipt.split(".");
8086
+ if (parts.length !== 3 || !parts[0] || !parts[1] || !parts[2]) {
8087
+ throw new Error("Cursor sign-in receipt was not a signed token.");
8088
+ }
8089
+ const [hSeg, pSeg, sSeg] = parts;
8090
+ const header = b64urlJson(hSeg);
8091
+ if (header.alg !== "EdDSA" || header.typ !== RECEIPT_TYP || typeof header.kid !== "string") {
8092
+ throw new Error("Cursor sign-in receipt was not a user confirmation.");
8093
+ }
8094
+ const payload = b64urlJson(pSeg);
8095
+ if (payload.iss !== CURSOR_ACCOUNT_ISSUER) {
8096
+ throw new Error("Cursor sign-in receipt came from an unexpected issuer.");
8097
+ }
8098
+ if (payload.aud !== expected.clientId) throw new Error("Cursor sign-in receipt was for a different app.");
8099
+ if (payload.state !== expected.state) throw new Error("Cursor sign-in did not match this attempt.");
8100
+ const exp = typeof payload.exp === "number" ? payload.exp : 0;
8101
+ if (!exp || exp * 1e3 < nowMs) throw new Error("Cursor sign-in receipt expired.");
8102
+ const sub = typeof payload.sub === "string" ? payload.sub.trim() : "";
8103
+ if (!sub) throw new Error("Cursor did not return an account id.");
8104
+ const jti = typeof payload.jti === "string" ? payload.jti.trim() : "";
8105
+ if (!jti) throw new Error("Cursor sign-in receipt was missing an id.");
8106
+ const jwksRes = await fetchImpl(JWKS_URL);
8107
+ const body = await jwksRes.json();
8108
+ const jwk = (body.keys ?? []).find(
8109
+ (key2) => key2.kid === header.kid && key2.kty === "OKP" && key2.crv === "Ed25519" && key2.x
8110
+ );
8111
+ if (!jwk?.x) throw new Error("Cursor did not publish the key that signed this receipt.");
8112
+ const key = createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x: jwk.x }, format: "jwk" });
8113
+ const ok = verify(null, Buffer.from(`${hSeg}.${pSeg}`), key, b64urlBuf(sSeg));
8114
+ if (!ok) throw new Error("Cursor sign-in receipt signature did not verify.");
8115
+ if (!rememberJti(jti, exp * 1e3, nowMs)) throw new Error("Cursor sign-in receipt was already used.");
8116
+ const email = typeof payload.email === "string" && payload.email.trim() ? payload.email.trim() : null;
8117
+ return {
8118
+ issuer: CURSOR_ACCOUNT_ISSUER,
8119
+ subject: sub,
8120
+ email,
8121
+ emailVerified: Boolean(email)
8122
+ };
8123
+ }
8124
+ function cursorGitHostEntry() {
8125
+ return {
8126
+ label: "Cursor",
8127
+ requiresClientSecret: false,
8128
+ credentialParam: "confirmation_receipt",
8129
+ authorizeUrl(client, redirectUri, state) {
8130
+ return cursorAuthorizeUrl(client.clientId, redirectUri, state);
8131
+ },
8132
+ fetchIdentity(client, receipt, _redirectUri, state, fetchImpl) {
8133
+ return cursorIdentityFromReceipt(receipt, { clientId: client.clientId, state }, fetchImpl);
8134
+ }
8135
+ };
8136
+ }
8137
+
8138
+ // src/relay/account-entire.ts
8139
+ import { createHash as createHash3, randomBytes as randomBytes6 } from "crypto";
8140
+ var ENTIRE_AUTHORIZE_ORIGIN = "https://auth.entire.io";
8141
+ var ENTIRE_DEFAULT_ISSUER = "https://us.auth.entire.io";
8142
+ var ISSUER_SUFFIX = ".auth.entire.io";
8143
+ function entireAccountIssuer(value) {
8144
+ const raw = value?.trim() ?? "";
8145
+ if (!raw) return null;
8146
+ let url;
8147
+ try {
8148
+ url = new URL(raw);
8149
+ } catch {
8150
+ return null;
8151
+ }
8152
+ if (url.protocol !== "https:" || url.username || url.password || url.port) return null;
8153
+ if (url.pathname !== "/" && url.pathname !== "") return null;
8154
+ if (url.search || url.hash) return null;
8155
+ const host = url.hostname.toLowerCase();
8156
+ if (!host.endsWith(ISSUER_SUFFIX)) return null;
8157
+ const label = host.slice(0, -ISSUER_SUFFIX.length);
8158
+ if (!/^[a-z0-9]+$/.test(label)) return null;
8159
+ return `https://${host}`;
8160
+ }
8161
+ function newEntireCodeVerifier() {
8162
+ return randomBytes6(32).toString("base64url");
8163
+ }
8164
+ function entireCodeChallenge(verifier) {
8165
+ return createHash3("sha256").update(verifier).digest("base64url");
8166
+ }
8167
+ function entireAuthorizeUrl(clientId, redirectUri, state, codeChallenge) {
8168
+ const url = new URL("/authorize", ENTIRE_AUTHORIZE_ORIGIN);
8169
+ url.searchParams.set("client_id", clientId);
8170
+ url.searchParams.set("redirect_uri", redirectUri);
8171
+ url.searchParams.set("response_type", "code");
8172
+ url.searchParams.set("scope", "openid email");
8173
+ url.searchParams.set("state", state);
8174
+ url.searchParams.set("code_challenge", codeChallenge);
8175
+ url.searchParams.set("code_challenge_method", "S256");
8176
+ return url.toString();
8177
+ }
8178
+ async function readJson(res) {
8179
+ const text5 = await res.text();
8180
+ if (!text5) return {};
8181
+ try {
8182
+ return JSON.parse(text5);
8183
+ } catch {
8184
+ throw new Error("Entire returned a non-JSON response.");
8185
+ }
8186
+ }
8187
+ function accessToken(body) {
8188
+ const token = body.access_token;
8189
+ if (typeof token === "string" && token.trim()) return token.trim();
8190
+ const described = body.error_description;
8191
+ const code = body.error;
8192
+ const message = typeof described === "string" && described.trim() ? described : code;
8193
+ throw new Error(
8194
+ typeof message === "string" && message.trim() ? message : "Entire rejected the sign-in code."
8195
+ );
8196
+ }
8197
+ async function entireIdentityFromCode(client, code, redirectUri, ctx, fetchImpl) {
8198
+ if (!ctx.codeVerifier) throw new Error("Entire sign-in could not be verified.");
8199
+ const issuer = ctx.issuer?.trim() ? entireAccountIssuer(ctx.issuer) : ENTIRE_DEFAULT_ISSUER;
8200
+ if (!issuer) throw new Error("Entire sign-in came from an unexpected issuer.");
8201
+ const body = new URLSearchParams({
8202
+ grant_type: "authorization_code",
8203
+ code,
8204
+ redirect_uri: redirectUri,
8205
+ client_id: client.clientId,
8206
+ code_verifier: ctx.codeVerifier
8207
+ });
8208
+ const secret = client.clientSecret?.trim() ?? "";
8209
+ const headers = {
8210
+ Accept: "application/json",
8211
+ "Content-Type": "application/x-www-form-urlencoded"
8212
+ };
8213
+ if (secret) {
8214
+ headers.Authorization = `Basic ${Buffer.from(`${client.clientId}:${secret}`).toString("base64")}`;
8215
+ }
8216
+ const tokenRes = await fetchImpl(`${issuer}/oauth/token`, {
8217
+ method: "POST",
8218
+ redirect: "error",
8219
+ headers,
8220
+ body
8221
+ });
8222
+ const token = accessToken(await readJson(tokenRes));
8223
+ const userRes = await fetchImpl(`${issuer}/userinfo`, {
8224
+ redirect: "error",
8225
+ headers: { Accept: "application/json", Authorization: `Bearer ${token}` }
8226
+ });
8227
+ if (!userRes.ok) throw new Error("Entire did not return an account.");
8228
+ const user = await readJson(userRes);
8229
+ const subject = typeof user.sub === "string" ? user.sub.trim() : "";
8230
+ if (!subject) throw new Error("Entire did not return an account id.");
8231
+ const email = typeof user.email === "string" ? user.email.trim() : "";
8232
+ const emailVerified = user.email_verified === true && Boolean(email);
8233
+ return {
8234
+ issuer,
8235
+ subject,
8236
+ email: emailVerified ? email : null,
8237
+ emailVerified
8238
+ };
8239
+ }
8240
+ function entireGitHostEntry() {
8241
+ return {
8242
+ label: "Entire",
8243
+ requiresClientSecret: false,
8244
+ credentialParam: "code",
8245
+ authorizeUrl(client, redirectUri, state, ctx) {
8246
+ if (!ctx.codeVerifier) throw new Error("Entire sign-in could not start.");
8247
+ return entireAuthorizeUrl(client.clientId, redirectUri, state, entireCodeChallenge(ctx.codeVerifier));
8248
+ },
8249
+ fetchIdentity(client, code, redirectUri, _state, fetchImpl, ctx) {
8250
+ return entireIdentityFromCode(client, code, redirectUri, ctx, fetchImpl);
8251
+ }
8252
+ };
8253
+ }
8254
+
8026
8255
  // src/relay/account-oauth.ts
8027
- var RELAY_GIT_HOSTS = ["github"];
8256
+ var RELAY_GIT_HOSTS = ["github", "cursor", "entire"];
8028
8257
  var REMOTE_LOGIN_PATH = "/remote/login";
8029
8258
  var REMOTE_OAUTH_CALLBACK_PATH = "/remote/oauth/callback";
8030
8259
  var REMOTE_OAUTH_RESULT_PATH = "/remote/oauth/result";
8031
8260
  var REMOTE_LOGOUT_PATH = "/remote/logout";
8032
8261
  var STATE_RE = /^[A-Za-z0-9_-]{16,128}$/;
8033
8262
  var LOGIN_TTL_MS = 10 * 60 * 1e3;
8263
+ var EMPTY_AUTH = { codeVerifier: null, issuer: null };
8034
8264
  var RelayLoginSessions = class {
8035
8265
  waiting = /* @__PURE__ */ new Map();
8036
8266
  results = /* @__PURE__ */ new Map();
8037
- begin(state, provider, accountId) {
8267
+ begin(state, provider, accountId, codeVerifier = null) {
8038
8268
  this.sweep();
8039
- this.waiting.set(state, { provider, accountId, expiresAt: Date.now() + LOGIN_TTL_MS });
8269
+ this.waiting.set(state, {
8270
+ provider,
8271
+ accountId,
8272
+ codeVerifier,
8273
+ expiresAt: Date.now() + LOGIN_TTL_MS
8274
+ });
8040
8275
  }
8041
8276
  takeLogin(state) {
8042
8277
  this.sweep();
@@ -8071,24 +8306,29 @@ var RelayLoginSessions = class {
8071
8306
  var GIT_HOST_AUTH = {
8072
8307
  github: {
8073
8308
  label: "GitHub",
8074
- authorizeUrl: "https://github.com/login/oauth/authorize",
8075
- scope: "user:email",
8309
+ requiresClientSecret: true,
8310
+ credentialParam: "code",
8311
+ authorizeUrl: (client, redirectUri, state) => githubAuthorizeUrl(client, redirectUri, state),
8076
8312
  fetchIdentity: fetchGithubIdentity
8077
- }
8313
+ },
8314
+ cursor: cursorGitHostEntry(),
8315
+ entire: entireGitHostEntry()
8078
8316
  };
8079
- function providerOf(value) {
8080
- return RELAY_GIT_HOSTS.includes(value) ? value : null;
8081
- }
8082
- function relayAuthorizeUrl(provider, client, redirectUri, state) {
8083
- const host = GIT_HOST_AUTH[provider];
8084
- const url = new URL(host.authorizeUrl);
8317
+ function githubAuthorizeUrl(client, redirectUri, state) {
8318
+ const url = new URL("https://github.com/login/oauth/authorize");
8085
8319
  url.searchParams.set("client_id", client.clientId);
8086
8320
  url.searchParams.set("redirect_uri", redirectUri);
8087
- url.searchParams.set("scope", host.scope);
8321
+ url.searchParams.set("scope", "user:email");
8088
8322
  url.searchParams.set("state", state);
8089
8323
  return url.toString();
8090
8324
  }
8091
- async function readJson(res) {
8325
+ function providerOf(value) {
8326
+ return RELAY_GIT_HOSTS.includes(value) ? value : null;
8327
+ }
8328
+ function relayAuthorizeUrl(provider, client, redirectUri, state, ctx = EMPTY_AUTH) {
8329
+ return GIT_HOST_AUTH[provider].authorizeUrl(client, redirectUri, state, ctx);
8330
+ }
8331
+ async function readJson2(res) {
8092
8332
  const text5 = await res.text();
8093
8333
  if (!text5) return {};
8094
8334
  try {
@@ -8097,7 +8337,7 @@ async function readJson(res) {
8097
8337
  throw new Error("Sign-in provider returned a non-JSON response.");
8098
8338
  }
8099
8339
  }
8100
- function accessToken(body) {
8340
+ function accessToken2(body) {
8101
8341
  const token = body.access_token;
8102
8342
  if (typeof token !== "string" || !token.trim()) {
8103
8343
  const message = body.error_description;
@@ -8105,7 +8345,10 @@ function accessToken(body) {
8105
8345
  }
8106
8346
  return token.trim();
8107
8347
  }
8108
- async function fetchGithubIdentity(client, code, redirectUri, fetchImpl) {
8348
+ async function fetchGithubIdentity(client, code, redirectUri, state, fetchImpl, _ctx) {
8349
+ void state;
8350
+ void _ctx;
8351
+ if (!client.clientSecret) throw new Error("GitHub sign-in is not configured on this relay.");
8109
8352
  const tokenRes = await fetchImpl("https://github.com/login/oauth/access_token", {
8110
8353
  method: "POST",
8111
8354
  headers: { Accept: "application/json", "Content-Type": "application/json" },
@@ -8116,17 +8359,17 @@ async function fetchGithubIdentity(client, code, redirectUri, fetchImpl) {
8116
8359
  redirect_uri: redirectUri
8117
8360
  })
8118
8361
  });
8119
- const token = accessToken(await readJson(tokenRes));
8362
+ const token = accessToken2(await readJson2(tokenRes));
8120
8363
  const userRes = await fetchImpl("https://api.github.com/user", {
8121
8364
  headers: { Authorization: `Bearer ${token}`, Accept: "application/vnd.github+json", "User-Agent": "sideboard-relay" }
8122
8365
  });
8123
- const user = await readJson(userRes);
8366
+ const user = await readJson2(userRes);
8124
8367
  const subject = typeof user.id === "number" ? String(user.id) : "";
8125
8368
  if (!subject) throw new Error("GitHub did not return an account id.");
8126
8369
  const emailRes = await fetchImpl("https://api.github.com/user/emails", {
8127
8370
  headers: { Authorization: `Bearer ${token}`, Accept: "application/vnd.github+json", "User-Agent": "sideboard-relay" }
8128
8371
  });
8129
- const emails = await readJson(emailRes);
8372
+ const emails = await readJson2(emailRes);
8130
8373
  const list = Array.isArray(emails) ? emails : [];
8131
8374
  const primary = list.find((row2) => row2.primary === true && row2.verified === true);
8132
8375
  const anyVerified = list.find((row2) => row2.verified === true);
@@ -8134,8 +8377,8 @@ async function fetchGithubIdentity(client, code, redirectUri, fetchImpl) {
8134
8377
  const email = chosen && typeof chosen.email === "string" ? chosen.email : null;
8135
8378
  return { issuer: GITHUB_ACCOUNT_ISSUER, subject, email, emailVerified: Boolean(email) };
8136
8379
  }
8137
- async function fetchRelayIdentity(provider, client, code, redirectUri, fetchImpl) {
8138
- return GIT_HOST_AUTH[provider].fetchIdentity(client, code, redirectUri, fetchImpl);
8380
+ async function fetchRelayIdentity(provider, client, credential, redirectUri, state, fetchImpl, ctx = EMPTY_AUTH) {
8381
+ return GIT_HOST_AUTH[provider].fetchIdentity(client, credential, redirectUri, state, fetchImpl, ctx);
8139
8382
  }
8140
8383
  async function readBody(req) {
8141
8384
  const chunks = [];
@@ -8245,7 +8488,8 @@ async function handleRelayAccountHttp(opts) {
8245
8488
  return true;
8246
8489
  }
8247
8490
  const client = opts.oauth[provider];
8248
- if (!client?.clientId || !client.clientSecret) {
8491
+ const host = provider ? GIT_HOST_AUTH[provider] : null;
8492
+ if (!client?.clientId || host?.requiresClientSecret && !client.clientSecret) {
8249
8493
  sendJson(opts.res, 503, {
8250
8494
  ok: false,
8251
8495
  error: `${GIT_HOST_AUTH[provider].label} sign-in is not configured on this relay.`
@@ -8261,21 +8505,26 @@ async function handleRelayAccountHttp(opts) {
8261
8505
  return true;
8262
8506
  }
8263
8507
  }
8264
- opts.sessions.begin(state, provider, accountId);
8265
- sendJson(opts.res, 200, { ok: true, url: relayAuthorizeUrl(provider, client, redirectUri, state) });
8508
+ const codeVerifier = provider === "entire" ? newEntireCodeVerifier() : null;
8509
+ const auth = { codeVerifier, issuer: null };
8510
+ opts.sessions.begin(state, provider, accountId, codeVerifier);
8511
+ sendJson(opts.res, 200, {
8512
+ ok: true,
8513
+ url: relayAuthorizeUrl(provider, client, redirectUri, state, auth)
8514
+ });
8266
8515
  return true;
8267
8516
  }
8268
8517
  if (method === "GET" && path2 === REMOTE_OAUTH_CALLBACK_PATH) {
8269
8518
  const url = new URL(reqUrl, origin);
8270
8519
  const state = url.searchParams.get("state")?.trim() ?? "";
8271
- const code = url.searchParams.get("code")?.trim() ?? "";
8272
8520
  const providerError = url.searchParams.get("error")?.trim() ?? "";
8273
8521
  const pending = STATE_RE.test(state) ? opts.sessions.takeLogin(state) : null;
8274
8522
  if (!pending) {
8275
8523
  sendHtml(opts.res, 400, "Sideboard", "<h1>Sign-in expired</h1><p>Return to Sideboard and try again.</p>");
8276
8524
  return true;
8277
8525
  }
8278
- if (providerError || !code) {
8526
+ const credential = url.searchParams.get(GIT_HOST_AUTH[pending.provider].credentialParam)?.trim() ?? "";
8527
+ if (providerError || !credential) {
8279
8528
  const message = providerError || "Sign-in was cancelled.";
8280
8529
  opts.sessions.putResult(state, { ok: false, error: message });
8281
8530
  sendHtml(opts.res, 400, "Sideboard", `<h1>Could not sign in</h1><p>${escapeHtml(message)}</p>`);
@@ -8288,7 +8537,15 @@ async function handleRelayAccountHttp(opts) {
8288
8537
  return true;
8289
8538
  }
8290
8539
  try {
8291
- const identity = await fetchRelayIdentity(pending.provider, client, code, redirectUri, fetchImpl);
8540
+ const identity = await fetchRelayIdentity(
8541
+ pending.provider,
8542
+ client,
8543
+ credential,
8544
+ redirectUri,
8545
+ state,
8546
+ fetchImpl,
8547
+ { codeVerifier: pending.codeVerifier, issuer: url.searchParams.get("iss") }
8548
+ );
8292
8549
  const signed = opts.store.signIn(identity, pending.accountId);
8293
8550
  opts.sessions.putResult(state, {
8294
8551
  ok: true,
@@ -8757,7 +9014,7 @@ async function startHeadlessHost(opts) {
8757
9014
  };
8758
9015
  const refreshRunning = async () => {
8759
9016
  try {
8760
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-NPFWU3XU.js");
9017
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-B4STIW4B.js");
8761
9018
  agentsRunning = getOrchestrator2().getRuntime().running;
8762
9019
  } catch {
8763
9020
  agentsRunning = 0;
@@ -8835,6 +9092,128 @@ function flatInterfaces() {
8835
9092
  return out;
8836
9093
  }
8837
9094
 
9095
+ // src/integrations/cursor-git.ts
9096
+ function parseOriginAuthStatus(text5) {
9097
+ const account = text5.match(/^Account:\s+(.+)$/m)?.[1]?.trim() || null;
9098
+ const authMethod = text5.match(/^Auth method:\s+(.+)$/m)?.[1]?.trim() || null;
9099
+ return { account, authMethod };
9100
+ }
9101
+ async function getCursorGitStatus() {
9102
+ const which = await run("which", ["origin"], { reject: false, timeoutMs: 5e3 });
9103
+ if (which.exitCode !== 0 || !which.stdout.trim()) {
9104
+ return {
9105
+ installed: false,
9106
+ connected: false,
9107
+ account: null,
9108
+ authMethod: null,
9109
+ reason: "origin CLI not found on PATH"
9110
+ };
9111
+ }
9112
+ const status = await run("origin", ["auth", "status"], { reject: false, timeoutMs: 15e3 });
9113
+ const text5 = `${status.stdout}
9114
+ ${status.stderr}`;
9115
+ const parsed = parseOriginAuthStatus(text5);
9116
+ if (status.exitCode === 0 && parsed.account) {
9117
+ return {
9118
+ installed: true,
9119
+ connected: true,
9120
+ account: parsed.account,
9121
+ authMethod: parsed.authMethod,
9122
+ reason: null
9123
+ };
9124
+ }
9125
+ return {
9126
+ installed: true,
9127
+ connected: false,
9128
+ account: null,
9129
+ authMethod: null,
9130
+ reason: status.stderr.trim() || status.stdout.trim() || "Not signed in to Cursor (Settings \u2192 Git \u2192 Cursor, or origin auth login)"
9131
+ };
9132
+ }
9133
+ async function loginCursorGit() {
9134
+ const status = await getCursorGitStatus();
9135
+ if (!status.installed) {
9136
+ return { ok: false, message: status.reason || "origin CLI not found on PATH" };
9137
+ }
9138
+ await openInSystemTerminal("origin auth login");
9139
+ return {
9140
+ ok: true,
9141
+ openedTerminal: true,
9142
+ command: "origin auth login",
9143
+ message: "Opened Terminal to run: origin auth login"
9144
+ };
9145
+ }
9146
+ async function setupCursorGit() {
9147
+ const status = await getCursorGitStatus();
9148
+ if (!status.installed) {
9149
+ return { ok: false, message: status.reason || "origin CLI not found on PATH" };
9150
+ }
9151
+ const result = await run("origin", ["auth", "setup-git"], {
9152
+ reject: false,
9153
+ timeoutMs: 2e4
9154
+ });
9155
+ const message = result.stdout.trim() || result.stderr.trim() || (result.exitCode === 0 ? "Git is configured to authenticate Origin through the origin CLI." : "origin auth setup-git failed");
9156
+ return {
9157
+ ok: result.exitCode === 0,
9158
+ command: "origin auth setup-git",
9159
+ message,
9160
+ stdout: result.stdout,
9161
+ stderr: result.stderr,
9162
+ exitCode: result.exitCode
9163
+ };
9164
+ }
9165
+
9166
+ // src/integrations/entire-git.ts
9167
+ function parseEntireAuthContexts(text5) {
9168
+ for (const line of text5.split("\n")) {
9169
+ if (!/\(active\)/i.test(line)) continue;
9170
+ const cols = line.replace(/\(active\)/gi, "").trim().split(/\s{2,}/).map((part) => part.trim()).filter(Boolean);
9171
+ const handle = cols[1] || cols[0] || null;
9172
+ if (handle && !/^context$/i.test(handle)) return { account: handle };
9173
+ }
9174
+ return { account: null };
9175
+ }
9176
+ async function getEntireGitStatus() {
9177
+ const which = await run("which", ["entire"], { reject: false, timeoutMs: 5e3 });
9178
+ if (which.exitCode !== 0 || !which.stdout.trim()) {
9179
+ return {
9180
+ installed: false,
9181
+ connected: false,
9182
+ account: null,
9183
+ reason: "entire CLI not found on PATH"
9184
+ };
9185
+ }
9186
+ const status = await run("entire", ["auth", "contexts"], { reject: false, timeoutMs: 15e3 });
9187
+ const parsed = parseEntireAuthContexts(status.stdout);
9188
+ if (status.exitCode === 0 && parsed.account) {
9189
+ return {
9190
+ installed: true,
9191
+ connected: true,
9192
+ account: parsed.account,
9193
+ reason: null
9194
+ };
9195
+ }
9196
+ return {
9197
+ installed: true,
9198
+ connected: false,
9199
+ account: null,
9200
+ reason: status.stderr.trim() || "Not signed in to Entire (Settings \u2192 Git \u2192 Entire, or entire login)"
9201
+ };
9202
+ }
9203
+ async function loginEntireGit() {
9204
+ const status = await getEntireGitStatus();
9205
+ if (!status.installed) {
9206
+ return { ok: false, message: status.reason || "entire CLI not found on PATH" };
9207
+ }
9208
+ await openInSystemTerminal("entire login");
9209
+ return {
9210
+ ok: true,
9211
+ openedTerminal: true,
9212
+ command: "entire login",
9213
+ message: "Opened Terminal to run: entire login"
9214
+ };
9215
+ }
9216
+
8838
9217
  // src/composer/diff-comment.ts
8839
9218
  function lineRangeLabel(lines) {
8840
9219
  const nos = lines.map((l) => l.lineNo);
@@ -9723,11 +10102,15 @@ function fail2(err) {
9723
10102
  true
9724
10103
  );
9725
10104
  }
10105
+ async function cursorIssueBlock(repoPath) {
10106
+ const cwd = await resolveRepoRoot((repoPath ?? "").trim() || process.cwd());
10107
+ return cursorIssuesUnavailableReason(cwd);
10108
+ }
9726
10109
  var repoPathSchema = z3.string().optional().describe("Workspace / worktree path. Omit on a worktree turn (uses cwd).");
9727
10110
  function registerGithubIssueTools(server) {
9728
10111
  server.tool(
9729
10112
  "github_search_issues",
9730
- "Search or list open GitHub issues in this repo via Account gh. Default 40; pass query and/or limit (max 250) when truncated. assignee: me, unassigned, all, or a login. Pass updatedSince for new/updated tickets and new comments (e.g. \u201Cany updates since yesterday?\u201D).",
10113
+ "Search or list open GitHub issues in this repo via Account gh. A Cursor origin returns unavailableReason \u2014 Origin has no issue tracker. An Entire origin does the same \u2014 tickets there are Trails (`entire trail`), not GitHub Issues. Default 40; pass query and/or limit (max 250) when truncated. assignee: me, unassigned, all, or a login. Pass updatedSince for new/updated tickets and new comments (e.g. \u201Cany updates since yesterday?\u201D).",
9731
10114
  {
9732
10115
  query: z3.string().optional().describe("Search text (title, body, identifiers). Omit to list by assignee only."),
9733
10116
  assignee: z3.string().optional().describe("me, unassigned, all, or a GitHub login. Default: all when query is set, otherwise me."),
@@ -9739,6 +10122,15 @@ function registerGithubIssueTools(server) {
9739
10122
  try {
9740
10123
  const cwd = await resolveRepoRoot((repoPath ?? "").trim() || process.cwd());
9741
10124
  const page = clampMcpIssueLimit(limit);
10125
+ const blocked = await cursorIssuesUnavailableReason(cwd);
10126
+ if (blocked) {
10127
+ return mcpJson(
10128
+ formatListedIssuesForMcp(
10129
+ { source: "github", issues: [], unavailableReason: blocked },
10130
+ page
10131
+ )
10132
+ );
10133
+ }
9742
10134
  const since = updatedSince ? parseIssueSince(updatedSince) : void 0;
9743
10135
  const issues = await listGitHubIssues(cwd, {
9744
10136
  query,
@@ -9774,6 +10166,8 @@ function registerGithubIssueTools(server) {
9774
10166
  { repoPath: repoPathSchema },
9775
10167
  async ({ repoPath }) => {
9776
10168
  try {
10169
+ const blocked = await cursorIssueBlock(repoPath);
10170
+ if (blocked) throw new Error(blocked);
9777
10171
  return text2({ projects: await listGitHubProjects({ repoPath }) });
9778
10172
  } catch (err) {
9779
10173
  return fail2(err);
@@ -9786,6 +10180,8 @@ function registerGithubIssueTools(server) {
9786
10180
  { id: z3.string(), include: mcpIssueIncludeSchema, repoPath: repoPathSchema },
9787
10181
  async ({ id, include, repoPath }) => {
9788
10182
  try {
10183
+ const blocked = await cursorIssueBlock(repoPath);
10184
+ if (blocked) throw new Error(blocked);
9789
10185
  return text2(formatGitHubIssuePayload(await getGitHubIssue(id, { repoPath }), include));
9790
10186
  } catch (err) {
9791
10187
  return fail2(err);
@@ -9814,6 +10210,8 @@ function registerGithubIssueTools(server) {
9814
10210
  { id: z3.string(), body: z3.string(), repoPath: repoPathSchema },
9815
10211
  async ({ id, body, repoPath }) => {
9816
10212
  try {
10213
+ const blocked = await cursorIssueBlock(repoPath);
10214
+ if (blocked) throw new Error(blocked);
9817
10215
  return text2(await commentGitHubIssue({ id, body }, { repoPath }));
9818
10216
  } catch (err) {
9819
10217
  return fail2(err);
@@ -9841,6 +10239,8 @@ function registerGithubIssueTools(server) {
9841
10239
  },
9842
10240
  async (args) => {
9843
10241
  try {
10242
+ const blocked = await cursorIssueBlock(args.repoPath);
10243
+ if (blocked) throw new Error(blocked);
9844
10244
  return text2(await updateGitHubIssue(args, { repoPath: args.repoPath }));
9845
10245
  } catch (err) {
9846
10246
  return fail2(err);
@@ -9858,6 +10258,8 @@ function registerGithubIssueTools(server) {
9858
10258
  },
9859
10259
  async (args) => {
9860
10260
  try {
10261
+ const blocked = await cursorIssueBlock(args.repoPath);
10262
+ if (blocked) throw new Error(blocked);
9861
10263
  return text2(await createGitHubIssue(args, { repoPath: args.repoPath }));
9862
10264
  } catch (err) {
9863
10265
  return fail2(err);
@@ -10690,7 +11092,7 @@ async function handleJobStop(params, _ctx) {
10690
11092
  return stopDetachedJob(jobCwd(rec), id, reason ? { reason } : void 0);
10691
11093
  }
10692
11094
  async function defaultTurnWait(ref, timeoutMs) {
10693
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-NPFWU3XU.js");
11095
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-B4STIW4B.js");
10694
11096
  const orch = getOrchestrator2();
10695
11097
  const thread = await orch.waitForTurn(ref, timeoutMs, {
10696
11098
  resolveIfStillRunning: true
@@ -11078,13 +11480,13 @@ async function startMcpServer() {
11078
11480
  if (!worktreeProfile) {
11079
11481
  server.tool(
11080
11482
  "list_projects",
11081
- "List registered projects (git repos). Each line is name, path, github:owner/repo when resolvable, and project context when set \u2014 use path as repoPath for list_board/list_branches/list_prs/list_issues/create_workspace. Account / project context (Settings \u2192 Agents / Projects) says which tickets and review PRs belong to the user.",
11483
+ "List registered projects (git repos). Each line is name, path, that repo's origin as host:owner/repo (github:, cursor:, entire:, or another hostname), and project context when set. Projects do not share one git host. Use path as repoPath for list_board/list_branches/list_prs/list_issues/create_workspace. Account / project context (Settings \u2192 Agents / Projects) says which tickets and review PRs belong to the user.",
11082
11484
  {},
11083
11485
  async () => {
11084
11486
  const workspaces = orch.listWorkspaces();
11085
11487
  const lines = await Promise.all(
11086
11488
  workspaces.map(async (w) => {
11087
- const slug = await resolveGithubRepoSlug(w.path).catch(() => null);
11489
+ const tag = await resolveProjectRemoteTag(w.path).catch(() => null);
11088
11490
  let profile;
11089
11491
  try {
11090
11492
  profile = resolveViewerProfileForRepo(w.path);
@@ -11092,7 +11494,7 @@ async function startMcpServer() {
11092
11494
  profile = resolveViewerProfile();
11093
11495
  }
11094
11496
  const suffix = formatWorkspaceProfileSuffix(profile);
11095
- return slug ? `${w.name} ${w.path} github:${slug}${suffix}` : `${w.name} ${w.path}${suffix}`;
11497
+ return tag ? `${w.name} ${w.path} ${tag}${suffix}` : `${w.name} ${w.path}${suffix}`;
11096
11498
  })
11097
11499
  );
11098
11500
  return {
@@ -11939,7 +12341,7 @@ async function startMcpServer() {
11939
12341
  error: true,
11940
12342
  action,
11941
12343
  lastError: message,
11942
- hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_chat so the worktree agent runs gh pr create --draft --assignee @me -R <origin> --body-file <short.md>. Keep the description short." : void 0
12344
+ hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_chat so the worktree agent retries with a short body (GitHub: gh pr create --draft --assignee @me -R <slug>; Cursor: origin pr create --draft --push -R <slug>; Entire: entire trail create --title with a short --body). Keep the description short." : void 0
11943
12345
  },
11944
12346
  true
11945
12347
  );
@@ -12249,7 +12651,7 @@ async function startMcpServer() {
12249
12651
  );
12250
12652
  server.tool(
12251
12653
  "list_issues",
12252
- "List or search issues (Linear, AbleTime, or GitHub; falls back to GitHub). Use Settings \u2192 Agents / Projects notes and roles to pick tickets relevant to the viewer (query + assignee=me or unassigned as the notes say). Default 40; pass query and/or limit (max 250) when truncated. assignee: me (Linear default), unassigned, all, or a user id. Pass updatedSince for new/updated tickets and new comments (\u201Cany updates since yesterday?\u201D). Then create_workspace with sourceType=ticket.",
12654
+ "List or search issues (Linear, AbleTime, or GitHub; falls back to GitHub). Cursor Origin has no issue tracker \u2014 a Cursor repo returns unavailableReason unless Linear or AbleTime is the source. Entire tickets are Trails (`entire trail`), not GitHub Issues, so an Entire repo does the same unless Linear or AbleTime is the source. Use Settings \u2192 Agents / Projects notes and roles to pick tickets relevant to the viewer (query + assignee=me or unassigned as the notes say). Default 40; pass query and/or limit (max 250) when truncated. assignee: me (Linear default), unassigned, all, or a user id. Pass updatedSince for new/updated tickets and new comments (\u201Cany updates since yesterday?\u201D). Then create_workspace with sourceType=ticket.",
12253
12655
  {
12254
12656
  repoPath: z8.string(),
12255
12657
  query: z8.string().optional().describe("Search title, identifier, or description"),
@@ -12275,7 +12677,7 @@ async function startMcpServer() {
12275
12677
  }
12276
12678
 
12277
12679
  // src/agent-rpc/server.ts
12278
- import { randomBytes as randomBytes6, randomUUID as randomUUID8, timingSafeEqual as timingSafeEqual2 } from "crypto";
12680
+ import { randomBytes as randomBytes7, randomUUID as randomUUID8, timingSafeEqual as timingSafeEqual2 } from "crypto";
12279
12681
  import { createServer as createServer3 } from "http";
12280
12682
  import { WebSocketServer as WebSocketServer2 } from "ws";
12281
12683
  function tokensEqual(a, b) {
@@ -12315,7 +12717,7 @@ var AgentRpcServer = class {
12315
12717
  async listen(opts = {}) {
12316
12718
  const host = opts.host ?? "127.0.0.1";
12317
12719
  const port = opts.port ?? 0;
12318
- const authToken = randomBytes6(24).toString("base64url");
12720
+ const authToken = randomBytes7(24).toString("base64url");
12319
12721
  this.meta = {
12320
12722
  runtimeId: randomUUID8(),
12321
12723
  pid: process.pid,
@@ -13168,7 +13570,7 @@ function slackTokenFor(ws, kind = "read") {
13168
13570
  }
13169
13571
 
13170
13572
  // src/slack/oauth.ts
13171
- import { randomBytes as randomBytes7 } from "crypto";
13573
+ import { randomBytes as randomBytes8 } from "crypto";
13172
13574
  var SLACK_BOT_SCOPES = [
13173
13575
  "app_mentions:read",
13174
13576
  "channels:history",
@@ -13261,7 +13663,7 @@ async function startSlackOAuth(opts) {
13261
13663
  throw new SlackOAuthCancelledError();
13262
13664
  }
13263
13665
  const { clientId } = slackOAuthCredentials();
13264
- const state = randomBytes7(16).toString("hex");
13666
+ const state = randomBytes8(16).toString("hex");
13265
13667
  const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
13266
13668
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
13267
13669
  const pollIntervalMs = opts?.pollIntervalMs ?? 400;
@@ -14154,7 +14556,7 @@ function resolveSlackListenMode(opts) {
14154
14556
  }
14155
14557
 
14156
14558
  // src/relay/account-login.ts
14157
- import { randomBytes as randomBytes8 } from "crypto";
14559
+ import { randomBytes as randomBytes9 } from "crypto";
14158
14560
  var RemoteAccountLoginCancelled = class extends Error {
14159
14561
  constructor() {
14160
14562
  super("Sign-in cancelled");
@@ -14207,7 +14609,7 @@ async function relayFetch(fetchImpl, url, init) {
14207
14609
  throw relayFetchError(err, url);
14208
14610
  }
14209
14611
  }
14210
- async function readJson2(res, url) {
14612
+ async function readJson3(res, url) {
14211
14613
  try {
14212
14614
  return await res.json();
14213
14615
  } catch {
@@ -14220,7 +14622,7 @@ async function readJson2(res, url) {
14220
14622
  async function startRemoteAccountLogin(opts) {
14221
14623
  if (opts.signal?.aborted) throw new RemoteAccountLoginCancelled();
14222
14624
  const origin = (opts.origin ?? remoteAccountHttpOrigin()).replace(/\/+$/, "");
14223
- const state = randomBytes8(16).toString("hex");
14625
+ const state = randomBytes9(16).toString("hex");
14224
14626
  const timeoutMs = opts.timeoutMs ?? 5 * 6e4;
14225
14627
  const pollIntervalMs = opts.pollIntervalMs ?? 400;
14226
14628
  const linkToken = opts.linkToken?.trim() ?? "";
@@ -14234,7 +14636,7 @@ async function startRemoteAccountLogin(opts) {
14234
14636
  ...linkToken ? { accountToken: linkToken } : {}
14235
14637
  })
14236
14638
  });
14237
- const startBody = await readJson2(started, startUrl);
14639
+ const startBody = await readJson3(started, startUrl);
14238
14640
  if (!started.ok || !startBody.url) {
14239
14641
  throw new Error(startBody.error || `Could not start sign-in (HTTP ${started.status}).`);
14240
14642
  }
@@ -14358,7 +14760,7 @@ async function continueSourceThread(threadId, prompt) {
14358
14760
  await continueOnReply(threadId, prompt);
14359
14761
  return;
14360
14762
  }
14361
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-NPFWU3XU.js");
14763
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-B4STIW4B.js");
14362
14764
  await getOrchestrator2().send(threadId, prompt);
14363
14765
  } catch {
14364
14766
  }
@@ -14672,12 +15074,14 @@ export {
14672
15074
  CONTEXT_REVIEW_PATH,
14673
15075
  CONVENTION_SETUP_RELPATHS,
14674
15076
  COORDINATOR_TOOL_PLAYBOOK,
15077
+ CURSOR_ISSUES_UNAVAILABLE,
14675
15078
  CURSOR_SDK_INSTALL_HINT,
14676
15079
  DEFAULT_ABLETIME_HOST,
14677
15080
  DEFAULT_RUN_LOG_TAIL_CHARS,
14678
15081
  DEFAULT_WORKTREE_SORT,
14679
15082
  DETACHED_JOBS_DIR,
14680
15083
  EMPTY_MANAGED_ACCOUNTS,
15084
+ ENTIRE_ISSUES_ARE_TRAILS,
14681
15085
  FAMOUS_SOCCER_TEAMS,
14682
15086
  FOLLOW_UP_BEHAVIORS,
14683
15087
  GITHUB_GIT_AUTH_MODES,
@@ -14945,6 +15349,7 @@ export {
14945
15349
  createThreadWorktree,
14946
15350
  currentBranch,
14947
15351
  cursorAdapter,
15352
+ cursorIssuesUnavailableReason,
14948
15353
  cursorSdkMessageToEvents,
14949
15354
  decodeBrightsyTarget,
14950
15355
  defaultScheduleName,
@@ -14994,6 +15399,7 @@ export {
14994
15399
  ensureSlackCoordinator,
14995
15400
  ensureSlackDeviceIdentity,
14996
15401
  ensureWorkspace,
15402
+ entireUsesTrails,
14997
15403
  estimateMessageChars,
14998
15404
  estimateOccupancyTokens,
14999
15405
  estimateThreadChars,
@@ -15044,8 +15450,10 @@ export {
15044
15450
  formatClaudeUsageTooltip,
15045
15451
  formatCloudTurnReply,
15046
15452
  formatConnectedOrchestratorReminder,
15453
+ formatCursorGitDirective,
15047
15454
  formatDetachedJobInvoke,
15048
15455
  formatDevAccessHint,
15456
+ formatEntireGitDirective,
15049
15457
  formatFetchError,
15050
15458
  formatGhLandError,
15051
15459
  formatGitAuthModeDirective,
@@ -15102,6 +15510,7 @@ export {
15102
15510
  getBrightsySession,
15103
15511
  getCaffeinateHold,
15104
15512
  getClaudePlanUsage,
15513
+ getCursorGitStatus,
15105
15514
  getDefaultAgent,
15106
15515
  getDefaultAutonomy,
15107
15516
  getDefaultEffort,
@@ -15110,6 +15519,7 @@ export {
15110
15519
  getDefaultRunScript,
15111
15520
  getDiff,
15112
15521
  getDiffSummary,
15522
+ getEntireGitStatus,
15113
15523
  getGitHubIssue,
15114
15524
  getGitHubStatus,
15115
15525
  getGithubGitAuthMode,
@@ -15327,6 +15737,8 @@ export {
15327
15737
  localhostPreviewUrl,
15328
15738
  locksDir,
15329
15739
  loginAgent,
15740
+ loginCursorGit,
15741
+ loginEntireGit,
15330
15742
  loginEnvPrefix,
15331
15743
  loginManagedAccount,
15332
15744
  looksLikeComposerSkillExpansion,
@@ -15393,6 +15805,7 @@ export {
15393
15805
  orchestrationQuotaOnLimit,
15394
15806
  orchestrationTitleNeedsSoccerNickname,
15395
15807
  orchestratorSessionPoisonedByBuiltins,
15808
+ originCli,
15396
15809
  originFetchBranch,
15397
15810
  originGhRepoEnv,
15398
15811
  outboundReplyFromTurn,
@@ -15403,11 +15816,13 @@ export {
15403
15816
  parseCursorRunnerLine,
15404
15817
  parseDevPreview,
15405
15818
  parseDurationMs,
15819
+ parseEntireAuthContexts,
15406
15820
  parseForceStopMessage,
15407
15821
  parseGhStackViewJson,
15408
15822
  parseGitHubIssueNumber,
15409
15823
  parseGithubSlugFromRemoteUrl,
15410
15824
  parseMcpList,
15825
+ parseOriginAuthStatus,
15411
15826
  parsePlanQuestionsInput,
15412
15827
  parsePrDetailsView,
15413
15828
  parseSessionQuotaResetAt,
@@ -15510,9 +15925,11 @@ export {
15510
15925
  resolveNewThreadOptions,
15511
15926
  resolveOrchChildFollowUp,
15512
15927
  resolveOrchestratorDefaults,
15928
+ resolveOriginRemote,
15513
15929
  resolvePlanMarkdown,
15514
15930
  resolvePrSelector,
15515
15931
  resolvePrSelectors,
15932
+ resolveProjectRemoteTag,
15516
15933
  resolveProjectReviewLabel,
15517
15934
  resolveQuotaFallbackAgent,
15518
15935
  resolveRepoRoot,
@@ -15563,6 +15980,7 @@ export {
15563
15980
  setStatus,
15564
15981
  setVaultMasterKey,
15565
15982
  settingsSourceLabel,
15983
+ setupCursorGit,
15566
15984
  shiftQueuedItem,
15567
15985
  shouldAttachPastedText,
15568
15986
  shouldCompactContext,