@sideboard-ai/core 0.1.320 → 0.1.322
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/agents/cursor-runner.js +2 -2
- package/dist/{agents-CJZYJOWP.js → agents-PFVYC36J.js} +8 -8
- package/dist/{agents-F2E2HACB.js → agents-ROFDNE7Z.js} +9 -9
- package/dist/{chunk-QVN2WOKJ.js → chunk-2TUE6JKQ.js} +12 -0
- package/dist/{chunk-B7UL36WH.js → chunk-45UB2J47.js} +335 -65
- package/dist/{chunk-DD67JWTN.js → chunk-4YXZOXMT.js} +1 -1
- package/dist/{chunk-V5BTGQ6M.js → chunk-6U6QRUHY.js} +1 -1
- package/dist/{chunk-QGY3UNNL.js → chunk-7JV5QP5K.js} +1 -1
- package/dist/{chunk-DJZRDTZY.js → chunk-BANN5HUX.js} +6 -6
- package/dist/{chunk-CB5Z5C3J.js → chunk-BPDVHB4U.js} +1 -1
- package/dist/{chunk-RHJPP26T.js → chunk-H6GXYV5Q.js} +14 -11
- package/dist/{chunk-4GZC6DDH.js → chunk-IFWGG2M2.js} +7 -0
- package/dist/{chunk-LLIEU2ZB.js → chunk-JNEFEA2A.js} +6 -6
- package/dist/{chunk-IDPFLXRY.js → chunk-LD2DXHBP.js} +341 -67
- package/dist/{chunk-2P4XKWV2.js → chunk-QKHEVSB5.js} +1 -1
- package/dist/{chunk-P74GXA5V.js → chunk-RGUZPMTF.js} +6 -6
- package/dist/{chunk-UK2KESBN.js → chunk-RHJKZOPQ.js} +3 -3
- package/dist/{chunk-HH3VVTEC.js → chunk-S5CJUIPY.js} +5 -5
- package/dist/{chunk-5S3YP5KH.js → chunk-SPMIZSKH.js} +14 -11
- package/dist/{chunk-EQ5JY3MJ.js → chunk-TEFFR6PB.js} +1 -1
- package/dist/{chunk-EDXTP2VR.js → chunk-UWJUARFA.js} +545 -186
- package/dist/{chunk-OAFBHCSM.js → chunk-UX6EDDGR.js} +1 -1
- package/dist/{chunk-ZYZBCLJR.js → chunk-XDQSHSL6.js} +6 -6
- package/dist/{chunk-2UG25RMK.js → chunk-YBTSZ2SW.js} +12 -0
- package/dist/{chunk-PNLGWAYE.js → chunk-YWBLQBSN.js} +548 -187
- package/dist/{chunk-Y3Y7SZBZ.js → chunk-ZHGMRBSC.js} +1 -1
- package/dist/{conductor-FPFY6Z5S.js → conductor-CNT3VL3S.js} +6 -6
- package/dist/{conductor-JA5W3L7C.js → conductor-XLXJU24U.js} +6 -6
- package/dist/{connected-teams-IHK2WXUI.js → connected-teams-H4LZOJDC.js} +2 -2
- package/dist/{connected-teams-IFW3NQ6G.js → connected-teams-XYRZMQO4.js} +2 -2
- package/dist/{coordinator-prompt-NUC2ZXMJ.js → coordinator-prompt-D5EE2YTV.js} +5 -5
- package/dist/{coordinator-prompt-M75TAN43.js → coordinator-prompt-TU24TQ4I.js} +5 -5
- package/dist/{global-workspace-5A4H34AF.js → global-workspace-743TPQNF.js} +5 -5
- package/dist/{global-workspace-SCLQUNUI.js → global-workspace-UPMXDQM7.js} +5 -5
- package/dist/index.cjs +1577 -471
- package/dist/index.d.cts +182 -70
- package/dist/index.d.ts +182 -70
- package/dist/index.js +480 -62
- package/dist/mcp/run-stdio.cjs +1159 -447
- package/dist/mcp/run-stdio.js +65 -17
- package/dist/{optional-cli-MRNQKVIR.js → optional-cli-2YDQQCCD.js} +4 -4
- package/dist/{optional-cli-2V3SLME5.js → optional-cli-USD6PROE.js} +3 -3
- package/dist/{orchestrator-NPFWU3XU.js → orchestrator-B4STIW4B.js} +12 -12
- package/dist/{orchestrator-7BDZ5GWD.js → orchestrator-VQ4HRYVB.js} +11 -11
- package/dist/{run-PCX5QWR4.js → run-7QMRYP3F.js} +3 -1
- package/dist/{run-TB7RBII2.js → run-UPNCCRCN.js} +3 -1
- package/dist/{thread-store-JWHVXLDX.js → thread-store-3F7GR64A.js} +1 -1
- package/dist/{thread-store-QHYN2ZMQ.js → thread-store-JRSL4HQY.js} +1 -1
- package/dist/{workspaces-KWMBOTQD.js → workspaces-47WQL5IG.js} +5 -5
- package/dist/{workspaces-5QA3YM4L.js → workspaces-75FD4QUR.js} +5 -5
- package/dist/{worktree-O6BANO2I.js → worktree-G3E6WP66.js} +10 -8
- package/dist/{worktree-7EATHVYQ.js → worktree-PDNPL5CQ.js} +10 -8
- package/dist/{worktree-exclude-RXZPTCNH.js → worktree-exclude-INRDQFWV.js} +2 -2
- package/dist/{worktree-exclude-5N2KTYIT.js → worktree-exclude-P5NJODWP.js} +2 -2
- package/package.json +1 -1
- /package/dist/{chunk-XMHMVEIY.js → chunk-B4CDSSRN.js} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -5083,6 +5083,12 @@ function workspaceNameLabel(thread) {
|
|
|
5083
5083
|
if (repo && worktreeNameFromPath(repo).toLowerCase() === dir.toLowerCase()) return null;
|
|
5084
5084
|
return agentNicknameFromWorktreePath(path2) ?? dir;
|
|
5085
5085
|
}
|
|
5086
|
+
function workspaceRowLabel(threads) {
|
|
5087
|
+
if (threads.length === 0) return { label: "Worktree" };
|
|
5088
|
+
const label = worktreeAnchorLabel(threads).title;
|
|
5089
|
+
const named = workspaceNameLabel(threads[0]);
|
|
5090
|
+
return named && named !== label ? { label, workspace: named } : { label };
|
|
5091
|
+
}
|
|
5086
5092
|
function worktreeIdentityTitles(thread, parentTitle) {
|
|
5087
5093
|
const out = [];
|
|
5088
5094
|
const push2 = (value) => {
|
|
@@ -9339,6 +9345,7 @@ var run_exports = {};
|
|
|
9339
9345
|
__export(run_exports, {
|
|
9340
9346
|
gh: () => gh,
|
|
9341
9347
|
git: () => git,
|
|
9348
|
+
originCli: () => originCli,
|
|
9342
9349
|
resolveGhAuthToken: () => resolveGhAuthToken,
|
|
9343
9350
|
resolveGitDirsForLockRecovery: () => resolveGitDirsForLockRecovery,
|
|
9344
9351
|
run: () => run
|
|
@@ -9419,6 +9426,17 @@ ${result.stderr}`
|
|
|
9419
9426
|
}
|
|
9420
9427
|
return result;
|
|
9421
9428
|
}
|
|
9429
|
+
async function originCli(args, cwd, opts) {
|
|
9430
|
+
return run("origin", args, {
|
|
9431
|
+
cwd,
|
|
9432
|
+
reject: opts?.reject,
|
|
9433
|
+
timeoutMs: opts?.timeoutMs,
|
|
9434
|
+
env: {
|
|
9435
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
9436
|
+
NO_COLOR: "1"
|
|
9437
|
+
}
|
|
9438
|
+
});
|
|
9439
|
+
}
|
|
9422
9440
|
async function gh(args, cwd, opts) {
|
|
9423
9441
|
return run("gh", args, {
|
|
9424
9442
|
cwd,
|
|
@@ -9629,9 +9647,9 @@ var init_worktree_exclude = __esm({
|
|
|
9629
9647
|
});
|
|
9630
9648
|
|
|
9631
9649
|
// src/git/git-auth-mode.ts
|
|
9632
|
-
function githubHttpsInsteadOfEntries(
|
|
9650
|
+
function githubHttpsInsteadOfEntries(remoteUrl2) {
|
|
9633
9651
|
const entries = [...HTTPS_REWRITE];
|
|
9634
|
-
const url =
|
|
9652
|
+
const url = remoteUrl2?.trim() ?? "";
|
|
9635
9653
|
const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
|
|
9636
9654
|
if (scpAlias?.[1]) {
|
|
9637
9655
|
entries.push({
|
|
@@ -9841,6 +9859,58 @@ var init_git_auth_mode = __esm({
|
|
|
9841
9859
|
}
|
|
9842
9860
|
});
|
|
9843
9861
|
|
|
9862
|
+
// src/git/remote-forge.ts
|
|
9863
|
+
function formatRemoteTag(remote) {
|
|
9864
|
+
const name = remote.forge === "other" ? remote.host : remote.forge;
|
|
9865
|
+
return `${name}:${remote.slug}`;
|
|
9866
|
+
}
|
|
9867
|
+
function forgeForHost(host) {
|
|
9868
|
+
const h = host.toLowerCase();
|
|
9869
|
+
if (h === "github.com" || h.startsWith("github.com-")) return "github";
|
|
9870
|
+
if (h === "origin.cursor.com") return "cursor";
|
|
9871
|
+
if (h === "entire.io" || h.endsWith(".entire.io") || h === "entire.com" || h.endsWith(".entire.com")) {
|
|
9872
|
+
return "entire";
|
|
9873
|
+
}
|
|
9874
|
+
return "other";
|
|
9875
|
+
}
|
|
9876
|
+
function repoFromParts(host, owner, name) {
|
|
9877
|
+
if (!host || !owner || !name || owner.includes("@")) return null;
|
|
9878
|
+
const normalized = host.toLowerCase();
|
|
9879
|
+
return {
|
|
9880
|
+
forge: forgeForHost(normalized),
|
|
9881
|
+
host: normalized,
|
|
9882
|
+
slug: `${owner}/${name}`
|
|
9883
|
+
};
|
|
9884
|
+
}
|
|
9885
|
+
function parseRemoteRepo(url) {
|
|
9886
|
+
const trimmed = url.trim().replace(/\.git$/i, "");
|
|
9887
|
+
if (!trimmed) return null;
|
|
9888
|
+
if (trimmed.toLowerCase().startsWith("entire://")) {
|
|
9889
|
+
const parts = trimmed.slice("entire://".length).replace(/^\/+/, "").split("/").filter(Boolean);
|
|
9890
|
+
if (parts.length === 2) return { forge: "entire", host: "entire.io", slug: `${parts[0]}/${parts[1]}` };
|
|
9891
|
+
if (parts.length >= 3) {
|
|
9892
|
+
return repoFromParts(parts[0], parts[1], parts[2]);
|
|
9893
|
+
}
|
|
9894
|
+
return null;
|
|
9895
|
+
}
|
|
9896
|
+
const ssh = trimmed.match(/^git@([^:]+):([^/]+)\/([^/]+)$/i);
|
|
9897
|
+
if (ssh?.[1] && ssh[2] && ssh[3]) return repoFromParts(ssh[1], ssh[2], ssh[3]);
|
|
9898
|
+
try {
|
|
9899
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
9900
|
+
const parsed = new URL(withScheme);
|
|
9901
|
+
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
9902
|
+
if (parts.length < 2) return null;
|
|
9903
|
+
return repoFromParts(parsed.hostname, parts[parts.length - 2], parts[parts.length - 1]);
|
|
9904
|
+
} catch {
|
|
9905
|
+
return null;
|
|
9906
|
+
}
|
|
9907
|
+
}
|
|
9908
|
+
var init_remote_forge = __esm({
|
|
9909
|
+
"src/git/remote-forge.ts"() {
|
|
9910
|
+
"use strict";
|
|
9911
|
+
}
|
|
9912
|
+
});
|
|
9913
|
+
|
|
9844
9914
|
// src/git/list-prs.ts
|
|
9845
9915
|
function normalizePrListState(state) {
|
|
9846
9916
|
const key = (state ?? "").trim().toLowerCase();
|
|
@@ -10209,6 +10279,345 @@ var init_list_prs = __esm({
|
|
|
10209
10279
|
}
|
|
10210
10280
|
});
|
|
10211
10281
|
|
|
10282
|
+
// src/git/cursor-pr.ts
|
|
10283
|
+
function repoArgs(slug) {
|
|
10284
|
+
return ["-R", slug];
|
|
10285
|
+
}
|
|
10286
|
+
function cursorHeadBranch(head, slug) {
|
|
10287
|
+
const branch = head.trim().replace(/^refs\/heads\//, "");
|
|
10288
|
+
const owner = slug.split("/")[0];
|
|
10289
|
+
if (owner && branch.startsWith(`${owner}:`)) return branch.slice(owner.length + 1);
|
|
10290
|
+
return branch;
|
|
10291
|
+
}
|
|
10292
|
+
function cursorMergeFields(value) {
|
|
10293
|
+
if (typeof value === "string" && value.trim()) {
|
|
10294
|
+
const upper = value.trim().toUpperCase();
|
|
10295
|
+
return { mergeable: upper, mergeStateStatus: upper };
|
|
10296
|
+
}
|
|
10297
|
+
if (value && typeof value === "object") {
|
|
10298
|
+
const row2 = value;
|
|
10299
|
+
const conflictState = String(row2.mergeConflictState ?? "").trim().toUpperCase();
|
|
10300
|
+
if ("hasMergeConflicts" in row2 || conflictState) {
|
|
10301
|
+
if (conflictState.includes("PENDING")) {
|
|
10302
|
+
return { mergeable: "UNKNOWN", mergeStateStatus: "UNKNOWN" };
|
|
10303
|
+
}
|
|
10304
|
+
const conflicting = row2.hasMergeConflicts === true || conflictState.includes("CONFLICT") && !conflictState.includes("CLEAN");
|
|
10305
|
+
if (conflicting) return { mergeable: "CONFLICTING", mergeStateStatus: "DIRTY" };
|
|
10306
|
+
if (row2.hasMergeConflicts === false || conflictState.includes("CLEAN")) {
|
|
10307
|
+
return { mergeable: "MERGEABLE", mergeStateStatus: "CLEAN" };
|
|
10308
|
+
}
|
|
10309
|
+
}
|
|
10310
|
+
const verdict = String(row2.verdict ?? row2.verdictKind ?? "").trim().toUpperCase();
|
|
10311
|
+
if (verdict === "BLOCKED") return { mergeable: null, mergeStateStatus: "BLOCKED" };
|
|
10312
|
+
if (verdict === "MERGEABLE") return { mergeable: "MERGEABLE", mergeStateStatus: "CLEAN" };
|
|
10313
|
+
const status = String(row2.status ?? row2.state ?? row2.mergeable ?? "").trim().toUpperCase();
|
|
10314
|
+
return { mergeable: status || null, mergeStateStatus: status || null };
|
|
10315
|
+
}
|
|
10316
|
+
return { mergeable: null, mergeStateStatus: null };
|
|
10317
|
+
}
|
|
10318
|
+
function cursorReviewDecision(value) {
|
|
10319
|
+
const raw = typeof value === "string" ? value.trim().toUpperCase().replace(/[\s-]+/g, "_") : "";
|
|
10320
|
+
if (!raw) return null;
|
|
10321
|
+
if (raw === "REQUIRED" || raw === "REVIEW_REQUIRED") return "REVIEW_REQUIRED";
|
|
10322
|
+
if (raw === "CHANGES_REQUESTED") return "CHANGES_REQUESTED";
|
|
10323
|
+
if (raw === "APPROVED") return "APPROVED";
|
|
10324
|
+
return raw;
|
|
10325
|
+
}
|
|
10326
|
+
function cursorViewToPrMeta(view) {
|
|
10327
|
+
const merge = cursorMergeFields(view.mergeability ?? view.mergeable);
|
|
10328
|
+
const author = view.author ?? {};
|
|
10329
|
+
return {
|
|
10330
|
+
number: Number(view.number),
|
|
10331
|
+
title: String(view.title ?? ""),
|
|
10332
|
+
url: String(view.url ?? ""),
|
|
10333
|
+
state: String(view.state ?? ""),
|
|
10334
|
+
isDraft: Boolean(view.isDraft),
|
|
10335
|
+
reviewDecision: cursorReviewDecision(view.reviewDecision),
|
|
10336
|
+
baseRefName: String(view.baseRefName ?? ""),
|
|
10337
|
+
headRefName: String(view.headRefName ?? ""),
|
|
10338
|
+
isInMergeQueue: false,
|
|
10339
|
+
mergeable: merge.mergeable,
|
|
10340
|
+
mergeStateStatus: merge.mergeStateStatus,
|
|
10341
|
+
authorLogin: author.login?.trim() || null,
|
|
10342
|
+
reviewerLogins: [],
|
|
10343
|
+
labels: labelNames(view.labels)
|
|
10344
|
+
};
|
|
10345
|
+
}
|
|
10346
|
+
function loginOf(author) {
|
|
10347
|
+
if (!author || typeof author !== "object") return "";
|
|
10348
|
+
const row2 = author;
|
|
10349
|
+
for (const key of ["login", "handle", "email", "displayName", "name", "id"]) {
|
|
10350
|
+
const value = row2[key];
|
|
10351
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
10352
|
+
}
|
|
10353
|
+
return "";
|
|
10354
|
+
}
|
|
10355
|
+
function upperState(value, isDraft) {
|
|
10356
|
+
const raw = typeof value === "string" ? value.trim().toUpperCase() : "";
|
|
10357
|
+
if (raw === "DRAFT") return "OPEN";
|
|
10358
|
+
if (raw === "OPEN" || raw === "CLOSED" || raw === "MERGED") return raw;
|
|
10359
|
+
return isDraft ? "OPEN" : raw;
|
|
10360
|
+
}
|
|
10361
|
+
function normalizeOriginPr(raw) {
|
|
10362
|
+
const isDraft = raw.isDraft === true || String(raw.status ?? raw.state ?? "").toLowerCase() === "draft";
|
|
10363
|
+
const login = loginOf(raw.author);
|
|
10364
|
+
const author = raw.author && typeof raw.author === "object" ? { ...raw.author, login: login || "unknown" } : login ? { login } : { login: "unknown" };
|
|
10365
|
+
return {
|
|
10366
|
+
...raw,
|
|
10367
|
+
isDraft,
|
|
10368
|
+
state: upperState(raw.state ?? raw.status, isDraft),
|
|
10369
|
+
author,
|
|
10370
|
+
body: raw.body ?? raw.description ?? "",
|
|
10371
|
+
isCrossRepository: false,
|
|
10372
|
+
reviewDecision: cursorReviewDecision(raw.reviewDecision),
|
|
10373
|
+
reviewRequests: originReviewRequests(raw.reviewRequests)
|
|
10374
|
+
};
|
|
10375
|
+
}
|
|
10376
|
+
function originReviewRequests(raw) {
|
|
10377
|
+
if (!Array.isArray(raw)) return raw;
|
|
10378
|
+
return raw.map(originReviewer).filter((row2) => row2 != null);
|
|
10379
|
+
}
|
|
10380
|
+
function originReviewer(raw) {
|
|
10381
|
+
if (typeof raw === "string" && raw.trim()) return { login: raw.trim() };
|
|
10382
|
+
if (!raw || typeof raw !== "object") return null;
|
|
10383
|
+
const row2 = raw;
|
|
10384
|
+
if (typeof row2.login === "string" && row2.login.trim()) return row2;
|
|
10385
|
+
const kind = String(row2.kind ?? row2.__typename ?? "").toLowerCase();
|
|
10386
|
+
const slug = typeof row2.slug === "string" ? row2.slug.trim() : "";
|
|
10387
|
+
const name = typeof row2.name === "string" ? row2.name.trim() : "";
|
|
10388
|
+
const id = typeof row2.id === "string" ? row2.id.trim() : "";
|
|
10389
|
+
if (kind.includes("team") || kind.includes("group") || slug.includes("/") && !row2.login) {
|
|
10390
|
+
return { __typename: "Team", slug: slug || name, name };
|
|
10391
|
+
}
|
|
10392
|
+
if (kind.includes("service") || kind.includes("bot")) {
|
|
10393
|
+
const login2 = name || id || "cursor-bot";
|
|
10394
|
+
return { __typename: "Bot", login: login2.toLowerCase().endsWith("[bot]") ? login2 : `${login2}[bot]` };
|
|
10395
|
+
}
|
|
10396
|
+
const login = name || id;
|
|
10397
|
+
return login ? { login } : null;
|
|
10398
|
+
}
|
|
10399
|
+
function originChecksToRuns(stdout) {
|
|
10400
|
+
let parsed;
|
|
10401
|
+
try {
|
|
10402
|
+
parsed = JSON.parse(stdout);
|
|
10403
|
+
} catch {
|
|
10404
|
+
return [];
|
|
10405
|
+
}
|
|
10406
|
+
const rows = Array.isArray(parsed) ? parsed : [];
|
|
10407
|
+
return rows.map((row2) => {
|
|
10408
|
+
const item = row2 ?? {};
|
|
10409
|
+
const conclusion = typeof item.conclusion === "string" ? item.conclusion.toLowerCase() : "";
|
|
10410
|
+
const status = typeof item.status === "string" ? item.status.toLowerCase() : "";
|
|
10411
|
+
const bucket = conclusion === "success" || conclusion === "neutral" ? "pass" : conclusion === "failure" || conclusion === "timed_out" || conclusion === "action_required" ? "fail" : conclusion === "cancelled" ? "cancel" : conclusion === "skipped" ? "skipping" : "pending";
|
|
10412
|
+
const state = conclusion || status || "pending";
|
|
10413
|
+
const link = typeof item.link === "string" ? item.link : typeof item.detailsUrl === "string" ? item.detailsUrl : null;
|
|
10414
|
+
const description = typeof item.summary === "string" ? item.summary : typeof item.description === "string" ? item.description : null;
|
|
10415
|
+
return {
|
|
10416
|
+
name: String(item.name ?? "check"),
|
|
10417
|
+
state,
|
|
10418
|
+
bucket,
|
|
10419
|
+
startedAt: typeof item.startedAt === "string" ? item.startedAt : null,
|
|
10420
|
+
completedAt: typeof item.completedAt === "string" ? item.completedAt : null,
|
|
10421
|
+
link,
|
|
10422
|
+
description,
|
|
10423
|
+
workflow: typeof item.group === "string" ? item.group : null,
|
|
10424
|
+
kind: "ci"
|
|
10425
|
+
};
|
|
10426
|
+
});
|
|
10427
|
+
}
|
|
10428
|
+
function listedHasLabels(pr, labels) {
|
|
10429
|
+
if (labels.length === 0) return true;
|
|
10430
|
+
const have = new Set((pr.labels ?? []).map((name) => name.toLowerCase()));
|
|
10431
|
+
return labels.every((label) => have.has(label.toLowerCase()));
|
|
10432
|
+
}
|
|
10433
|
+
async function listCursorPrs(repoPath, slug, opts, head) {
|
|
10434
|
+
const resolved = resolveListPrsOptions(opts);
|
|
10435
|
+
const limit = Math.max(1, Math.min(250, resolved.limit ?? 200));
|
|
10436
|
+
const fetchLimit = prListFetchLimit(limit, resolved.reviewer);
|
|
10437
|
+
const useSearch = resolved.labels.length > 0 || Boolean(resolved.reviewer) || Boolean(resolved.query);
|
|
10438
|
+
const state = resolved.draft === true ? "draft" : resolved.state;
|
|
10439
|
+
const args = [
|
|
10440
|
+
"pr",
|
|
10441
|
+
"list",
|
|
10442
|
+
...repoArgs(slug),
|
|
10443
|
+
"--state",
|
|
10444
|
+
state,
|
|
10445
|
+
"--limit",
|
|
10446
|
+
String(fetchLimit),
|
|
10447
|
+
"--json",
|
|
10448
|
+
useSearch ? SEARCH_LIST_FIELDS : PLAIN_LIST_FIELDS
|
|
10449
|
+
];
|
|
10450
|
+
if (head?.trim()) args.push("--head", head.trim());
|
|
10451
|
+
if (useSearch) {
|
|
10452
|
+
for (const label of resolved.labels) args.push("--label", label);
|
|
10453
|
+
if (resolved.query) args.push("--search", resolved.query);
|
|
10454
|
+
else if (resolved.labels.length === 0) {
|
|
10455
|
+
const token = state === "all" ? "is:open OR is:closed OR is:merged" : `is:${state}`;
|
|
10456
|
+
args.push("--search", token);
|
|
10457
|
+
}
|
|
10458
|
+
}
|
|
10459
|
+
const { stdout, exitCode } = await originCli(args, repoPath, { reject: false, timeoutMs: 2e4 });
|
|
10460
|
+
if (exitCode !== 0 || !stdout.trim()) return [];
|
|
10461
|
+
let parsed;
|
|
10462
|
+
try {
|
|
10463
|
+
parsed = JSON.parse(stdout);
|
|
10464
|
+
} catch {
|
|
10465
|
+
return [];
|
|
10466
|
+
}
|
|
10467
|
+
if (!Array.isArray(parsed)) return [];
|
|
10468
|
+
const normalized = parsed.filter((row2) => row2 && typeof row2 === "object").map((row2) => normalizeOriginPr(row2));
|
|
10469
|
+
const listed = applyPrListResponse(JSON.stringify(normalized), { ...opts, limit: void 0 });
|
|
10470
|
+
return listed.filter((pr) => listedHasLabels(pr, resolved.labels)).slice(0, limit);
|
|
10471
|
+
}
|
|
10472
|
+
async function viewCursorPr(repoPath, slug, selector, fields) {
|
|
10473
|
+
const { stdout, exitCode } = await originCli(
|
|
10474
|
+
["pr", "view", selector, ...repoArgs(slug), "--json", fields],
|
|
10475
|
+
repoPath,
|
|
10476
|
+
{ reject: false, timeoutMs: 2e4 }
|
|
10477
|
+
);
|
|
10478
|
+
if (exitCode !== 0 || !stdout.trim()) return null;
|
|
10479
|
+
try {
|
|
10480
|
+
const parsed = JSON.parse(stdout);
|
|
10481
|
+
return normalizeOriginPr(parsed);
|
|
10482
|
+
} catch {
|
|
10483
|
+
return null;
|
|
10484
|
+
}
|
|
10485
|
+
}
|
|
10486
|
+
async function createOrUpdateCursorPr(repoPath, slug, opts) {
|
|
10487
|
+
const branch = cursorHeadBranch(opts.head, slug);
|
|
10488
|
+
const existing = await originCli(
|
|
10489
|
+
["pr", "view", branch, ...repoArgs(slug), "--json", "url"],
|
|
10490
|
+
repoPath,
|
|
10491
|
+
{ reject: false, timeoutMs: 2e4 }
|
|
10492
|
+
);
|
|
10493
|
+
if (existing.exitCode === 0 && existing.stdout.trim()) {
|
|
10494
|
+
let url2 = "";
|
|
10495
|
+
try {
|
|
10496
|
+
url2 = String(JSON.parse(existing.stdout).url ?? "");
|
|
10497
|
+
} catch {
|
|
10498
|
+
url2 = "";
|
|
10499
|
+
}
|
|
10500
|
+
if (url2) {
|
|
10501
|
+
await originCli(
|
|
10502
|
+
["pr", "edit", branch, ...repoArgs(slug), "--title", opts.title, "-F", opts.bodyFile],
|
|
10503
|
+
repoPath,
|
|
10504
|
+
{ reject: false, timeoutMs: 2e4 }
|
|
10505
|
+
);
|
|
10506
|
+
return url2;
|
|
10507
|
+
}
|
|
10508
|
+
}
|
|
10509
|
+
const args = [
|
|
10510
|
+
"pr",
|
|
10511
|
+
"create",
|
|
10512
|
+
...repoArgs(slug),
|
|
10513
|
+
"--title",
|
|
10514
|
+
opts.title,
|
|
10515
|
+
"-F",
|
|
10516
|
+
opts.bodyFile,
|
|
10517
|
+
"--base",
|
|
10518
|
+
opts.base,
|
|
10519
|
+
"--head",
|
|
10520
|
+
branch,
|
|
10521
|
+
"--push"
|
|
10522
|
+
];
|
|
10523
|
+
if (opts.draft) args.push("--draft");
|
|
10524
|
+
const created = await originCli(args, repoPath, { reject: false, timeoutMs: 6e4 });
|
|
10525
|
+
if (created.exitCode !== 0) {
|
|
10526
|
+
throw new Error(created.stderr.trim() || created.stdout.trim() || "origin pr create failed");
|
|
10527
|
+
}
|
|
10528
|
+
const printed = created.stdout.trim().split("\n").find((line) => line.startsWith("http"));
|
|
10529
|
+
if (printed) return printed;
|
|
10530
|
+
const viewed = await viewCursorPr(repoPath, slug, branch, "url");
|
|
10531
|
+
const url = typeof viewed?.url === "string" ? viewed.url.trim() : "";
|
|
10532
|
+
return url || created.stdout.trim();
|
|
10533
|
+
}
|
|
10534
|
+
async function readyCursorPr(repoPath, slug, selector) {
|
|
10535
|
+
const ready = await originCli(["pr", "ready", selector, ...repoArgs(slug)], repoPath, {
|
|
10536
|
+
reject: false,
|
|
10537
|
+
timeoutMs: 2e4
|
|
10538
|
+
});
|
|
10539
|
+
if (ready.exitCode !== 0) {
|
|
10540
|
+
throw new Error(ready.stderr.trim() || ready.stdout.trim() || "Could not mark the Cursor pull request ready");
|
|
10541
|
+
}
|
|
10542
|
+
}
|
|
10543
|
+
async function mergeCursorPr(repoPath, slug, selector, method) {
|
|
10544
|
+
const args = ["pr", "merge", selector, ...repoArgs(slug)];
|
|
10545
|
+
if (method === "merge") args.push("--merge");
|
|
10546
|
+
else if (method === "squash") args.push("--squash");
|
|
10547
|
+
const merged = await originCli(args, repoPath, {
|
|
10548
|
+
reject: false,
|
|
10549
|
+
timeoutMs: 6e4
|
|
10550
|
+
});
|
|
10551
|
+
if (merged.exitCode !== 0) {
|
|
10552
|
+
throw new Error(merged.stderr.trim() || merged.stdout.trim() || "origin pr merge failed");
|
|
10553
|
+
}
|
|
10554
|
+
}
|
|
10555
|
+
async function fetchCursorPrHead(repoPath, slug, number, localBranch) {
|
|
10556
|
+
const view = await viewCursorPr(repoPath, slug, String(number), "headRefName");
|
|
10557
|
+
const head = typeof view?.headRefName === "string" ? view.headRefName.trim() : "";
|
|
10558
|
+
if (!head) {
|
|
10559
|
+
throw new Error(`Could not resolve the head branch for Cursor pull request #${number}`);
|
|
10560
|
+
}
|
|
10561
|
+
const result = await git(["fetch", "origin", `${head}:${localBranch}`], repoPath, { reject: false });
|
|
10562
|
+
if (result.exitCode !== 0) {
|
|
10563
|
+
throw new Error((result.stderr || result.stdout).trim() || `git fetch origin ${head} failed`);
|
|
10564
|
+
}
|
|
10565
|
+
}
|
|
10566
|
+
async function cursorPrChecks(repoPath, slug, selector) {
|
|
10567
|
+
const { stdout, exitCode, stderr } = await originCli(
|
|
10568
|
+
["pr", "checks", selector, ...repoArgs(slug), "--json", "name,status,conclusion,detailsUrl,startedAt,completedAt,summary,group,link"],
|
|
10569
|
+
repoPath,
|
|
10570
|
+
{ reject: false, timeoutMs: 2e4 }
|
|
10571
|
+
);
|
|
10572
|
+
const err = stderr.trim();
|
|
10573
|
+
let ci;
|
|
10574
|
+
if (!stdout.trim()) {
|
|
10575
|
+
if (/no pull request|not found|no change/i.test(err)) return null;
|
|
10576
|
+
if (exitCode !== 0 && err) throw new Error(err);
|
|
10577
|
+
ci = [];
|
|
10578
|
+
} else {
|
|
10579
|
+
ci = originChecksToRuns(stdout);
|
|
10580
|
+
}
|
|
10581
|
+
const view = await viewCursorPr(
|
|
10582
|
+
repoPath,
|
|
10583
|
+
slug,
|
|
10584
|
+
selector,
|
|
10585
|
+
"url,baseRefName,reviewDecision,mergeability"
|
|
10586
|
+
);
|
|
10587
|
+
if (!view) return ci;
|
|
10588
|
+
return cursorChecksWithGate(ci, cursorViewToPrMeta(view));
|
|
10589
|
+
}
|
|
10590
|
+
function cursorChecksWithGate(ci, meta) {
|
|
10591
|
+
const gate = {
|
|
10592
|
+
mergeable: meta.mergeable,
|
|
10593
|
+
mergeStateStatus: meta.mergeStateStatus,
|
|
10594
|
+
reviewDecision: meta.reviewDecision,
|
|
10595
|
+
baseRefName: meta.baseRefName,
|
|
10596
|
+
url: meta.url,
|
|
10597
|
+
isInMergeQueue: meta.isInMergeQueue
|
|
10598
|
+
};
|
|
10599
|
+
const review = (gate.reviewDecision ?? "").toUpperCase();
|
|
10600
|
+
const hasReviewRow = review === "CHANGES_REQUESTED" || review === "REVIEW_REQUIRED";
|
|
10601
|
+
const gateRows = buildMergeGateChecks(gate, {
|
|
10602
|
+
suppressGenericBlocked: ci.some((check) => check.bucket === "fail") || hasReviewRow
|
|
10603
|
+
});
|
|
10604
|
+
return [...gateRows, ...ci];
|
|
10605
|
+
}
|
|
10606
|
+
var PLAIN_LIST_FIELDS, SEARCH_LIST_FIELDS, VIEW_FIELDS, CURSOR_PR_VIEW_FIELDS;
|
|
10607
|
+
var init_cursor_pr = __esm({
|
|
10608
|
+
"src/git/cursor-pr.ts"() {
|
|
10609
|
+
"use strict";
|
|
10610
|
+
init_run();
|
|
10611
|
+
init_remote_forge();
|
|
10612
|
+
init_list_prs();
|
|
10613
|
+
init_pr_gates();
|
|
10614
|
+
PLAIN_LIST_FIELDS = "number,title,headRefName,url,author,state,isDraft,reviewDecision";
|
|
10615
|
+
SEARCH_LIST_FIELDS = `${PLAIN_LIST_FIELDS},labels,reviewRequests`;
|
|
10616
|
+
VIEW_FIELDS = "number,title,body,url,state,isDraft,reviewDecision,author,createdAt,baseRefName,headRefName,additions,deletions,changedFiles,commits,comments,reviews,labels,mergeability";
|
|
10617
|
+
CURSOR_PR_VIEW_FIELDS = VIEW_FIELDS;
|
|
10618
|
+
}
|
|
10619
|
+
});
|
|
10620
|
+
|
|
10212
10621
|
// src/util/enqueue-by-key.ts
|
|
10213
10622
|
function enqueueByKey(key, fn) {
|
|
10214
10623
|
const prev = tails.get(key) ?? Promise.resolve();
|
|
@@ -10540,11 +10949,11 @@ __export(worktree_exports, {
|
|
|
10540
10949
|
connectedPrSelectors: () => connectedPrSelectors,
|
|
10541
10950
|
countUnpushedVsOrigin: () => countUnpushedVsOrigin,
|
|
10542
10951
|
createExistingBranchWorktree: () => createExistingBranchWorktree,
|
|
10543
|
-
createOrUpdatePr: () => createOrUpdatePr,
|
|
10544
10952
|
createThreadWorktree: () => createThreadWorktree,
|
|
10545
10953
|
currentBranch: () => currentBranch,
|
|
10546
10954
|
detectLocalMergeConflicts: () => detectLocalMergeConflicts,
|
|
10547
10955
|
ensureGhPreferOrigin: () => ensureGhPreferOrigin,
|
|
10956
|
+
entireUsesTrails: () => entireUsesTrails,
|
|
10548
10957
|
fastForwardMainCheckoutIfSafe: () => fastForwardMainCheckoutIfSafe,
|
|
10549
10958
|
fetchOriginForWorktree: () => fetchOriginForWorktree,
|
|
10550
10959
|
fetchPrHead: () => fetchPrHead,
|
|
@@ -10554,7 +10963,6 @@ __export(worktree_exports, {
|
|
|
10554
10963
|
getPrForHeadBranch: () => getPrForHeadBranch,
|
|
10555
10964
|
getPrMeta: () => getPrMeta,
|
|
10556
10965
|
ghHeadRef: () => ghHeadRef,
|
|
10557
|
-
ghPrCreateAssigneeArgs: () => ghPrCreateAssigneeArgs,
|
|
10558
10966
|
ghRepoSelectArgs: () => ghRepoSelectArgs,
|
|
10559
10967
|
githubAgentGitEnv: () => githubAgentGitEnv,
|
|
10560
10968
|
isDefaultishSourceRef: () => isDefaultishSourceRef,
|
|
@@ -10578,8 +10986,10 @@ __export(worktree_exports, {
|
|
|
10578
10986
|
resolveDefaultBranch: () => resolveDefaultBranch,
|
|
10579
10987
|
resolveDiffBaseRef: () => resolveDiffBaseRef,
|
|
10580
10988
|
resolveGithubRepoSlug: () => resolveGithubRepoSlug,
|
|
10989
|
+
resolveOriginRemote: () => resolveOriginRemote,
|
|
10581
10990
|
resolvePrSelector: () => resolvePrSelector,
|
|
10582
10991
|
resolvePrSelectors: () => resolvePrSelectors,
|
|
10992
|
+
resolveProjectRemoteTag: () => resolveProjectRemoteTag,
|
|
10583
10993
|
resolveRepoRoot: () => resolveRepoRoot,
|
|
10584
10994
|
resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
|
|
10585
10995
|
slugify: () => slugify,
|
|
@@ -10593,31 +11003,6 @@ __export(worktree_exports, {
|
|
|
10593
11003
|
worktreeNameFromPath: () => worktreeNameFromPath,
|
|
10594
11004
|
worktreeSlugForTicket: () => worktreeSlugForTicket
|
|
10595
11005
|
});
|
|
10596
|
-
async function lookupGithubGraphqlReset(cwd) {
|
|
10597
|
-
const result = await gh(["api", "rate_limit"], cwd, { reject: false });
|
|
10598
|
-
if (result.exitCode !== 0 || !result.stdout.trim()) return void 0;
|
|
10599
|
-
try {
|
|
10600
|
-
const data = JSON.parse(result.stdout);
|
|
10601
|
-
const reset = data.resources?.graphql?.reset;
|
|
10602
|
-
return typeof reset === "number" ? reset : void 0;
|
|
10603
|
-
} catch {
|
|
10604
|
-
return void 0;
|
|
10605
|
-
}
|
|
10606
|
-
}
|
|
10607
|
-
async function formatPrCreateFailure(raw, cwd, ctx) {
|
|
10608
|
-
if (!isGhRateLimitError(raw)) {
|
|
10609
|
-
return formatGhLandError(raw, {
|
|
10610
|
-
targetedRepo: ctx?.slug,
|
|
10611
|
-
headRef: ctx?.head
|
|
10612
|
-
});
|
|
10613
|
-
}
|
|
10614
|
-
const resetAt = await lookupGithubGraphqlReset(cwd);
|
|
10615
|
-
return formatGhLandError(raw, {
|
|
10616
|
-
resetAt,
|
|
10617
|
-
targetedRepo: ctx?.slug,
|
|
10618
|
-
headRef: ctx?.head
|
|
10619
|
-
});
|
|
10620
|
-
}
|
|
10621
11006
|
function slugify(input) {
|
|
10622
11007
|
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
10623
11008
|
}
|
|
@@ -10640,25 +11025,39 @@ function canonicalizeRepoPath(path2) {
|
|
|
10640
11025
|
}
|
|
10641
11026
|
}
|
|
10642
11027
|
function parseGithubSlugFromRemoteUrl(url) {
|
|
10643
|
-
const
|
|
10644
|
-
|
|
10645
|
-
const github = trimmed.match(/github\.com[:/]([^/]+)\/([^/]+)$/i);
|
|
10646
|
-
if (github?.[1] && github[2]) return `${github[1]}/${github[2]}`;
|
|
10647
|
-
const sshAlias = trimmed.match(/^git@[^:]+:([^/]+)\/([^/]+)$/i);
|
|
10648
|
-
if (sshAlias?.[1] && sshAlias[2]) return `${sshAlias[1]}/${sshAlias[2]}`;
|
|
10649
|
-
return null;
|
|
11028
|
+
const parsed = parseRemoteRepo(url);
|
|
11029
|
+
return parsed?.forge === "github" ? parsed.slug : null;
|
|
10650
11030
|
}
|
|
10651
|
-
async function
|
|
11031
|
+
async function remoteUrl(repoPath, remote) {
|
|
10652
11032
|
const result = await git(["remote", "get-url", remote], repoPath, {
|
|
10653
11033
|
reject: false,
|
|
10654
11034
|
timeoutMs: 5e3
|
|
10655
11035
|
});
|
|
10656
11036
|
if (result.exitCode !== 0 || !result.stdout.trim()) return null;
|
|
10657
|
-
return
|
|
11037
|
+
return result.stdout.trim();
|
|
11038
|
+
}
|
|
11039
|
+
async function slugFromGitRemote(repoPath, remote) {
|
|
11040
|
+
const url = await remoteUrl(repoPath, remote);
|
|
11041
|
+
if (!url) return null;
|
|
11042
|
+
return parseGithubSlugFromRemoteUrl(url);
|
|
11043
|
+
}
|
|
11044
|
+
async function resolveOriginRemote(repoPath) {
|
|
11045
|
+
const url = await remoteUrl(repoPath, "origin");
|
|
11046
|
+
if (!url) return null;
|
|
11047
|
+
return parseRemoteRepo(url);
|
|
11048
|
+
}
|
|
11049
|
+
async function resolveProjectRemoteTag(repoPath) {
|
|
11050
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
11051
|
+
if (origin) return formatRemoteTag(origin);
|
|
11052
|
+
const slug = await resolveGithubRepoSlug(repoPath);
|
|
11053
|
+
return slug ? `github:${slug}` : null;
|
|
10658
11054
|
}
|
|
10659
11055
|
async function resolveGithubRepoSlug(repoPath) {
|
|
10660
|
-
const
|
|
10661
|
-
if (
|
|
11056
|
+
const originUrl = await remoteUrl(repoPath, "origin");
|
|
11057
|
+
if (originUrl) {
|
|
11058
|
+
const parsed = parseRemoteRepo(originUrl);
|
|
11059
|
+
return parsed?.forge === "github" ? parsed.slug : null;
|
|
11060
|
+
}
|
|
10662
11061
|
const hasAlt = Boolean(await slugFromGitRemote(repoPath, "upstream")) || Boolean(await slugFromGitRemote(repoPath, "github"));
|
|
10663
11062
|
if (!hasAlt) {
|
|
10664
11063
|
const viaGh = await gh(
|
|
@@ -10704,6 +11103,8 @@ ${view.stderr}`;
|
|
|
10704
11103
|
});
|
|
10705
11104
|
}
|
|
10706
11105
|
async function originGhRepoEnv(cwd, opts) {
|
|
11106
|
+
const origin = await resolveOriginRemote(cwd);
|
|
11107
|
+
if (origin?.forge === "cursor") return { ORIGIN_REPO: origin.slug };
|
|
10707
11108
|
await ensureGhPreferOrigin(cwd);
|
|
10708
11109
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
10709
11110
|
const mode = opts?.mode ?? getGithubGitAuthMode();
|
|
@@ -10818,7 +11219,16 @@ async function listBranches(repoPath, opts) {
|
|
|
10818
11219
|
}
|
|
10819
11220
|
return sorted.filter((b) => keep.has(b.name));
|
|
10820
11221
|
}
|
|
11222
|
+
function entireUsesTrails() {
|
|
11223
|
+
return new Error(
|
|
11224
|
+
"This checkout is on Entire. Trails replace pull requests \u2014 use `entire trail` (Settings \u2192 Git \u2192 Entire), not `gh`."
|
|
11225
|
+
);
|
|
11226
|
+
}
|
|
10821
11227
|
async function listPrs(repoPath, opts) {
|
|
11228
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
11229
|
+
if (origin?.forge === "entire") return [];
|
|
11230
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
11231
|
+
if (cursorSlug) return listCursorPrs(repoPath, cursorSlug, opts);
|
|
10822
11232
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
10823
11233
|
const resolved = resolveListPrsOptions(opts);
|
|
10824
11234
|
const limit = resolved.limit ?? 200;
|
|
@@ -10855,6 +11265,18 @@ function prInfoFromGhView(view) {
|
|
|
10855
11265
|
};
|
|
10856
11266
|
}
|
|
10857
11267
|
async function getPr(repoPath, number) {
|
|
11268
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
11269
|
+
if (origin?.forge === "entire") return null;
|
|
11270
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
11271
|
+
if (cursorSlug) {
|
|
11272
|
+
const view = await viewCursorPr(
|
|
11273
|
+
repoPath,
|
|
11274
|
+
cursorSlug,
|
|
11275
|
+
String(number),
|
|
11276
|
+
"number,title,headRefName,url,author,isDraft,state"
|
|
11277
|
+
);
|
|
11278
|
+
return view ? prInfoFromGhView(view) : null;
|
|
11279
|
+
}
|
|
10858
11280
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
10859
11281
|
const args = [
|
|
10860
11282
|
"pr",
|
|
@@ -10916,6 +11338,13 @@ function connectedPrSelectors(thread, currentHeadPrUrl) {
|
|
|
10916
11338
|
async function getPrForHeadBranch(repoPath, branch) {
|
|
10917
11339
|
const head = normalizeGitBranchName(branch);
|
|
10918
11340
|
if (!head || isDefaultishSourceRef(head)) return null;
|
|
11341
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
11342
|
+
if (origin?.forge === "entire") return null;
|
|
11343
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
11344
|
+
if (cursorSlug) {
|
|
11345
|
+
const rows = await listCursorPrs(repoPath, cursorSlug, { state: "open", limit: 5 }, head);
|
|
11346
|
+
return rows[0] ?? null;
|
|
11347
|
+
}
|
|
10919
11348
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
10920
11349
|
const listHead = slug ? ghHeadRef(slug, head) : head;
|
|
10921
11350
|
const listArgs = [
|
|
@@ -11080,6 +11509,10 @@ async function probeLocalMergeGate(cwd, gate) {
|
|
|
11080
11509
|
return { gate, files: [] };
|
|
11081
11510
|
}
|
|
11082
11511
|
async function getPrChecks(cwd, selector) {
|
|
11512
|
+
const origin = await resolveOriginRemote(cwd);
|
|
11513
|
+
if (origin?.forge === "entire") return null;
|
|
11514
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
11515
|
+
if (cursorSlug) return cursorPrChecks(cwd, cursorSlug, selector);
|
|
11083
11516
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
11084
11517
|
const args = [
|
|
11085
11518
|
"pr",
|
|
@@ -11135,6 +11568,18 @@ async function getPrChecks(cwd, selector) {
|
|
|
11135
11568
|
return [...gateRows, ...ciChecks];
|
|
11136
11569
|
}
|
|
11137
11570
|
async function getPrMeta(cwd, selector) {
|
|
11571
|
+
const origin = await resolveOriginRemote(cwd);
|
|
11572
|
+
if (origin?.forge === "entire") return null;
|
|
11573
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
11574
|
+
if (cursorSlug) {
|
|
11575
|
+
const view = await viewCursorPr(
|
|
11576
|
+
cwd,
|
|
11577
|
+
cursorSlug,
|
|
11578
|
+
selector,
|
|
11579
|
+
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,author,labels,mergeability"
|
|
11580
|
+
);
|
|
11581
|
+
return view ? cursorViewToPrMeta(view) : null;
|
|
11582
|
+
}
|
|
11138
11583
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
11139
11584
|
const viewArgs = [
|
|
11140
11585
|
"pr",
|
|
@@ -11263,6 +11708,13 @@ function parsePrDetailsView(view) {
|
|
|
11263
11708
|
};
|
|
11264
11709
|
}
|
|
11265
11710
|
async function getPrDetails(cwd, selector) {
|
|
11711
|
+
const origin = await resolveOriginRemote(cwd);
|
|
11712
|
+
if (origin?.forge === "entire") return null;
|
|
11713
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
11714
|
+
if (cursorSlug) {
|
|
11715
|
+
const view2 = await viewCursorPr(cwd, cursorSlug, selector, CURSOR_PR_VIEW_FIELDS);
|
|
11716
|
+
return view2 ? parsePrDetailsView(view2) : null;
|
|
11717
|
+
}
|
|
11266
11718
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
11267
11719
|
const viewArgs = ["pr", "view", selector, "--json", PR_DETAILS_JSON_FIELDS];
|
|
11268
11720
|
if (slug) viewArgs.push("--repo", slug);
|
|
@@ -11282,6 +11734,13 @@ async function getPrDetails(cwd, selector) {
|
|
|
11282
11734
|
return parsePrDetailsView(view);
|
|
11283
11735
|
}
|
|
11284
11736
|
async function fetchPrHead(repoPath, number, localBranch) {
|
|
11737
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
11738
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
11739
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
11740
|
+
if (cursorSlug) {
|
|
11741
|
+
await fetchCursorPrHead(repoPath, cursorSlug, number, localBranch);
|
|
11742
|
+
return;
|
|
11743
|
+
}
|
|
11285
11744
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
11286
11745
|
const refspec = `+pull/${number}/head:${localBranch}`;
|
|
11287
11746
|
const errors = [];
|
|
@@ -11312,10 +11771,10 @@ async function fetchPrHead(repoPath, number, localBranch) {
|
|
|
11312
11771
|
if (!fetched) fetched = await tryFetch(httpsRemote, { ghAuth: true });
|
|
11313
11772
|
}
|
|
11314
11773
|
const localOk = async () => {
|
|
11315
|
-
const
|
|
11774
|
+
const verify2 = await git(["rev-parse", "--verify", localBranch], repoPath, {
|
|
11316
11775
|
reject: false
|
|
11317
11776
|
});
|
|
11318
|
-
return
|
|
11777
|
+
return verify2.exitCode === 0;
|
|
11319
11778
|
};
|
|
11320
11779
|
if (!await localOk()) {
|
|
11321
11780
|
const viewArgs = [
|
|
@@ -11424,10 +11883,10 @@ async function originRemoteUrl(cwd) {
|
|
|
11424
11883
|
const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
|
|
11425
11884
|
return result.exitCode === 0 ? result.stdout.trim() : "";
|
|
11426
11885
|
}
|
|
11427
|
-
function githubHttpsRetryEnv(
|
|
11886
|
+
function githubHttpsRetryEnv(remoteUrl2) {
|
|
11428
11887
|
return {
|
|
11429
11888
|
GIT_TERMINAL_PROMPT: "0",
|
|
11430
|
-
...githubAgentGitEnv(void 0, { remoteUrl })
|
|
11889
|
+
...githubAgentGitEnv(void 0, { remoteUrl: remoteUrl2 })
|
|
11431
11890
|
};
|
|
11432
11891
|
}
|
|
11433
11892
|
async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
@@ -11441,11 +11900,11 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
|
11441
11900
|
}
|
|
11442
11901
|
const token = await resolveGithubAgentToken(mode, repoPath);
|
|
11443
11902
|
if (!token) return false;
|
|
11444
|
-
const
|
|
11903
|
+
const remoteUrl2 = await originRemoteUrl(repoPath);
|
|
11445
11904
|
const tryHttps = async (header) => git(args, repoPath, {
|
|
11446
11905
|
reject: false,
|
|
11447
11906
|
timeoutMs,
|
|
11448
|
-
env: githubHttpsRetryEnv(
|
|
11907
|
+
env: githubHttpsRetryEnv(remoteUrl2),
|
|
11449
11908
|
config: {
|
|
11450
11909
|
"http.extraHeader": header
|
|
11451
11910
|
}
|
|
@@ -11794,10 +12253,10 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
11794
12253
|
sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
|
|
11795
12254
|
);
|
|
11796
12255
|
}
|
|
11797
|
-
const
|
|
12256
|
+
const remoteUrl2 = await originRemoteUrl(worktreePath);
|
|
11798
12257
|
const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
|
|
11799
12258
|
reject: false,
|
|
11800
|
-
env: githubHttpsRetryEnv(
|
|
12259
|
+
env: githubHttpsRetryEnv(remoteUrl2),
|
|
11801
12260
|
config: {
|
|
11802
12261
|
"http.extraHeader": header
|
|
11803
12262
|
}
|
|
@@ -11810,6 +12269,40 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
11810
12269
|
const httpsErr = (basicPush.stderr || bearer.stderr || bearer.stdout).trim();
|
|
11811
12270
|
throw new Error(httpsErr || sshErr || `git push origin ${branchName} failed`);
|
|
11812
12271
|
}
|
|
12272
|
+
async function markCursorPrReady(cwd, slug, selector) {
|
|
12273
|
+
const view = await viewCursorPr(cwd, slug, selector, "url,state,isDraft");
|
|
12274
|
+
if (!view) throw new Error("Could not load the Cursor pull request");
|
|
12275
|
+
const url = String(view.url ?? "");
|
|
12276
|
+
const state = String(view.state ?? "").toUpperCase();
|
|
12277
|
+
const isDraft = Boolean(view.isDraft);
|
|
12278
|
+
if (state === "MERGED" || state === "CLOSED") {
|
|
12279
|
+
return { url, state, isDraft: false };
|
|
12280
|
+
}
|
|
12281
|
+
if (isDraft) {
|
|
12282
|
+
if (await isDirty(cwd)) {
|
|
12283
|
+
throw new Error(
|
|
12284
|
+
"Commit and push local work before marking the pull request ready for review."
|
|
12285
|
+
);
|
|
12286
|
+
}
|
|
12287
|
+
const unpushed = await countUnpushedVsOrigin(cwd);
|
|
12288
|
+
if (unpushed > 0) {
|
|
12289
|
+
throw new Error(
|
|
12290
|
+
"Push this branch to origin before marking the pull request ready for review."
|
|
12291
|
+
);
|
|
12292
|
+
}
|
|
12293
|
+
await readyCursorPr(cwd, slug, selector);
|
|
12294
|
+
}
|
|
12295
|
+
return { url, state: state || "OPEN", isDraft: false };
|
|
12296
|
+
}
|
|
12297
|
+
async function mergeCursorPullRequest(cwd, slug, selector, method) {
|
|
12298
|
+
const view = await viewCursorPr(cwd, slug, selector, "url,state,isDraft");
|
|
12299
|
+
if (!view) throw new Error("Could not load the Cursor pull request");
|
|
12300
|
+
const url = String(view.url ?? "");
|
|
12301
|
+
if (String(view.state ?? "").toUpperCase() === "MERGED") return { url, state: "MERGED" };
|
|
12302
|
+
if (view.isDraft) await readyCursorPr(cwd, slug, selector);
|
|
12303
|
+
await mergeCursorPr(cwd, slug, selector, method);
|
|
12304
|
+
return { url, state: "MERGED" };
|
|
12305
|
+
}
|
|
11813
12306
|
async function runPrReady(cwd, selector, slug) {
|
|
11814
12307
|
const readyArgs = ["pr", "ready", selector];
|
|
11815
12308
|
if (slug) readyArgs.push("--repo", slug);
|
|
@@ -11821,6 +12314,10 @@ async function runPrReady(cwd, selector, slug) {
|
|
|
11821
12314
|
}
|
|
11822
12315
|
}
|
|
11823
12316
|
async function markPrReady(cwd, selector) {
|
|
12317
|
+
const origin = await resolveOriginRemote(cwd);
|
|
12318
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
12319
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
12320
|
+
if (cursorSlug) return markCursorPrReady(cwd, cursorSlug, selector);
|
|
11824
12321
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
11825
12322
|
const viewArgs = ["pr", "view", selector, "--json", "url,state,isDraft"];
|
|
11826
12323
|
if (slug) viewArgs.push("--repo", slug);
|
|
@@ -11859,6 +12356,10 @@ async function markPrReady(cwd, selector) {
|
|
|
11859
12356
|
return { url, state: state || "OPEN", isDraft: false };
|
|
11860
12357
|
}
|
|
11861
12358
|
async function mergePr(cwd, selector, opts) {
|
|
12359
|
+
const origin = await resolveOriginRemote(cwd);
|
|
12360
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
12361
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
12362
|
+
if (cursorSlug) return mergeCursorPullRequest(cwd, cursorSlug, selector, opts?.method ?? "squash");
|
|
11862
12363
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
11863
12364
|
const viewArgs = ["pr", "view", selector, "--json", "url,state,isDraft,number"];
|
|
11864
12365
|
if (slug) viewArgs.push("--repo", slug);
|
|
@@ -11917,128 +12418,16 @@ async function mergePr(cwd, selector, opts) {
|
|
|
11917
12418
|
}
|
|
11918
12419
|
return { url, state: "MERGED" };
|
|
11919
12420
|
}
|
|
11920
|
-
function ghPrCreateAssigneeArgs(assignee) {
|
|
11921
|
-
const raw = assignee?.trim();
|
|
11922
|
-
if (raw && /^(none|unassigned)$/i.test(raw)) return [];
|
|
11923
|
-
return ["--assignee", raw || "@me"];
|
|
11924
|
-
}
|
|
11925
|
-
async function createOrUpdatePr(worktreePath, opts) {
|
|
11926
|
-
await ensureGhPreferOrigin(worktreePath);
|
|
11927
|
-
const slug = await resolveGithubRepoSlug(worktreePath);
|
|
11928
|
-
if (!slug) {
|
|
11929
|
-
throw new Error(
|
|
11930
|
-
"Could not resolve the origin GitHub repo (owner/name) for this worktree. Check that `git remote get-url origin` points at github.com."
|
|
11931
|
-
);
|
|
11932
|
-
}
|
|
11933
|
-
const repoArgs = ghRepoSelectArgs(slug);
|
|
11934
|
-
const headRef = ghHeadRef(slug, opts.head);
|
|
11935
|
-
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
11936
|
-
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
11937
|
-
const bodyFile = (0, import_node_path27.join)(
|
|
11938
|
-
(0, import_node_os8.tmpdir)(),
|
|
11939
|
-
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto10.randomBytes)(6).toString("hex")}.md`
|
|
11940
|
-
);
|
|
11941
|
-
(0, import_node_fs23.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
11942
|
-
`, "utf8");
|
|
11943
|
-
const bodyArgs = ["--body-file", bodyFile];
|
|
11944
|
-
try {
|
|
11945
|
-
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
11946
|
-
...opts,
|
|
11947
|
-
slug,
|
|
11948
|
-
repoArgs,
|
|
11949
|
-
headRef,
|
|
11950
|
-
branchOnly,
|
|
11951
|
-
bodyArgs
|
|
11952
|
-
});
|
|
11953
|
-
} finally {
|
|
11954
|
-
try {
|
|
11955
|
-
(0, import_node_fs23.unlinkSync)(bodyFile);
|
|
11956
|
-
} catch {
|
|
11957
|
-
}
|
|
11958
|
-
}
|
|
11959
|
-
}
|
|
11960
|
-
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
11961
|
-
const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
|
|
11962
|
-
const existing = await gh(
|
|
11963
|
-
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
11964
|
-
worktreePath,
|
|
11965
|
-
{ reject: false }
|
|
11966
|
-
);
|
|
11967
|
-
if (existing.exitCode === 0 && existing.stdout.trim() && !opts.web) {
|
|
11968
|
-
const url2 = existing.stdout.trim();
|
|
11969
|
-
await gh(
|
|
11970
|
-
[
|
|
11971
|
-
...repoArgs,
|
|
11972
|
-
"pr",
|
|
11973
|
-
"edit",
|
|
11974
|
-
branchOnly,
|
|
11975
|
-
"--title",
|
|
11976
|
-
opts.title,
|
|
11977
|
-
...bodyArgs
|
|
11978
|
-
],
|
|
11979
|
-
worktreePath,
|
|
11980
|
-
{ reject: false }
|
|
11981
|
-
);
|
|
11982
|
-
return url2;
|
|
11983
|
-
}
|
|
11984
|
-
if (opts.web) {
|
|
11985
|
-
const args2 = [
|
|
11986
|
-
...repoArgs,
|
|
11987
|
-
"pr",
|
|
11988
|
-
"create",
|
|
11989
|
-
"--web",
|
|
11990
|
-
"--title",
|
|
11991
|
-
opts.title,
|
|
11992
|
-
...bodyArgs,
|
|
11993
|
-
"--base",
|
|
11994
|
-
opts.base,
|
|
11995
|
-
"--head",
|
|
11996
|
-
headRef
|
|
11997
|
-
];
|
|
11998
|
-
if (opts.draft) args2.push("--draft");
|
|
11999
|
-
args2.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
12000
|
-
await gh(args2, worktreePath, { reject: false });
|
|
12001
|
-
const again = await gh(
|
|
12002
|
-
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
12003
|
-
worktreePath,
|
|
12004
|
-
{ reject: false }
|
|
12005
|
-
);
|
|
12006
|
-
return again.stdout.trim() || "";
|
|
12007
|
-
}
|
|
12008
|
-
const args = [
|
|
12009
|
-
...repoArgs,
|
|
12010
|
-
"pr",
|
|
12011
|
-
"create",
|
|
12012
|
-
"--title",
|
|
12013
|
-
opts.title,
|
|
12014
|
-
...bodyArgs,
|
|
12015
|
-
"--base",
|
|
12016
|
-
opts.base,
|
|
12017
|
-
"--head",
|
|
12018
|
-
headRef
|
|
12019
|
-
];
|
|
12020
|
-
if (opts.draft) args.push("--draft");
|
|
12021
|
-
args.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
12022
|
-
const created = await gh(args, worktreePath, { reject: false });
|
|
12023
|
-
if (created.exitCode !== 0) {
|
|
12024
|
-
const raw = created.stderr.trim() || created.stdout.trim() || "gh pr create failed";
|
|
12025
|
-
throw new Error(await formatPrCreateFailure(raw, worktreePath, { slug, head: headRef }));
|
|
12026
|
-
}
|
|
12027
|
-
const url = created.stdout.trim().split("\n").find((l) => l.startsWith("http")) ?? created.stdout.trim();
|
|
12028
|
-
return url;
|
|
12029
|
-
}
|
|
12030
12421
|
function suggestSlug(source) {
|
|
12031
12422
|
const base = slugify(source || "thread");
|
|
12032
12423
|
const stamp = Date.now().toString(36).slice(-4);
|
|
12033
12424
|
return `${base || "thread"}-${stamp}`;
|
|
12034
12425
|
}
|
|
12035
|
-
var
|
|
12426
|
+
var import_node_fs23, import_node_path27, PR_INFO_JSON_FIELDS, PR_DETAILS_JSON_FIELDS;
|
|
12036
12427
|
var init_worktree = __esm({
|
|
12037
12428
|
"src/git/worktree.ts"() {
|
|
12038
12429
|
"use strict";
|
|
12039
|
-
import_node_crypto10 = require("crypto");
|
|
12040
12430
|
import_node_fs23 = require("fs");
|
|
12041
|
-
import_node_os8 = require("os");
|
|
12042
12431
|
import_node_path27 = require("path");
|
|
12043
12432
|
init_paths();
|
|
12044
12433
|
init_worktree_labels();
|
|
@@ -12046,6 +12435,8 @@ var init_worktree = __esm({
|
|
|
12046
12435
|
init_worktree_exclude();
|
|
12047
12436
|
init_git_auth_mode();
|
|
12048
12437
|
init_run();
|
|
12438
|
+
init_remote_forge();
|
|
12439
|
+
init_cursor_pr();
|
|
12049
12440
|
init_list_prs();
|
|
12050
12441
|
init_repo_git_lock();
|
|
12051
12442
|
init_app_settings();
|
|
@@ -12199,7 +12590,7 @@ function pathIsInside(parent, child) {
|
|
|
12199
12590
|
}
|
|
12200
12591
|
function defaultWorktreesRoot(repoPath) {
|
|
12201
12592
|
const slug = (0, import_node_path28.basename)(repoPath.replace(/\/+$/, "")) || "repo";
|
|
12202
|
-
return (0, import_node_path28.join)((0,
|
|
12593
|
+
return (0, import_node_path28.join)((0, import_node_os8.homedir)(), "sideboard", "workspaces", slug);
|
|
12203
12594
|
}
|
|
12204
12595
|
function removedWorktreeCoversRepo(saved, repoPath) {
|
|
12205
12596
|
if (!saved || !repoPath) return false;
|
|
@@ -12382,12 +12773,12 @@ async function archiveRemovedWorkspaceChats(threads, archive) {
|
|
|
12382
12773
|
}
|
|
12383
12774
|
if (failures.length > 0) throw new Error(failures.join("\n"));
|
|
12384
12775
|
}
|
|
12385
|
-
var import_node_fs24,
|
|
12776
|
+
var import_node_fs24, import_node_os8, import_node_path28;
|
|
12386
12777
|
var init_workspaces = __esm({
|
|
12387
12778
|
"src/store/workspaces.ts"() {
|
|
12388
12779
|
"use strict";
|
|
12389
12780
|
import_node_fs24 = require("fs");
|
|
12390
|
-
|
|
12781
|
+
import_node_os8 = require("os");
|
|
12391
12782
|
import_node_path28 = require("path");
|
|
12392
12783
|
init_settings();
|
|
12393
12784
|
init_paths();
|
|
@@ -12411,7 +12802,7 @@ __export(coordinator_prompt_exports, {
|
|
|
12411
12802
|
function formatWorkspaceInventory(workspaces) {
|
|
12412
12803
|
if (workspaces.length === 0) return "(no registered workspaces)";
|
|
12413
12804
|
return workspaces.map((w) => {
|
|
12414
|
-
const slug = w.githubSlug?.trim() ? ` github:${w.githubSlug.trim()}` : "";
|
|
12805
|
+
const slug = w.originRemote ? ` ${formatRemoteTag(w.originRemote)}` : w.githubSlug?.trim() ? ` github:${w.githubSlug.trim()}` : "";
|
|
12415
12806
|
const profile = formatWorkspaceProfileSuffix(safeViewerProfile(w.path));
|
|
12416
12807
|
return `- ${w.name}: ${w.path}${slug}${profile}`;
|
|
12417
12808
|
}).join("\n");
|
|
@@ -12419,8 +12810,9 @@ function formatWorkspaceInventory(workspaces) {
|
|
|
12419
12810
|
async function enrichWorkspacesWithGithub(workspaces) {
|
|
12420
12811
|
return Promise.all(
|
|
12421
12812
|
workspaces.map(async (w) => {
|
|
12422
|
-
const
|
|
12423
|
-
|
|
12813
|
+
const originRemote = await resolveOriginRemote(w.path).catch(() => null);
|
|
12814
|
+
const githubSlug = originRemote ? originRemote.forge === "github" ? originRemote.slug : null : await resolveGithubRepoSlug(w.path).catch(() => null);
|
|
12815
|
+
return { ...w, githubSlug, originRemote };
|
|
12424
12816
|
})
|
|
12425
12817
|
);
|
|
12426
12818
|
}
|
|
@@ -12431,8 +12823,8 @@ function coordinatorGreenfieldPlaybook(reposDir) {
|
|
|
12431
12823
|
"- Examples:",
|
|
12432
12824
|
` - Clone: \`git clone <url> ${reposDir}/<name>\``,
|
|
12433
12825
|
` - New GitHub repo: \`gh repo create <owner>/<name> --private --clone -- ${reposDir}/<name>\` (or mkdir + git init + gh repo create + remote add + push)`,
|
|
12434
|
-
"- Then: add_project with that absolute path \u2192 create_workspace (repoPath + parentChatId) \u2192 send_to_chat (build) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft (
|
|
12435
|
-
"- Always target the child worktree's **origin** (`github:`
|
|
12826
|
+
"- Then: add_project with that absolute path \u2192 create_workspace (repoPath + parentChatId) \u2192 send_to_chat (build) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft (GitHub: `gh pr create --draft --assignee @me -R <slug>`; Cursor: `origin pr create --draft --push -R <slug>`; Entire: `entire trail create --title`).",
|
|
12827
|
+
"- Always target the child worktree's **origin** (`github:`, `cursor:`, or `entire:` from list_projects / `git remote get-url origin` in that worktree). Never open PRs against `upstream`.",
|
|
12436
12828
|
"- Do coding work in the child worktree thread, not by editing files in this home cwd."
|
|
12437
12829
|
].join("\n");
|
|
12438
12830
|
}
|
|
@@ -12593,6 +12985,7 @@ var init_coordinator_prompt = __esm({
|
|
|
12593
12985
|
"use strict";
|
|
12594
12986
|
import_node_fs25 = require("fs");
|
|
12595
12987
|
import_node_path29 = require("path");
|
|
12988
|
+
init_remote_forge();
|
|
12596
12989
|
init_worktree();
|
|
12597
12990
|
init_app_settings();
|
|
12598
12991
|
init_paths();
|
|
@@ -12601,9 +12994,9 @@ var init_coordinator_prompt = __esm({
|
|
|
12601
12994
|
"Role: you oversee Sideboard workspaces across registered repos. A workspace is one isolated checkout and can have many agent chats on those same files. You do not live inside one of those worktrees. Do not treat a workspace as one agent.",
|
|
12602
12995
|
"Sideboard MCP (fleet control \u2014 prefer these for status and orchestration):",
|
|
12603
12996
|
"Discover:",
|
|
12604
|
-
"- list_projects \u2014 registered repos (path + github
|
|
12997
|
+
"- list_projects \u2014 registered repos (path + that repo's origin host:owner/repo, such as github:, cursor:, or entire:, and project context when set). Projects do not share one git host. Use account / project context to pick the right repo for tickets or reviews.",
|
|
12605
12998
|
"- list_board \u2014 Home Kanban of workspaces (New / Draft / Review / Approved / Merged; one card per checkout). Sibling chats on a card are separate agents, not one agent. Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 approved \u2192 merged. Archive removes the card to Settings \u2192 History (list_archive to browse, restore_workspace to bring it back). Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind, column, limit.",
|
|
12606
|
-
|
|
12999
|
+
'- list_branches / list_prs / list_issues \u2014 pass repoPath from list_projects. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_workspace sourceType=pr. That is open non-draft PRs labeled with this project\'s ready-for-review GitHub label (Settings \u2192 Projects; default eng-review) with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored. Use Settings \u2192 Agents / Projects context (roles, teams, labels \u2014 freeform text; project adds to account) to prefer the right queues. queue=mine is review-requested:@me; queue=approved|changes uses those labels. Also: state, label, reviewer=me|unassigned|login, query, limit default 40 max 250; raise limit or tighten when truncated. list_issues (query, assignee=me|unassigned|all|user, limit default 40 max 250) lists Linear, AbleTime, or GitHub tickets. Cursor Origin has no issues; a Cursor repo uses Linear or AbleTime (unavailableReason otherwise) \u2014 do not use it for that review-inbox ask. Entire tickets are Trails (`entire trail`), not GitHub Issues. When they ask for tickets to work on, follow their context (assignee=me or unassigned as it says).',
|
|
12607
13000
|
"- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo) context. Tickets \u2192 Sideboard list_issues / linear_* (Account Linear). Reviews \u2192 list_prs(queue=review). Do not call Claude Linear MCP or any other vendor Linear MCP \u2014 those HTTP connectors hang or flap on the first turn. If a vendor MCP is down or reconnecting, ignore it and keep going with Sideboard tools. A failed Claude connector is not a Sideboard outage \u2014 do not mention it when the Account connection works. Show the options \u2014 do not create_workspace or start unless they also asked to start (e.g. \u201Cfind me work and start it\u201D). Do not start this unprompted. To change that context, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context with confirmed=true. Never write it without confirmation.",
|
|
12608
13001
|
"- Ticket updates: list_issues / linear_search_issues / github_search_issues with updatedSince (yesterday, 2d, or ISO). One call returns new assignments, ticket edits, and new comments \u2014 do not get_issue every ticket just to check for comments. kind=created vs updated distinguishes new tickets from existing ones.",
|
|
12609
13002
|
"- linear_* (when Linear is connected) \u2014 list_teams for team key/states; linear_list_projects for project names; get/search include the project a ticket is on; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket when they were asked to do the work. When reviewing a PR or ticket, do not comment or update until the user types a next step \u2014 they should work through the feedback in chat first. Do not tell the child to ask_user after the review. Scope errors: reconnect Linear in Account settings. Prefer these over any Linear MCP the CLI may still list. Worktree agents use the Claude Linear connector only when Account Linear is not set or the Sideboard call fails, and they do not mention that connector startup failure when Sideboard works.",
|
|
@@ -12640,11 +13033,11 @@ var init_coordinator_prompt = __esm({
|
|
|
12640
13033
|
"- list_run_scripts / run_dev_script / stop_dev_script / get_run_log \u2014 start/stop named run scripts and read the Run-tab terminal (tail). Pass name so desktop and mobile (or any pair) can run at once; each gets its own port. run_dev_script returns {url, port, preview} (SIDEBOARD_PORT). preview=url \u2192 tell the worktree agent to open that URL; preview=window \u2192 Electron: the native window is the app (url is renderer/HMR only). Never localhost:3000. list_run_scripts active[].url if already running.",
|
|
12641
13034
|
"Inspect / review / PRs:",
|
|
12642
13035
|
"- get_diff \u2014 compact diff summary",
|
|
12643
|
-
"- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` \u2014 do not poll for the human.",
|
|
13036
|
+
"- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` on GitHub, `origin pr watch` on Cursor, or `entire trail watch` on Entire \u2014 do not poll for the human.",
|
|
12644
13037
|
'- request_review \u2014 run a Review on a worktree thread. Reuses the only unused idle agent when the checkout has a single chat with no messages; otherwise opens a Review tab (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat so they can read it and type next steps \u2014 do not tell the child to comment or update the PR or ticket.',
|
|
12645
13038
|
"- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge \u2014 same prompts as the desktop git buttons (Resolve, Create PR, \u2026). Always steers the worktree agent; then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If the user gave a goal (Greptile 5/5, CI green), send_to_chat that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
|
|
12646
13039
|
'- Merge (`ask_git` action=merge / send_to_chat "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
|
|
12647
|
-
'- Or send_to_chat with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge PR." Prefer ask_git resolve-conflicts (it names the actual PR base \u2014 not always main) over paraphrasing.
|
|
13040
|
+
'- Or send_to_chat with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge PR." Prefer ask_git resolve-conflicts (it names the actual PR base \u2014 not always main) over paraphrasing. Draft PRs follow that workspace origin: GitHub (`github:`) uses `gh pr create --draft --assignee @me -R <slug>`; Cursor (`cursor:`) uses `origin pr create --draft --push -R <slug>`; Entire (`entire:`) uses `entire trail create --title` (Trails have no draft state). Never upstream. Never run git, gh, origin, or entire from this orchestration cwd, and never merge the PR yourself.',
|
|
12648
13041
|
"Process guides:",
|
|
12649
13042
|
"- Long child jobs (pack, test, deploy, anything that may run more than ~30s): workers always have `/long-running` (Sideboard product skill). Tell them to detach and wait; they may `stop_job` if it hangs or is doing the wrong thing; do not ask the human to poll.",
|
|
12650
13043
|
"- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
|
|
@@ -12987,7 +13380,7 @@ function resolveBrightsyConfigFile(path2) {
|
|
|
12987
13380
|
}
|
|
12988
13381
|
function brightsyConfigPath() {
|
|
12989
13382
|
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
12990
|
-
const raw = override || (0, import_node_path31.join)((0,
|
|
13383
|
+
const raw = override || (0, import_node_path31.join)((0, import_node_os9.homedir)(), ".brightsy", "config.json");
|
|
12991
13384
|
return resolveBrightsyConfigFile(raw);
|
|
12992
13385
|
}
|
|
12993
13386
|
function loadBrightsyConfig() {
|
|
@@ -13021,12 +13414,12 @@ function saveBrightsyConfig(cfg) {
|
|
|
13021
13414
|
mode: 384
|
|
13022
13415
|
});
|
|
13023
13416
|
}
|
|
13024
|
-
var import_node_fs27,
|
|
13417
|
+
var import_node_fs27, import_node_os9, import_node_path31;
|
|
13025
13418
|
var init_config = __esm({
|
|
13026
13419
|
"src/brightsy/config.ts"() {
|
|
13027
13420
|
"use strict";
|
|
13028
13421
|
import_node_fs27 = require("fs");
|
|
13029
|
-
|
|
13422
|
+
import_node_os9 = require("os");
|
|
13030
13423
|
import_node_path31 = require("path");
|
|
13031
13424
|
}
|
|
13032
13425
|
});
|
|
@@ -14337,7 +14730,7 @@ function claudePluginServerId(pluginName, serverName) {
|
|
|
14337
14730
|
return `plugin_${pluginName}_${serverName}`.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
14338
14731
|
}
|
|
14339
14732
|
function listEnabledClaudePluginMcpServers(opts) {
|
|
14340
|
-
const home = opts?.home ?? (0,
|
|
14733
|
+
const home = opts?.home ?? (0, import_node_os10.homedir)();
|
|
14341
14734
|
const pluginsRoot = claudePluginsRoot(home);
|
|
14342
14735
|
const enabled = enabledPluginIds(home, opts?.projectDirs ?? []);
|
|
14343
14736
|
const installed = readInstalledPlugins((0, import_node_path33.join)(pluginsRoot, "installed_plugins.json"));
|
|
@@ -14519,12 +14912,12 @@ function readJson(path2) {
|
|
|
14519
14912
|
return {};
|
|
14520
14913
|
}
|
|
14521
14914
|
}
|
|
14522
|
-
var import_node_fs30,
|
|
14915
|
+
var import_node_fs30, import_node_os10, import_node_path33;
|
|
14523
14916
|
var init_claude_plugins = __esm({
|
|
14524
14917
|
"src/agents/claude-plugins.ts"() {
|
|
14525
14918
|
"use strict";
|
|
14526
14919
|
import_node_fs30 = require("fs");
|
|
14527
|
-
|
|
14920
|
+
import_node_os10 = require("os");
|
|
14528
14921
|
import_node_path33 = require("path");
|
|
14529
14922
|
init_meta();
|
|
14530
14923
|
}
|
|
@@ -14970,7 +15363,7 @@ function versionDirNodeBins(root, toBin) {
|
|
|
14970
15363
|
return [];
|
|
14971
15364
|
}
|
|
14972
15365
|
}
|
|
14973
|
-
function defaultNodeBinCandidates(home = (0,
|
|
15366
|
+
function defaultNodeBinCandidates(home = (0, import_node_os11.homedir)()) {
|
|
14974
15367
|
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
14975
15368
|
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path36.join)(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
14976
15369
|
);
|
|
@@ -15085,12 +15478,12 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
15085
15478
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
15086
15479
|
};
|
|
15087
15480
|
}
|
|
15088
|
-
var import_node_fs33,
|
|
15481
|
+
var import_node_fs33, import_node_os11, import_node_path36, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
|
|
15089
15482
|
var init_node_launch = __esm({
|
|
15090
15483
|
"src/agents/node-launch.ts"() {
|
|
15091
15484
|
"use strict";
|
|
15092
15485
|
import_node_fs33 = require("fs");
|
|
15093
|
-
|
|
15486
|
+
import_node_os11 = require("os");
|
|
15094
15487
|
import_node_path36 = require("path");
|
|
15095
15488
|
init_nested_electron_env();
|
|
15096
15489
|
init_system_ca();
|
|
@@ -15387,7 +15780,7 @@ function mcpServersRecord(servers, extraServers) {
|
|
|
15387
15780
|
function writeMcpServersConfig(servers, extraServers) {
|
|
15388
15781
|
const mcpServers = mcpServersRecord(servers, extraServers);
|
|
15389
15782
|
if (Object.keys(mcpServers).length === 0) return null;
|
|
15390
|
-
const dir = (0, import_node_fs34.mkdtempSync)((0, import_node_path37.join)((0,
|
|
15783
|
+
const dir = (0, import_node_fs34.mkdtempSync)((0, import_node_path37.join)((0, import_node_os12.tmpdir)(), "sideboard-mcp-"));
|
|
15391
15784
|
const cfgPath = (0, import_node_path37.join)(dir, "mcp.json");
|
|
15392
15785
|
(0, import_node_fs34.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
15393
15786
|
return cfgPath;
|
|
@@ -15395,13 +15788,13 @@ function writeMcpServersConfig(servers, extraServers) {
|
|
|
15395
15788
|
async function writeInjectedMcpConfig(opts) {
|
|
15396
15789
|
return writeMcpServersConfig(await buildInjectedMcpServers(opts));
|
|
15397
15790
|
}
|
|
15398
|
-
var import_node_fs34, import_node_module,
|
|
15791
|
+
var import_node_fs34, import_node_module, import_node_os12, import_node_path37, import_node_url, import_meta2, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS, SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS, SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
|
|
15399
15792
|
var init_injected_mcp = __esm({
|
|
15400
15793
|
"src/agents/injected-mcp.ts"() {
|
|
15401
15794
|
"use strict";
|
|
15402
15795
|
import_node_fs34 = require("fs");
|
|
15403
15796
|
import_node_module = require("module");
|
|
15404
|
-
|
|
15797
|
+
import_node_os12 = require("os");
|
|
15405
15798
|
import_node_path37 = require("path");
|
|
15406
15799
|
import_node_url = require("url");
|
|
15407
15800
|
init_run();
|
|
@@ -15460,10 +15853,10 @@ var init_injected_mcp = __esm({
|
|
|
15460
15853
|
|
|
15461
15854
|
// src/agents/user-mcp-config.ts
|
|
15462
15855
|
function userCursorMcpConfigPath() {
|
|
15463
|
-
return (0, import_node_path38.join)((0,
|
|
15856
|
+
return (0, import_node_path38.join)((0, import_node_os13.homedir)(), ".cursor", "mcp.json");
|
|
15464
15857
|
}
|
|
15465
15858
|
function userClaudeMcpConfigPath() {
|
|
15466
|
-
return (0, import_node_path38.join)((0,
|
|
15859
|
+
return (0, import_node_path38.join)((0, import_node_os13.homedir)(), ".claude.json");
|
|
15467
15860
|
}
|
|
15468
15861
|
function asObject(value) {
|
|
15469
15862
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -15523,12 +15916,12 @@ async function registerPackagedUserMcpClients() {
|
|
|
15523
15916
|
}
|
|
15524
15917
|
return { cursor };
|
|
15525
15918
|
}
|
|
15526
|
-
var import_node_fs35,
|
|
15919
|
+
var import_node_fs35, import_node_os13, import_node_path38;
|
|
15527
15920
|
var init_user_mcp_config = __esm({
|
|
15528
15921
|
"src/agents/user-mcp-config.ts"() {
|
|
15529
15922
|
"use strict";
|
|
15530
15923
|
import_node_fs35 = require("fs");
|
|
15531
|
-
|
|
15924
|
+
import_node_os13 = require("os");
|
|
15532
15925
|
import_node_path38 = require("path");
|
|
15533
15926
|
init_paths();
|
|
15534
15927
|
init_injected_mcp();
|
|
@@ -15569,10 +15962,10 @@ function readText(path2) {
|
|
|
15569
15962
|
return "";
|
|
15570
15963
|
}
|
|
15571
15964
|
}
|
|
15572
|
-
function userCodexConfigPaths(home = (0,
|
|
15965
|
+
function userCodexConfigPaths(home = (0, import_node_os14.homedir)()) {
|
|
15573
15966
|
return [(0, import_node_path39.join)(home, ".codex", "config.toml"), (0, import_node_path39.join)(home, ".config", "codex", "config.toml")];
|
|
15574
15967
|
}
|
|
15575
|
-
function userOpencodeConfigPaths(home = (0,
|
|
15968
|
+
function userOpencodeConfigPaths(home = (0, import_node_os14.homedir)()) {
|
|
15576
15969
|
return [
|
|
15577
15970
|
(0, import_node_path39.join)(home, ".config", "opencode", "opencode.json"),
|
|
15578
15971
|
(0, import_node_path39.join)(home, ".config", "opencode", "opencode.jsonc")
|
|
@@ -15594,7 +15987,7 @@ function userMcpNamesToDisable(opts) {
|
|
|
15594
15987
|
}
|
|
15595
15988
|
return out;
|
|
15596
15989
|
}
|
|
15597
|
-
function listUserCodexMcpNames(home = (0,
|
|
15990
|
+
function listUserCodexMcpNames(home = (0, import_node_os14.homedir)()) {
|
|
15598
15991
|
const names = [];
|
|
15599
15992
|
for (const path2 of userCodexConfigPaths(home)) {
|
|
15600
15993
|
if (!(0, import_node_fs36.existsSync)(path2)) continue;
|
|
@@ -15602,7 +15995,7 @@ function listUserCodexMcpNames(home = (0, import_node_os15.homedir)()) {
|
|
|
15602
15995
|
}
|
|
15603
15996
|
return names;
|
|
15604
15997
|
}
|
|
15605
|
-
function listUserOpencodeMcpNames(home = (0,
|
|
15998
|
+
function listUserOpencodeMcpNames(home = (0, import_node_os14.homedir)()) {
|
|
15606
15999
|
const names = [];
|
|
15607
16000
|
for (const path2 of userOpencodeConfigPaths(home)) {
|
|
15608
16001
|
if (!(0, import_node_fs36.existsSync)(path2)) continue;
|
|
@@ -15610,12 +16003,12 @@ function listUserOpencodeMcpNames(home = (0, import_node_os15.homedir)()) {
|
|
|
15610
16003
|
}
|
|
15611
16004
|
return names;
|
|
15612
16005
|
}
|
|
15613
|
-
function userClaudeMcpConfigObject(home = (0,
|
|
15614
|
-
const claudePath = home === (0,
|
|
16006
|
+
function userClaudeMcpConfigObject(home = (0, import_node_os14.homedir)()) {
|
|
16007
|
+
const claudePath = home === (0, import_node_os14.homedir)() ? userClaudeMcpConfigPath() : (0, import_node_path39.join)(home, ".claude.json");
|
|
15615
16008
|
if (!(0, import_node_fs36.existsSync)(claudePath)) return {};
|
|
15616
16009
|
return asObject2(asObject2(readJsonObject2(claudePath)).mcpServers);
|
|
15617
16010
|
}
|
|
15618
|
-
function listUserClaudeMcpServerEntries(home = (0,
|
|
16011
|
+
function listUserClaudeMcpServerEntries(home = (0, import_node_os14.homedir)(), projectDirs) {
|
|
15619
16012
|
const out = {};
|
|
15620
16013
|
for (const [name, entry] of Object.entries(
|
|
15621
16014
|
listEnabledClaudePluginMcpServers({ home, projectDirs })
|
|
@@ -15651,13 +16044,13 @@ function toCodexUnattendedAppsArgs() {
|
|
|
15651
16044
|
"features.plugins=false"
|
|
15652
16045
|
];
|
|
15653
16046
|
}
|
|
15654
|
-
var import_node_fs36,
|
|
16047
|
+
var import_node_fs36, import_node_os14, import_node_path39, import_smol_toml2;
|
|
15655
16048
|
var init_orch_mcp_isolation = __esm({
|
|
15656
16049
|
"src/agents/orch-mcp-isolation.ts"() {
|
|
15657
16050
|
"use strict";
|
|
15658
16051
|
import_node_fs36 = require("fs");
|
|
15659
16052
|
init_claude_plugins();
|
|
15660
|
-
|
|
16053
|
+
import_node_os14 = require("os");
|
|
15661
16054
|
import_node_path39 = require("path");
|
|
15662
16055
|
import_smol_toml2 = require("smol-toml");
|
|
15663
16056
|
init_user_mcp_config();
|
|
@@ -15758,7 +16151,7 @@ var init_proxy_server = __esm({
|
|
|
15758
16151
|
|
|
15759
16152
|
// src/mcp-ui/proxy-http.ts
|
|
15760
16153
|
async function listenMcpUiProxy(opts) {
|
|
15761
|
-
const token = (0,
|
|
16154
|
+
const token = (0, import_node_crypto10.randomBytes)(24).toString("hex");
|
|
15762
16155
|
const transports = /* @__PURE__ */ new Map();
|
|
15763
16156
|
const httpServer = (0, import_node_http.createServer)((req, res) => {
|
|
15764
16157
|
void handle(req, res);
|
|
@@ -15796,7 +16189,7 @@ async function listenMcpUiProxy(opts) {
|
|
|
15796
16189
|
return;
|
|
15797
16190
|
}
|
|
15798
16191
|
const created = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
15799
|
-
sessionIdGenerator: () => (0,
|
|
16192
|
+
sessionIdGenerator: () => (0, import_node_crypto10.randomUUID)(),
|
|
15800
16193
|
allowedHosts: ["127.0.0.1", "localhost"],
|
|
15801
16194
|
onsessioninitialized: (id) => {
|
|
15802
16195
|
transports.set(`${sessionKey}:${id}`, created);
|
|
@@ -15849,11 +16242,11 @@ function parseMcpUiProxyPath(url) {
|
|
|
15849
16242
|
return null;
|
|
15850
16243
|
}
|
|
15851
16244
|
}
|
|
15852
|
-
var
|
|
16245
|
+
var import_node_crypto10, import_node_http, import_server2, import_streamableHttp;
|
|
15853
16246
|
var init_proxy_http = __esm({
|
|
15854
16247
|
"src/mcp-ui/proxy-http.ts"() {
|
|
15855
16248
|
"use strict";
|
|
15856
|
-
|
|
16249
|
+
import_node_crypto10 = require("crypto");
|
|
15857
16250
|
import_node_http = require("http");
|
|
15858
16251
|
import_server2 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
15859
16252
|
import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
@@ -15990,7 +16383,7 @@ var init_session = __esm({
|
|
|
15990
16383
|
function getMcpUiHost() {
|
|
15991
16384
|
if (!singleton) {
|
|
15992
16385
|
singleton = new McpUiHost({
|
|
15993
|
-
entries: (projectDirs) => listUserClaudeMcpServerEntries((0,
|
|
16386
|
+
entries: (projectDirs) => listUserClaudeMcpServerEntries((0, import_node_os15.homedir)(), projectDirs)
|
|
15994
16387
|
});
|
|
15995
16388
|
}
|
|
15996
16389
|
return singleton;
|
|
@@ -15998,7 +16391,7 @@ function getMcpUiHost() {
|
|
|
15998
16391
|
async function proxyClaudeUserMcp(orchestrator, projectDirs) {
|
|
15999
16392
|
if (orchestrator) return {};
|
|
16000
16393
|
const dirs = projectDirs.filter((d) => typeof d === "string" && d.length > 0);
|
|
16001
|
-
return getMcpUiHost().proxyEntries(listUserClaudeMcpServerEntries((0,
|
|
16394
|
+
return getMcpUiHost().proxyEntries(listUserClaudeMcpServerEntries((0, import_node_os15.homedir)(), dirs), dirs);
|
|
16002
16395
|
}
|
|
16003
16396
|
function closeMcpUiHost() {
|
|
16004
16397
|
const host = singleton;
|
|
@@ -16007,14 +16400,14 @@ function closeMcpUiHost() {
|
|
|
16007
16400
|
}
|
|
16008
16401
|
function dirsKeyFor(projectDirs) {
|
|
16009
16402
|
if (!projectDirs?.length) return "";
|
|
16010
|
-
return (0,
|
|
16403
|
+
return (0, import_node_crypto11.createHash)("sha256").update(projectDirs.join("\0")).digest("hex").slice(0, 16);
|
|
16011
16404
|
}
|
|
16012
|
-
var
|
|
16405
|
+
var import_node_crypto11, import_node_os15, TOOL_TTL_MS, McpUiHost, singleton;
|
|
16013
16406
|
var init_host = __esm({
|
|
16014
16407
|
"src/mcp-ui/host.ts"() {
|
|
16015
16408
|
"use strict";
|
|
16016
|
-
|
|
16017
|
-
|
|
16409
|
+
import_node_crypto11 = require("crypto");
|
|
16410
|
+
import_node_os15 = require("os");
|
|
16018
16411
|
init_orch_mcp_isolation();
|
|
16019
16412
|
init_meta();
|
|
16020
16413
|
init_proxy_http();
|
|
@@ -17150,8 +17543,8 @@ function usageFromCodex(usage) {
|
|
|
17150
17543
|
}
|
|
17151
17544
|
function codexConfigHasNetworkAccess() {
|
|
17152
17545
|
const candidates = [
|
|
17153
|
-
(0, import_node_path42.join)((0,
|
|
17154
|
-
(0, import_node_path42.join)((0,
|
|
17546
|
+
(0, import_node_path42.join)((0, import_node_os16.homedir)(), ".codex", "config.toml"),
|
|
17547
|
+
(0, import_node_path42.join)((0, import_node_os16.homedir)(), ".config", "codex", "config.toml")
|
|
17155
17548
|
];
|
|
17156
17549
|
for (const path2 of candidates) {
|
|
17157
17550
|
if (!(0, import_node_fs40.existsSync)(path2)) continue;
|
|
@@ -17187,7 +17580,7 @@ function asRecord5(value) {
|
|
|
17187
17580
|
return void 0;
|
|
17188
17581
|
}
|
|
17189
17582
|
function codexLooksAuthenticated() {
|
|
17190
|
-
const authPath = (0, import_node_path42.join)((0,
|
|
17583
|
+
const authPath = (0, import_node_path42.join)((0, import_node_os16.homedir)(), ".codex", "auth.json");
|
|
17191
17584
|
if (!(0, import_node_fs40.existsSync)(authPath)) return false;
|
|
17192
17585
|
try {
|
|
17193
17586
|
return (0, import_node_fs40.statSync)(authPath).size > 2;
|
|
@@ -17195,12 +17588,12 @@ function codexLooksAuthenticated() {
|
|
|
17195
17588
|
return false;
|
|
17196
17589
|
}
|
|
17197
17590
|
}
|
|
17198
|
-
var import_node_fs40,
|
|
17591
|
+
var import_node_fs40, import_node_os16, import_node_path42, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
17199
17592
|
var init_codex = __esm({
|
|
17200
17593
|
"src/agents/codex.ts"() {
|
|
17201
17594
|
"use strict";
|
|
17202
17595
|
import_node_fs40 = require("fs");
|
|
17203
|
-
|
|
17596
|
+
import_node_os16 = require("os");
|
|
17204
17597
|
import_node_path42 = require("path");
|
|
17205
17598
|
init_run();
|
|
17206
17599
|
init_app_settings();
|
|
@@ -19096,7 +19489,7 @@ function accessTokenFromCredentialsJson(raw) {
|
|
|
19096
19489
|
}
|
|
19097
19490
|
}
|
|
19098
19491
|
function claudeCredentialsPath(configDir) {
|
|
19099
|
-
const root = configDir?.trim() || process.env.CLAUDE_CONFIG_DIR?.trim() || (0, import_node_path47.join)((0,
|
|
19492
|
+
const root = configDir?.trim() || process.env.CLAUDE_CONFIG_DIR?.trim() || (0, import_node_path47.join)((0, import_node_os17.homedir)(), ".claude");
|
|
19100
19493
|
return (0, import_node_path47.join)(root, ".credentials.json");
|
|
19101
19494
|
}
|
|
19102
19495
|
async function readFileAccessToken(configDir) {
|
|
@@ -19214,12 +19607,12 @@ async function getClaudePlanUsage(opts = {}) {
|
|
|
19214
19607
|
})();
|
|
19215
19608
|
return inflight;
|
|
19216
19609
|
}
|
|
19217
|
-
var import_node_fs46,
|
|
19610
|
+
var import_node_fs46, import_node_os17, import_node_path47, CLAUDE_OAUTH_USAGE_URL, CLAUDE_USAGE_TTL_MS, CLAUDE_USAGE_ERROR_TTL_MS, CLAUDE_USAGE_STALE_OK_MS, KEYCHAIN_SERVICES, cache, errorUntil, inflight, lastGood, claudeVersion, cacheDirKey;
|
|
19218
19611
|
var init_claude_usage_client = __esm({
|
|
19219
19612
|
"src/agents/claude-usage-client.ts"() {
|
|
19220
19613
|
"use strict";
|
|
19221
19614
|
import_node_fs46 = require("fs");
|
|
19222
|
-
|
|
19615
|
+
import_node_os17 = require("os");
|
|
19223
19616
|
import_node_path47 = require("path");
|
|
19224
19617
|
init_run();
|
|
19225
19618
|
init_fetch();
|
|
@@ -20125,7 +20518,9 @@ function resolveSidebarGitPrompt(action, opts) {
|
|
|
20125
20518
|
}
|
|
20126
20519
|
return agentGitPrompt(action, opts);
|
|
20127
20520
|
}
|
|
20128
|
-
function gitActionExpansion(action, base) {
|
|
20521
|
+
function gitActionExpansion(action, base, forge) {
|
|
20522
|
+
if (forge === "cursor") return cursorGitActionExpansion(action, base);
|
|
20523
|
+
if (forge === "entire") return entireGitActionExpansion(action, base);
|
|
20129
20524
|
switch (action) {
|
|
20130
20525
|
case "commit-push":
|
|
20131
20526
|
return "Commit any uncommitted work with a purpose-stating message, then push to origin (`git push -u origin HEAD`; this updates an existing PR when one is linked). Do not start a checks loop unless a goal was given.";
|
|
@@ -20150,7 +20545,57 @@ function gitActionExpansion(action, base) {
|
|
|
20150
20545
|
return "This phrase is the explicit ask to merge this thread's open pull request on GitHub. If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.";
|
|
20151
20546
|
}
|
|
20152
20547
|
}
|
|
20153
|
-
function
|
|
20548
|
+
function cursorGitActionExpansion(action, base) {
|
|
20549
|
+
switch (action) {
|
|
20550
|
+
case "commit-push":
|
|
20551
|
+
return "Commit any uncommitted work with a purpose-stating message, then push to origin (`git push -u origin HEAD`; this updates an existing PR when one is linked). Use `origin`, not `gh`. Do not start a checks loop unless a goal was given.";
|
|
20552
|
+
case "create-draft":
|
|
20553
|
+
return "Commit, push, then create a draft PR with `origin pr create --draft --push -R <origin-owner/name> --body-file <short.md>` (title/body from the change purpose). Take the URL from `--json url`. Update the existing PR with `origin pr edit` if one is linked. Do not use `gh`.";
|
|
20554
|
+
case "create-web":
|
|
20555
|
+
return "Commit, push, then `origin pr create --push -R <origin-owner/name>` and open the URL from `--json url`. Origin has no `--web` form. Add `--draft` when they asked for a draft. Do not use `gh`.";
|
|
20556
|
+
case "resolve-conflicts":
|
|
20557
|
+
if (base && !isMainishPrBase(base)) {
|
|
20558
|
+
return `Fetch \`origin/${base}\` (this PR's base \u2014 not main/master), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable. Do not merge origin/main.`;
|
|
20559
|
+
}
|
|
20560
|
+
if (base) {
|
|
20561
|
+
return `Fetch the PR base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
|
|
20562
|
+
}
|
|
20563
|
+
return "Look up this PR's base with `origin pr view --json baseRefName` and merge that remote branch into this branch (do not assume main). Resolve conflicts carefully, then commit and push until the PR is mergeable. Do not use `gh`.";
|
|
20564
|
+
case "ready-for-review":
|
|
20565
|
+
return "This phrase is the explicit ask to mark this thread's draft pull request ready for review on Cursor (`origin pr ready -R <origin-owner/name>`). Update title/body if the purpose drifted. Do not merge. Do not use `gh`.";
|
|
20566
|
+
case "merge":
|
|
20567
|
+
if (base && !isMainishPrBase(base)) {
|
|
20568
|
+
return `This phrase is the explicit ask to merge this thread's open pull request into \`${base}\` on Cursor with \`origin pr merge\`. This PR targets \`${base}\`, not main \u2014 do not use \`origin stack merge\` and do not retarget or merge into main/master. Do not force-push main/master or merge locally into the main checkout. Do not use \`gh\`.`;
|
|
20569
|
+
}
|
|
20570
|
+
return "This phrase is the explicit ask to merge this thread's open pull request on Cursor. If `origin stack view` shows a stack, use `origin stack merge`; otherwise `origin pr merge`. Do not force-push main/master or merge locally into the main checkout. Do not use `gh`.";
|
|
20571
|
+
}
|
|
20572
|
+
}
|
|
20573
|
+
function entireGitActionExpansion(action, base) {
|
|
20574
|
+
switch (action) {
|
|
20575
|
+
case "commit-push":
|
|
20576
|
+
return "Commit any uncommitted work with a purpose-stating message, then push to origin (`git push -u origin HEAD`). Use `entire`, not `gh` or `origin`. Do not start a checks loop unless a goal was given.";
|
|
20577
|
+
case "create-draft":
|
|
20578
|
+
return 'Commit, push, then open a Trail with `entire trail create --title "<title>" --body "<short>"` (title/body from the change purpose). Take the URL from `--json`. If this branch already has a trail, `entire trail update` instead of creating another. Trails have no draft flag. Do not use `gh` or `origin`.';
|
|
20579
|
+
case "create-web":
|
|
20580
|
+
return 'Commit, push, then `entire trail create --title "<title>" --body "<short>"` and open the URL from `--json`. Entire has no `--web` form. Do not use `gh` or `origin`.';
|
|
20581
|
+
case "resolve-conflicts":
|
|
20582
|
+
if (base && !isMainishPrBase(base)) {
|
|
20583
|
+
return `Fetch \`origin/${base}\` (this Trail's base \u2014 not main/master), merge it into this branch, resolve conflicts carefully, then commit and push. Do not merge origin/main.`;
|
|
20584
|
+
}
|
|
20585
|
+
if (base) {
|
|
20586
|
+
return `Fetch the Trail base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push.`;
|
|
20587
|
+
}
|
|
20588
|
+
return "Look up this Trail's base with `entire trail show --json` and merge that remote branch into this branch (do not assume main). Resolve conflicts carefully, then commit and push. Do not use `gh`.";
|
|
20589
|
+
case "ready-for-review":
|
|
20590
|
+
return "This phrase means the Trail should be ready for a person to review. Trails have no draft flag and start open. Update title or body with `entire trail update` if the purpose drifted. Do not approve the trail and do not merge. Do not use `gh`.";
|
|
20591
|
+
case "merge":
|
|
20592
|
+
if (base && !isMainishPrBase(base)) {
|
|
20593
|
+
return `This phrase is the explicit ask to merge this thread's Trail change into \`${base}\` with \`entire trail merge\`. This change targets \`${base}\`, not main \u2014 do not retarget or merge into main/master. Do not force-push main/master or merge locally into the main checkout. Do not use \`gh\`.`;
|
|
20594
|
+
}
|
|
20595
|
+
return "This phrase is the explicit ask to merge this thread's Trail change with `entire trail merge`. Do not force-push main/master or merge locally into the main checkout. Do not use `gh`.";
|
|
20596
|
+
}
|
|
20597
|
+
}
|
|
20598
|
+
function expandCanonicalGitRequest(prompt, opts) {
|
|
20154
20599
|
const trimmed = prompt.trim();
|
|
20155
20600
|
let action = null;
|
|
20156
20601
|
let base = null;
|
|
@@ -20175,11 +20620,12 @@ function expandCanonicalGitRequest(prompt) {
|
|
|
20175
20620
|
base = m[1]?.trim() || null;
|
|
20176
20621
|
}
|
|
20177
20622
|
}
|
|
20178
|
-
|
|
20623
|
+
const forge = opts?.forge ?? null;
|
|
20624
|
+
let expansion = action ? gitActionExpansion(action, base, forge) : null;
|
|
20179
20625
|
if (!expansion && trimmed === "Address review comments.") {
|
|
20180
|
-
expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
|
|
20626
|
+
expansion = forge === "cursor" ? "Read the PR review feedback (`origin pr view --comments`, `origin pr thread list`), make the requested changes, commit, and push. Do not use `gh`." : forge === "entire" ? "Read open findings (`entire trail finding list`), make the requested changes, commit, and push. Do not use `gh` or `entire trail comment` (agent sessions cannot post trail comments)." : "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
|
|
20181
20627
|
} else if (!expansion && FIX_CI_RE.test(trimmed)) {
|
|
20182
|
-
expansion = "Investigate that failing check (`gh pr checks`, `gh run view --log-failed`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given.";
|
|
20628
|
+
expansion = forge === "cursor" ? "Investigate that failing check (`origin pr checks`, `origin pr watch`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given. Do not use `gh run`." : forge === "entire" ? "Investigate the blocking gate (`entire trail merge --dry-run`, `entire trail finding list`, `entire trail watch`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given. Do not use `gh run`." : "Investigate that failing check (`gh pr checks`, `gh run view --log-failed`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given.";
|
|
20183
20629
|
}
|
|
20184
20630
|
if (!expansion) return prompt;
|
|
20185
20631
|
return `${trimmed}
|
|
@@ -20935,7 +21381,7 @@ function forkMessageSlice(from, throughIndex) {
|
|
|
20935
21381
|
function buildForkTranscriptAttachment(baseTitle, messages) {
|
|
20936
21382
|
const title = baseTitle || "Chat";
|
|
20937
21383
|
return {
|
|
20938
|
-
id: (0,
|
|
21384
|
+
id: (0, import_node_crypto12.randomUUID)(),
|
|
20939
21385
|
name: `Transcript of ${title}.md`,
|
|
20940
21386
|
kind: "transcript",
|
|
20941
21387
|
content: formatTranscriptMarkdown(title, messages)
|
|
@@ -20994,11 +21440,11 @@ function forkChatTab(input) {
|
|
|
20994
21440
|
}
|
|
20995
21441
|
return tab;
|
|
20996
21442
|
}
|
|
20997
|
-
var
|
|
21443
|
+
var import_node_crypto12;
|
|
20998
21444
|
var init_chat_tabs = __esm({
|
|
20999
21445
|
"src/threads/chat-tabs.ts"() {
|
|
21000
21446
|
"use strict";
|
|
21001
|
-
|
|
21447
|
+
import_node_crypto12 = require("crypto");
|
|
21002
21448
|
init_context_compact();
|
|
21003
21449
|
init_teams();
|
|
21004
21450
|
init_worktree_labels();
|
|
@@ -21265,7 +21711,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
21265
21711
|
const path2 = opts?.path ?? REVIEW_SKILL_PATH;
|
|
21266
21712
|
const name = opts?.name ?? (path2 === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path2 === REPO_REVIEW_PATH || path2 === CONTEXT_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
21267
21713
|
return {
|
|
21268
|
-
id: (0,
|
|
21714
|
+
id: (0, import_node_crypto13.randomUUID)(),
|
|
21269
21715
|
name,
|
|
21270
21716
|
kind: "file",
|
|
21271
21717
|
path: path2,
|
|
@@ -21321,11 +21767,11 @@ async function requestReview(threadRef, send3) {
|
|
|
21321
21767
|
const started = await send3(tab.id, REVIEW_REQUEST_PREFILL);
|
|
21322
21768
|
return { tab: started, from };
|
|
21323
21769
|
}
|
|
21324
|
-
var
|
|
21770
|
+
var import_node_crypto13, import_node_fs49, import_node_path50, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
|
|
21325
21771
|
var init_request_review = __esm({
|
|
21326
21772
|
"src/review/request-review.ts"() {
|
|
21327
21773
|
"use strict";
|
|
21328
|
-
|
|
21774
|
+
import_node_crypto13 = require("crypto");
|
|
21329
21775
|
import_node_fs49 = require("fs");
|
|
21330
21776
|
import_node_path50 = require("path");
|
|
21331
21777
|
init_global_workspace();
|
|
@@ -23369,7 +23815,7 @@ function isUnclaimedSteerRequest(req) {
|
|
|
23369
23815
|
}
|
|
23370
23816
|
function nextSteerRequest(existing) {
|
|
23371
23817
|
if (existing?.requestId && !existing.claimedAt) return existing;
|
|
23372
|
-
return { requestId: (0,
|
|
23818
|
+
return { requestId: (0, import_node_crypto14.randomUUID)(), requestedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
23373
23819
|
}
|
|
23374
23820
|
function claimSteerRequest(threadId) {
|
|
23375
23821
|
const pending = readThread(threadId)?.steerRequest;
|
|
@@ -23378,11 +23824,11 @@ function claimSteerRequest(threadId) {
|
|
|
23378
23824
|
steerRequest: { ...pending, claimedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
23379
23825
|
});
|
|
23380
23826
|
}
|
|
23381
|
-
var
|
|
23827
|
+
var import_node_crypto14;
|
|
23382
23828
|
var init_steer_request = __esm({
|
|
23383
23829
|
"src/orchestrator/steer-request.ts"() {
|
|
23384
23830
|
"use strict";
|
|
23385
|
-
|
|
23831
|
+
import_node_crypto14 = require("crypto");
|
|
23386
23832
|
init_thread_store();
|
|
23387
23833
|
}
|
|
23388
23834
|
});
|
|
@@ -23698,8 +24144,8 @@ function resolveAbleTimeOAuthHost(requested, saved) {
|
|
|
23698
24144
|
return fromSaved || void 0;
|
|
23699
24145
|
}
|
|
23700
24146
|
function createAbleTimePkce() {
|
|
23701
|
-
const verifier = (0,
|
|
23702
|
-
const challenge = (0,
|
|
24147
|
+
const verifier = (0, import_node_crypto15.randomBytes)(32).toString("base64url");
|
|
24148
|
+
const challenge = (0, import_node_crypto15.createHash)("sha256").update(verifier).digest("base64url");
|
|
23703
24149
|
return { verifier, challenge };
|
|
23704
24150
|
}
|
|
23705
24151
|
function ableTimeOAuthAuthorizeUrl(clientId, state, codeChallenge, host) {
|
|
@@ -23804,7 +24250,7 @@ async function startAbleTimeOAuth(opts) {
|
|
|
23804
24250
|
opts?.host,
|
|
23805
24251
|
loadAppSettings().integrations.abletimeHost
|
|
23806
24252
|
);
|
|
23807
|
-
const state = (0,
|
|
24253
|
+
const state = (0, import_node_crypto15.randomBytes)(16).toString("hex");
|
|
23808
24254
|
const pkce = createAbleTimePkce();
|
|
23809
24255
|
const authorizeUrl = ableTimeOAuthAuthorizeUrl(clientId, state, pkce.challenge, host);
|
|
23810
24256
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
@@ -23904,11 +24350,11 @@ async function startAbleTimeOAuth(opts) {
|
|
|
23904
24350
|
return loadAppSettings();
|
|
23905
24351
|
}
|
|
23906
24352
|
}
|
|
23907
|
-
var
|
|
24353
|
+
var import_node_crypto15, import_node_http2, ABLETIME_OAUTH_CALLBACK_PATH, ABLETIME_OAUTH_PORT, ABLETIME_OAUTH_LOCAL_CALLBACK, ABLETIME_OAUTH_REDIRECT, BOUNCE_QUERY_KEYS, BAKED_ABLETIME_OAUTH_CLIENT_ID, ABLETIME_OAUTH_RESOURCE, REFRESH_SKEW_MS2, refreshInFlight2, ABLETIME_OAUTH_CANCELLED, AbleTimeOAuthCancelledError;
|
|
23908
24354
|
var init_abletime_oauth = __esm({
|
|
23909
24355
|
"src/integrations/abletime-oauth.ts"() {
|
|
23910
24356
|
"use strict";
|
|
23911
|
-
|
|
24357
|
+
import_node_crypto15 = require("crypto");
|
|
23912
24358
|
import_node_http2 = require("http");
|
|
23913
24359
|
init_fetch();
|
|
23914
24360
|
init_app_settings();
|
|
@@ -24669,7 +25115,7 @@ function uniqueAttachmentFileName(dir, originalName) {
|
|
|
24669
25115
|
const candidate = `${stem}-${i}${ext}`;
|
|
24670
25116
|
if (!(0, import_node_fs55.existsSync)((0, import_node_path56.join)(dir, candidate))) return candidate;
|
|
24671
25117
|
}
|
|
24672
|
-
return `${stem}-${(0,
|
|
25118
|
+
return `${stem}-${(0, import_node_crypto16.randomUUID)()}${ext}`;
|
|
24673
25119
|
}
|
|
24674
25120
|
function extractHttpUrls(markdown) {
|
|
24675
25121
|
const text7 = markdown ?? "";
|
|
@@ -24775,13 +25221,13 @@ async function downloadAuthenticatedFile(opts) {
|
|
|
24775
25221
|
...contentType ? { contentType } : {}
|
|
24776
25222
|
};
|
|
24777
25223
|
}
|
|
24778
|
-
var import_node_fs55, import_node_path56,
|
|
25224
|
+
var import_node_fs55, import_node_path56, import_node_crypto16, ISSUE_ATTACHMENT_MAX_BYTES, MARKDOWN_IMAGE_RE, MARKDOWN_LINK_RE, HTML_SRC_RE, BARE_URL_RE, EXT_BY_MIME;
|
|
24779
25225
|
var init_issue_attachments = __esm({
|
|
24780
25226
|
"src/integrations/issue-attachments.ts"() {
|
|
24781
25227
|
"use strict";
|
|
24782
25228
|
import_node_fs55 = require("fs");
|
|
24783
25229
|
import_node_path56 = require("path");
|
|
24784
|
-
|
|
25230
|
+
import_node_crypto16 = require("crypto");
|
|
24785
25231
|
init_fetch();
|
|
24786
25232
|
init_workspace_scratch();
|
|
24787
25233
|
ISSUE_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;
|
|
@@ -26412,7 +26858,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
26412
26858
|
...instructions
|
|
26413
26859
|
].join("\n");
|
|
26414
26860
|
return {
|
|
26415
|
-
id: (0,
|
|
26861
|
+
id: (0, import_node_crypto17.randomUUID)(),
|
|
26416
26862
|
name: orch ? "Orchestration quota handoff.md" : "Quota handoff.md",
|
|
26417
26863
|
kind: "transcript",
|
|
26418
26864
|
content: body
|
|
@@ -26450,11 +26896,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
|
|
|
26450
26896
|
}
|
|
26451
26897
|
return updateThread(tab.id, patch);
|
|
26452
26898
|
}
|
|
26453
|
-
var
|
|
26899
|
+
var import_node_crypto17, QUOTA_CONTINUE_PROMPT, QUOTA_CONTINUE_ACCOUNT_PROMPT, QUOTA_RESUME_PROMPT;
|
|
26454
26900
|
var init_quota_failover = __esm({
|
|
26455
26901
|
"src/orchestrator/quota-failover.ts"() {
|
|
26456
26902
|
"use strict";
|
|
26457
|
-
|
|
26903
|
+
import_node_crypto17 = require("crypto");
|
|
26458
26904
|
init_session_quota();
|
|
26459
26905
|
init_app_settings();
|
|
26460
26906
|
init_managed_accounts();
|
|
@@ -26564,7 +27010,7 @@ function listConductorWorkspaces() {
|
|
|
26564
27010
|
if (!(0, import_node_fs58.existsSync)(CONDUCTOR_DB)) {
|
|
26565
27011
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
26566
27012
|
}
|
|
26567
|
-
const tmp = (0, import_node_fs58.mkdtempSync)((0, import_node_path58.join)((0,
|
|
27013
|
+
const tmp = (0, import_node_fs58.mkdtempSync)((0, import_node_path58.join)((0, import_node_os18.tmpdir)(), "sideboard-conductor-"));
|
|
26568
27014
|
const snapshot = (0, import_node_path58.join)(tmp, "conductor.db");
|
|
26569
27015
|
try {
|
|
26570
27016
|
(0, import_node_fs58.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
@@ -26655,7 +27101,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
26655
27101
|
if (!(0, import_node_fs58.existsSync)(CONDUCTOR_DB)) {
|
|
26656
27102
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
26657
27103
|
}
|
|
26658
|
-
const tmp = (0, import_node_fs58.mkdtempSync)((0, import_node_path58.join)((0,
|
|
27104
|
+
const tmp = (0, import_node_fs58.mkdtempSync)((0, import_node_path58.join)((0, import_node_os18.tmpdir)(), "sideboard-conductor-"));
|
|
26659
27105
|
const snapshot = (0, import_node_path58.join)(tmp, "conductor.db");
|
|
26660
27106
|
try {
|
|
26661
27107
|
(0, import_node_fs58.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
@@ -26750,13 +27196,13 @@ function importConductorWorkspace(workspaceId) {
|
|
|
26750
27196
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
26751
27197
|
return importConductorWorkspace(workspaceId);
|
|
26752
27198
|
}
|
|
26753
|
-
var import_node_child_process6, import_node_fs58,
|
|
27199
|
+
var import_node_child_process6, import_node_fs58, import_node_os18, import_node_path58, import_node_module6, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
|
|
26754
27200
|
var init_adopt = __esm({
|
|
26755
27201
|
"src/threads/adopt.ts"() {
|
|
26756
27202
|
"use strict";
|
|
26757
27203
|
import_node_child_process6 = require("child_process");
|
|
26758
27204
|
import_node_fs58 = require("fs");
|
|
26759
|
-
|
|
27205
|
+
import_node_os18 = require("os");
|
|
26760
27206
|
import_node_path58 = require("path");
|
|
26761
27207
|
import_node_module6 = require("module");
|
|
26762
27208
|
init_worktree();
|
|
@@ -27080,9 +27526,187 @@ var init_stack_layers = __esm({
|
|
|
27080
27526
|
}
|
|
27081
27527
|
});
|
|
27082
27528
|
|
|
27529
|
+
// src/git/pr-write.ts
|
|
27530
|
+
async function lookupGithubGraphqlReset(cwd) {
|
|
27531
|
+
const result = await gh(["api", "rate_limit"], cwd, { reject: false });
|
|
27532
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) return void 0;
|
|
27533
|
+
try {
|
|
27534
|
+
const data = JSON.parse(result.stdout);
|
|
27535
|
+
const reset = data.resources?.graphql?.reset;
|
|
27536
|
+
return typeof reset === "number" ? reset : void 0;
|
|
27537
|
+
} catch {
|
|
27538
|
+
return void 0;
|
|
27539
|
+
}
|
|
27540
|
+
}
|
|
27541
|
+
async function formatPrCreateFailure(raw, cwd, ctx) {
|
|
27542
|
+
if (!isGhRateLimitError(raw)) {
|
|
27543
|
+
return formatGhLandError(raw, {
|
|
27544
|
+
targetedRepo: ctx?.slug,
|
|
27545
|
+
headRef: ctx?.head
|
|
27546
|
+
});
|
|
27547
|
+
}
|
|
27548
|
+
const resetAt = await lookupGithubGraphqlReset(cwd);
|
|
27549
|
+
return formatGhLandError(raw, {
|
|
27550
|
+
resetAt,
|
|
27551
|
+
targetedRepo: ctx?.slug,
|
|
27552
|
+
headRef: ctx?.head
|
|
27553
|
+
});
|
|
27554
|
+
}
|
|
27555
|
+
async function createCursorPullRequest(worktreePath, slug, opts) {
|
|
27556
|
+
const bodyText = (opts.body ?? opts.title).trim() || opts.title;
|
|
27557
|
+
const bodyFile = (0, import_node_path59.join)(
|
|
27558
|
+
(0, import_node_os19.tmpdir)(),
|
|
27559
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto18.randomBytes)(6).toString("hex")}.md`
|
|
27560
|
+
);
|
|
27561
|
+
(0, import_node_fs60.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
27562
|
+
`, "utf8");
|
|
27563
|
+
try {
|
|
27564
|
+
return await createOrUpdateCursorPr(worktreePath, slug, {
|
|
27565
|
+
title: opts.title,
|
|
27566
|
+
bodyFile,
|
|
27567
|
+
base: opts.base,
|
|
27568
|
+
head: opts.head,
|
|
27569
|
+
draft: opts.draft
|
|
27570
|
+
});
|
|
27571
|
+
} finally {
|
|
27572
|
+
try {
|
|
27573
|
+
(0, import_node_fs60.unlinkSync)(bodyFile);
|
|
27574
|
+
} catch {
|
|
27575
|
+
}
|
|
27576
|
+
}
|
|
27577
|
+
}
|
|
27578
|
+
function ghPrCreateAssigneeArgs(assignee) {
|
|
27579
|
+
const raw = assignee?.trim();
|
|
27580
|
+
if (raw && /^(none|unassigned)$/i.test(raw)) return [];
|
|
27581
|
+
return ["--assignee", raw || "@me"];
|
|
27582
|
+
}
|
|
27583
|
+
async function createOrUpdatePr(worktreePath, opts) {
|
|
27584
|
+
const origin = await resolveOriginRemote(worktreePath);
|
|
27585
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
27586
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
27587
|
+
if (cursorSlug) return createCursorPullRequest(worktreePath, cursorSlug, opts);
|
|
27588
|
+
await ensureGhPreferOrigin(worktreePath);
|
|
27589
|
+
const slug = await resolveGithubRepoSlug(worktreePath);
|
|
27590
|
+
if (!slug) {
|
|
27591
|
+
throw new Error(
|
|
27592
|
+
"Could not resolve the origin GitHub repo (owner/name) for this worktree. Check that `git remote get-url origin` points at github.com."
|
|
27593
|
+
);
|
|
27594
|
+
}
|
|
27595
|
+
const repoArgs2 = ghRepoSelectArgs(slug);
|
|
27596
|
+
const headRef = ghHeadRef(slug, opts.head);
|
|
27597
|
+
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
27598
|
+
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
27599
|
+
const bodyFile = (0, import_node_path59.join)(
|
|
27600
|
+
(0, import_node_os19.tmpdir)(),
|
|
27601
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto18.randomBytes)(6).toString("hex")}.md`
|
|
27602
|
+
);
|
|
27603
|
+
(0, import_node_fs60.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
27604
|
+
`, "utf8");
|
|
27605
|
+
const bodyArgs = ["--body-file", bodyFile];
|
|
27606
|
+
try {
|
|
27607
|
+
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
27608
|
+
...opts,
|
|
27609
|
+
slug,
|
|
27610
|
+
repoArgs: repoArgs2,
|
|
27611
|
+
headRef,
|
|
27612
|
+
branchOnly,
|
|
27613
|
+
bodyArgs
|
|
27614
|
+
});
|
|
27615
|
+
} finally {
|
|
27616
|
+
try {
|
|
27617
|
+
(0, import_node_fs60.unlinkSync)(bodyFile);
|
|
27618
|
+
} catch {
|
|
27619
|
+
}
|
|
27620
|
+
}
|
|
27621
|
+
}
|
|
27622
|
+
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
27623
|
+
const { slug, repoArgs: repoArgs2, headRef, branchOnly, bodyArgs } = opts;
|
|
27624
|
+
const existing = await gh(
|
|
27625
|
+
[...repoArgs2, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
27626
|
+
worktreePath,
|
|
27627
|
+
{ reject: false }
|
|
27628
|
+
);
|
|
27629
|
+
if (existing.exitCode === 0 && existing.stdout.trim() && !opts.web) {
|
|
27630
|
+
const url2 = existing.stdout.trim();
|
|
27631
|
+
await gh(
|
|
27632
|
+
[
|
|
27633
|
+
...repoArgs2,
|
|
27634
|
+
"pr",
|
|
27635
|
+
"edit",
|
|
27636
|
+
branchOnly,
|
|
27637
|
+
"--title",
|
|
27638
|
+
opts.title,
|
|
27639
|
+
...bodyArgs
|
|
27640
|
+
],
|
|
27641
|
+
worktreePath,
|
|
27642
|
+
{ reject: false }
|
|
27643
|
+
);
|
|
27644
|
+
return url2;
|
|
27645
|
+
}
|
|
27646
|
+
if (opts.web) {
|
|
27647
|
+
const args2 = [
|
|
27648
|
+
...repoArgs2,
|
|
27649
|
+
"pr",
|
|
27650
|
+
"create",
|
|
27651
|
+
"--web",
|
|
27652
|
+
"--title",
|
|
27653
|
+
opts.title,
|
|
27654
|
+
...bodyArgs,
|
|
27655
|
+
"--base",
|
|
27656
|
+
opts.base,
|
|
27657
|
+
"--head",
|
|
27658
|
+
headRef
|
|
27659
|
+
];
|
|
27660
|
+
if (opts.draft) args2.push("--draft");
|
|
27661
|
+
args2.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
27662
|
+
await gh(args2, worktreePath, { reject: false });
|
|
27663
|
+
const again = await gh(
|
|
27664
|
+
[...repoArgs2, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
27665
|
+
worktreePath,
|
|
27666
|
+
{ reject: false }
|
|
27667
|
+
);
|
|
27668
|
+
return again.stdout.trim() || "";
|
|
27669
|
+
}
|
|
27670
|
+
const args = [
|
|
27671
|
+
...repoArgs2,
|
|
27672
|
+
"pr",
|
|
27673
|
+
"create",
|
|
27674
|
+
"--title",
|
|
27675
|
+
opts.title,
|
|
27676
|
+
...bodyArgs,
|
|
27677
|
+
"--base",
|
|
27678
|
+
opts.base,
|
|
27679
|
+
"--head",
|
|
27680
|
+
headRef
|
|
27681
|
+
];
|
|
27682
|
+
if (opts.draft) args.push("--draft");
|
|
27683
|
+
args.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
27684
|
+
const created = await gh(args, worktreePath, { reject: false });
|
|
27685
|
+
if (created.exitCode !== 0) {
|
|
27686
|
+
const raw = created.stderr.trim() || created.stdout.trim() || "gh pr create failed";
|
|
27687
|
+
throw new Error(await formatPrCreateFailure(raw, worktreePath, { slug, head: headRef }));
|
|
27688
|
+
}
|
|
27689
|
+
const url = created.stdout.trim().split("\n").find((l) => l.startsWith("http")) ?? created.stdout.trim();
|
|
27690
|
+
return url;
|
|
27691
|
+
}
|
|
27692
|
+
var import_node_crypto18, import_node_fs60, import_node_os19, import_node_path59;
|
|
27693
|
+
var init_pr_write = __esm({
|
|
27694
|
+
"src/git/pr-write.ts"() {
|
|
27695
|
+
"use strict";
|
|
27696
|
+
import_node_crypto18 = require("crypto");
|
|
27697
|
+
import_node_fs60 = require("fs");
|
|
27698
|
+
import_node_os19 = require("os");
|
|
27699
|
+
import_node_path59 = require("path");
|
|
27700
|
+
init_gh_errors();
|
|
27701
|
+
init_run();
|
|
27702
|
+
init_cursor_pr();
|
|
27703
|
+
init_worktree();
|
|
27704
|
+
}
|
|
27705
|
+
});
|
|
27706
|
+
|
|
27083
27707
|
// src/diff/diff.ts
|
|
27084
27708
|
async function inspectGitWorktree(worktreePath) {
|
|
27085
|
-
if (!worktreePath || !(0,
|
|
27709
|
+
if (!worktreePath || !(0, import_node_fs61.existsSync)(worktreePath)) return "missing_worktree";
|
|
27086
27710
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
27087
27711
|
reject: false
|
|
27088
27712
|
});
|
|
@@ -27090,7 +27714,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
27090
27714
|
return "ok";
|
|
27091
27715
|
}
|
|
27092
27716
|
async function initializeGitRepository(worktreePath) {
|
|
27093
|
-
if (!worktreePath || !(0,
|
|
27717
|
+
if (!worktreePath || !(0, import_node_fs61.existsSync)(worktreePath)) {
|
|
27094
27718
|
throw new Error("Worktree not found");
|
|
27095
27719
|
}
|
|
27096
27720
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -27224,11 +27848,11 @@ new file mode 100644
|
|
|
27224
27848
|
};
|
|
27225
27849
|
}
|
|
27226
27850
|
async function untrackedPatch(worktreePath, path2, maxHunk) {
|
|
27227
|
-
const abs = (0,
|
|
27851
|
+
const abs = (0, import_node_path60.join)(worktreePath, path2);
|
|
27228
27852
|
try {
|
|
27229
|
-
const st = (0,
|
|
27853
|
+
const st = (0, import_node_fs61.statSync)(abs);
|
|
27230
27854
|
if (st.isFile() && st.size > maxHunk) {
|
|
27231
|
-
const buf = (0,
|
|
27855
|
+
const buf = (0, import_node_fs61.readFileSync)(abs).subarray(0, maxHunk);
|
|
27232
27856
|
return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
|
|
27233
27857
|
}
|
|
27234
27858
|
} catch {
|
|
@@ -27695,9 +28319,9 @@ async function getDiff(worktreePath, repoPath, opts) {
|
|
|
27695
28319
|
}
|
|
27696
28320
|
function statWorktreePath(worktreePath, relativePath) {
|
|
27697
28321
|
assertSafeRelativePath(relativePath);
|
|
27698
|
-
const abs = (0,
|
|
27699
|
-
if (!(0,
|
|
27700
|
-
const st = (0,
|
|
28322
|
+
const abs = (0, import_node_path60.join)(worktreePath, relativePath);
|
|
28323
|
+
if (!(0, import_node_fs61.existsSync)(abs)) return "missing";
|
|
28324
|
+
const st = (0, import_node_fs61.statSync)(abs);
|
|
27701
28325
|
if (st.isDirectory()) return "dir";
|
|
27702
28326
|
if (st.isFile()) return "file";
|
|
27703
28327
|
return "missing";
|
|
@@ -27726,8 +28350,8 @@ function isImageRelativePath(relativePath) {
|
|
|
27726
28350
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
27727
28351
|
assertSafeRelativePath(relativePath);
|
|
27728
28352
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
27729
|
-
const abs = (0,
|
|
27730
|
-
const st = (0,
|
|
28353
|
+
const abs = (0, import_node_path60.join)(worktreePath, relativePath);
|
|
28354
|
+
const st = (0, import_node_fs61.statSync)(abs);
|
|
27731
28355
|
if (!st.isFile()) {
|
|
27732
28356
|
throw new Error(`Not a file: ${relativePath}`);
|
|
27733
28357
|
}
|
|
@@ -27736,7 +28360,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
27736
28360
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
27737
28361
|
);
|
|
27738
28362
|
}
|
|
27739
|
-
const buf = (0,
|
|
28363
|
+
const buf = (0, import_node_fs61.readFileSync)(abs);
|
|
27740
28364
|
return {
|
|
27741
28365
|
path: relativePath,
|
|
27742
28366
|
contentBase64: buf.toString("base64"),
|
|
@@ -27746,12 +28370,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
27746
28370
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
27747
28371
|
assertSafeRelativePath(relativePath);
|
|
27748
28372
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
27749
|
-
const abs = (0,
|
|
27750
|
-
const st = (0,
|
|
28373
|
+
const abs = (0, import_node_path60.join)(worktreePath, relativePath);
|
|
28374
|
+
const st = (0, import_node_fs61.statSync)(abs);
|
|
27751
28375
|
if (!st.isFile()) {
|
|
27752
28376
|
throw new Error(`Not a file: ${relativePath}`);
|
|
27753
28377
|
}
|
|
27754
|
-
const buf = (0,
|
|
28378
|
+
const buf = (0, import_node_fs61.readFileSync)(abs);
|
|
27755
28379
|
if (isImageRelativePath(relativePath)) {
|
|
27756
28380
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
27757
28381
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -27794,9 +28418,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
27794
28418
|
}
|
|
27795
28419
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
27796
28420
|
assertSafeRelativePath(relativePath);
|
|
27797
|
-
const abs = (0,
|
|
27798
|
-
(0,
|
|
27799
|
-
(0,
|
|
28421
|
+
const abs = (0, import_node_path60.join)(worktreePath, relativePath);
|
|
28422
|
+
(0, import_node_fs61.mkdirSync)((0, import_node_path60.dirname)(abs), { recursive: true });
|
|
28423
|
+
(0, import_node_fs61.writeFileSync)(abs, content, "utf8");
|
|
27800
28424
|
return { path: relativePath };
|
|
27801
28425
|
}
|
|
27802
28426
|
async function getWorktreeDirtyStat(worktreePath) {
|
|
@@ -27836,12 +28460,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
27836
28460
|
truncated: full.files.length > maxFiles
|
|
27837
28461
|
};
|
|
27838
28462
|
}
|
|
27839
|
-
var
|
|
28463
|
+
var import_node_fs61, import_node_path60, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
|
|
27840
28464
|
var init_diff = __esm({
|
|
27841
28465
|
"src/diff/diff.ts"() {
|
|
27842
28466
|
"use strict";
|
|
27843
|
-
|
|
27844
|
-
|
|
28467
|
+
import_node_fs61 = require("fs");
|
|
28468
|
+
import_node_path60 = require("path");
|
|
27845
28469
|
init_run();
|
|
27846
28470
|
init_worktree();
|
|
27847
28471
|
mergeBaseCache = /* @__PURE__ */ new Map();
|
|
@@ -28050,6 +28674,7 @@ async function confirmLand(thread, opts) {
|
|
|
28050
28674
|
var init_land = __esm({
|
|
28051
28675
|
"src/land/land.ts"() {
|
|
28052
28676
|
"use strict";
|
|
28677
|
+
init_pr_write();
|
|
28053
28678
|
init_worktree();
|
|
28054
28679
|
init_diff();
|
|
28055
28680
|
init_pr_metadata();
|
|
@@ -28063,16 +28688,16 @@ function readWorktreeFileTail(worktreePath, relativePath, maxBytes = WORKTREE_TA
|
|
|
28063
28688
|
if (!relativePath || relativePath.includes("..") || relativePath.startsWith("/")) {
|
|
28064
28689
|
throw new Error("Invalid path");
|
|
28065
28690
|
}
|
|
28066
|
-
const abs = (0,
|
|
28067
|
-
const fd = (0,
|
|
28691
|
+
const abs = (0, import_node_path61.join)(worktreePath, relativePath);
|
|
28692
|
+
const fd = (0, import_node_fs62.openSync)(abs, "r");
|
|
28068
28693
|
try {
|
|
28069
|
-
const st = (0,
|
|
28694
|
+
const st = (0, import_node_fs62.fstatSync)(fd);
|
|
28070
28695
|
if (!st.isFile()) throw new Error(`Not a file: ${relativePath}`);
|
|
28071
28696
|
const size = st.size;
|
|
28072
28697
|
const start = Math.max(0, size - maxBytes);
|
|
28073
28698
|
const length = size - start;
|
|
28074
28699
|
const buf = Buffer.alloc(length);
|
|
28075
|
-
if (length > 0) (0,
|
|
28700
|
+
if (length > 0) (0, import_node_fs62.readSync)(fd, buf, 0, length, start);
|
|
28076
28701
|
if (buf.subarray(0, Math.min(buf.length, 8e3)).includes(0)) {
|
|
28077
28702
|
return {
|
|
28078
28703
|
path: relativePath,
|
|
@@ -28090,15 +28715,15 @@ function readWorktreeFileTail(worktreePath, relativePath, maxBytes = WORKTREE_TA
|
|
|
28090
28715
|
}
|
|
28091
28716
|
return { path: relativePath, content, truncated, binary: false, encoding: "utf8" };
|
|
28092
28717
|
} finally {
|
|
28093
|
-
(0,
|
|
28718
|
+
(0, import_node_fs62.closeSync)(fd);
|
|
28094
28719
|
}
|
|
28095
28720
|
}
|
|
28096
|
-
var
|
|
28721
|
+
var import_node_fs62, import_node_path61, WORKTREE_TAIL_BYTES;
|
|
28097
28722
|
var init_read_worktree_tail = __esm({
|
|
28098
28723
|
"src/diff/read-worktree-tail.ts"() {
|
|
28099
28724
|
"use strict";
|
|
28100
|
-
|
|
28101
|
-
|
|
28725
|
+
import_node_fs62 = require("fs");
|
|
28726
|
+
import_node_path61 = require("path");
|
|
28102
28727
|
WORKTREE_TAIL_BYTES = 2e5;
|
|
28103
28728
|
}
|
|
28104
28729
|
});
|
|
@@ -28247,7 +28872,7 @@ function parseFrontmatter(content) {
|
|
|
28247
28872
|
}
|
|
28248
28873
|
function readSkill(skillMd, source) {
|
|
28249
28874
|
try {
|
|
28250
|
-
const content = (0,
|
|
28875
|
+
const content = (0, import_node_fs63.readFileSync)(skillMd, "utf8");
|
|
28251
28876
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
28252
28877
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
28253
28878
|
const name = fmName || dirName;
|
|
@@ -28266,19 +28891,19 @@ function readSkill(skillMd, source) {
|
|
|
28266
28891
|
}
|
|
28267
28892
|
}
|
|
28268
28893
|
function scanSkillsDir(dir, source, out) {
|
|
28269
|
-
if (!(0,
|
|
28894
|
+
if (!(0, import_node_fs63.existsSync)(dir)) return;
|
|
28270
28895
|
let entries;
|
|
28271
28896
|
try {
|
|
28272
|
-
entries = (0,
|
|
28897
|
+
entries = (0, import_node_fs63.readdirSync)(dir);
|
|
28273
28898
|
} catch {
|
|
28274
28899
|
return;
|
|
28275
28900
|
}
|
|
28276
28901
|
for (const entry of entries) {
|
|
28277
28902
|
if (entry.startsWith(".")) continue;
|
|
28278
|
-
const skillMd = (0,
|
|
28279
|
-
if (!(0,
|
|
28903
|
+
const skillMd = (0, import_node_path62.join)(dir, entry, "SKILL.md");
|
|
28904
|
+
if (!(0, import_node_fs63.existsSync)(skillMd)) continue;
|
|
28280
28905
|
try {
|
|
28281
|
-
if (!(0,
|
|
28906
|
+
if (!(0, import_node_fs63.statSync)(skillMd).isFile()) continue;
|
|
28282
28907
|
} catch {
|
|
28283
28908
|
continue;
|
|
28284
28909
|
}
|
|
@@ -28287,24 +28912,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
28287
28912
|
}
|
|
28288
28913
|
}
|
|
28289
28914
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
28290
|
-
if (!(0,
|
|
28915
|
+
if (!(0, import_node_fs63.existsSync)(pluginsRoot)) return;
|
|
28291
28916
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
28292
28917
|
if (depth > 7) return;
|
|
28293
28918
|
let entries;
|
|
28294
28919
|
try {
|
|
28295
|
-
entries = (0,
|
|
28920
|
+
entries = (0, import_node_fs63.readdirSync)(dir);
|
|
28296
28921
|
} catch {
|
|
28297
28922
|
return;
|
|
28298
28923
|
}
|
|
28299
28924
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
28300
|
-
const skill = readSkill((0,
|
|
28925
|
+
const skill = readSkill((0, import_node_path62.join)(dir, "SKILL.md"), "cli");
|
|
28301
28926
|
if (skill) out.push(skill);
|
|
28302
28927
|
}
|
|
28303
28928
|
for (const entry of entries) {
|
|
28304
28929
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
28305
|
-
const full = (0,
|
|
28930
|
+
const full = (0, import_node_path62.join)(dir, entry);
|
|
28306
28931
|
try {
|
|
28307
|
-
if (!(0,
|
|
28932
|
+
if (!(0, import_node_fs63.statSync)(full).isDirectory()) continue;
|
|
28308
28933
|
} catch {
|
|
28309
28934
|
continue;
|
|
28310
28935
|
}
|
|
@@ -28322,17 +28947,17 @@ function discoverSkills(worktreePath) {
|
|
|
28322
28947
|
const home = (0, import_node_os20.homedir)();
|
|
28323
28948
|
const collected = [];
|
|
28324
28949
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
28325
|
-
scanSkillsDir((0,
|
|
28950
|
+
scanSkillsDir((0, import_node_path62.join)(worktreePath, rel), "workspace", collected);
|
|
28326
28951
|
}
|
|
28327
28952
|
for (const abs of [
|
|
28328
|
-
(0,
|
|
28329
|
-
(0,
|
|
28330
|
-
(0,
|
|
28331
|
-
(0,
|
|
28953
|
+
(0, import_node_path62.join)(home, ".claude/skills"),
|
|
28954
|
+
(0, import_node_path62.join)(home, ".cursor/skills"),
|
|
28955
|
+
(0, import_node_path62.join)(home, ".sideboard/skills"),
|
|
28956
|
+
(0, import_node_path62.join)(home, ".brightsy/skills")
|
|
28332
28957
|
]) {
|
|
28333
28958
|
scanSkillsDir(abs, "user", collected);
|
|
28334
28959
|
}
|
|
28335
|
-
scanClaudePluginSkills((0,
|
|
28960
|
+
scanClaudePluginSkills((0, import_node_path62.join)(home, ".claude/plugins"), collected);
|
|
28336
28961
|
collected.push(...bundledSkills());
|
|
28337
28962
|
const rank = {
|
|
28338
28963
|
workspace: 0,
|
|
@@ -28358,7 +28983,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
28358
28983
|
\u2026(truncated)` : body;
|
|
28359
28984
|
}
|
|
28360
28985
|
}
|
|
28361
|
-
const raw = (0,
|
|
28986
|
+
const raw = (0, import_node_fs63.readFileSync)(skillPath, "utf8");
|
|
28362
28987
|
if (raw.startsWith("---")) {
|
|
28363
28988
|
const end = raw.indexOf("\n---", 3);
|
|
28364
28989
|
if (end >= 0) {
|
|
@@ -28372,13 +28997,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
28372
28997
|
|
|
28373
28998
|
\u2026(truncated)` : raw;
|
|
28374
28999
|
}
|
|
28375
|
-
var
|
|
29000
|
+
var import_node_fs63, import_node_os20, import_node_path62, BUNDLED_SKILL_PREFIX;
|
|
28376
29001
|
var init_discover = __esm({
|
|
28377
29002
|
"src/skills/discover.ts"() {
|
|
28378
29003
|
"use strict";
|
|
28379
|
-
|
|
29004
|
+
import_node_fs63 = require("fs");
|
|
28380
29005
|
import_node_os20 = require("os");
|
|
28381
|
-
|
|
29006
|
+
import_node_path62 = require("path");
|
|
28382
29007
|
init_long_running();
|
|
28383
29008
|
BUNDLED_SKILL_PREFIX = "bundled:";
|
|
28384
29009
|
}
|
|
@@ -28589,7 +29214,7 @@ function promptForJoinedSteer(input) {
|
|
|
28589
29214
|
rewriteTrailingUserPrompt(input.threadId, input.promptText, input.latestPrompt);
|
|
28590
29215
|
const { agentPrompt: expandedLatest } = expandComposerPrompt(
|
|
28591
29216
|
input.worktreePath,
|
|
28592
|
-
expandCanonicalGitRequest(input.latestPrompt),
|
|
29217
|
+
expandCanonicalGitRequest(input.latestPrompt, { forge: input.gitForge }),
|
|
28593
29218
|
{ attachments: input.attachments }
|
|
28594
29219
|
);
|
|
28595
29220
|
return input.expandedPrompt && input.agentPrompt.endsWith(input.expandedPrompt) ? input.agentPrompt.slice(0, -input.expandedPrompt.length) + expandedLatest : `${input.agentPrompt}
|
|
@@ -28697,6 +29322,33 @@ var init_enqueue_thread_send = __esm({
|
|
|
28697
29322
|
}
|
|
28698
29323
|
});
|
|
28699
29324
|
|
|
29325
|
+
// src/agents/forge-git-directives.ts
|
|
29326
|
+
function formatCursorGitDirective(slug) {
|
|
29327
|
+
const repo = slug?.trim() || "<origin-owner/name>";
|
|
29328
|
+
return [
|
|
29329
|
+
`Git host (Settings \u2192 Git \u2192 Cursor): this checkout is on Cursor (\`origin.cursor.com\`, \`${repo}\`).`,
|
|
29330
|
+
"- Use the `origin` CLI, not `gh`. Where commands overlap, flags follow `gh` (`origin <command> --help`).",
|
|
29331
|
+
"- `origin` already authenticates from `CURSOR_AUTH_TOKEN`, then `CURSOR_API_KEY`, then the login stored in Settings \u2192 Git \u2192 Cursor. Do not read those values, set them, or run `origin auth login` from this turn.",
|
|
29332
|
+
"- Push with `git push -u origin HEAD`. If git asks for credentials, tell the user to open Settings \u2192 Git \u2192 Cursor and choose Configure git (`origin auth setup-git`). Do not wait for a Keychain dialog.",
|
|
29333
|
+
"- Origin has no issue tracker. Tickets for this repo come from Linear or AbleTime via `list_issues`. Do not use `gh issue`."
|
|
29334
|
+
].join("\n");
|
|
29335
|
+
}
|
|
29336
|
+
function formatEntireGitDirective(slug) {
|
|
29337
|
+
const repo = slug?.trim() || "<origin-owner/name>";
|
|
29338
|
+
return [
|
|
29339
|
+
`Git host (Settings \u2192 Git \u2192 Entire): this checkout is on Entire (\`${repo}\`).`,
|
|
29340
|
+
"- Use the `entire` CLI, not `gh` or `origin`. Trails replace pull requests and GitHub issues.",
|
|
29341
|
+
"- `entire` uses the login from Settings \u2192 Git \u2192 Entire. Do not read tokens, set `ENTIRE_TOKEN`, or run `entire login` from this turn.",
|
|
29342
|
+
"- Push with `git push -u origin HEAD`. If git asks for credentials, tell the user to open Settings \u2192 Git \u2192 Entire and log in. Do not wait for a Keychain dialog.",
|
|
29343
|
+
"- Tickets for this repo are Trails (`entire trail list` / `entire trail show`). Do not use `gh issue`."
|
|
29344
|
+
].join("\n");
|
|
29345
|
+
}
|
|
29346
|
+
var init_forge_git_directives = __esm({
|
|
29347
|
+
"src/agents/forge-git-directives.ts"() {
|
|
29348
|
+
"use strict";
|
|
29349
|
+
}
|
|
29350
|
+
});
|
|
29351
|
+
|
|
28700
29352
|
// src/skills/detached-job-path.ts
|
|
28701
29353
|
function compiledModuleDir() {
|
|
28702
29354
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
@@ -28704,7 +29356,7 @@ function compiledModuleDir() {
|
|
|
28704
29356
|
try {
|
|
28705
29357
|
const url = import_meta8.url;
|
|
28706
29358
|
if (typeof url === "string" && url.length > 0) {
|
|
28707
|
-
return (0,
|
|
29359
|
+
return (0, import_node_path63.dirname)((0, import_node_url5.fileURLToPath)(url));
|
|
28708
29360
|
}
|
|
28709
29361
|
} catch {
|
|
28710
29362
|
}
|
|
@@ -28712,8 +29364,8 @@ function compiledModuleDir() {
|
|
|
28712
29364
|
}
|
|
28713
29365
|
function detachedJobScriptIn(dir) {
|
|
28714
29366
|
for (const name of DETACHED_JOB_FILENAMES) {
|
|
28715
|
-
const script = (0,
|
|
28716
|
-
if ((0,
|
|
29367
|
+
const script = (0, import_node_path63.join)(dir, "scripts", name);
|
|
29368
|
+
if ((0, import_node_fs64.existsSync)(script)) return script;
|
|
28717
29369
|
}
|
|
28718
29370
|
return null;
|
|
28719
29371
|
}
|
|
@@ -28730,7 +29382,7 @@ function resolveDetachedJobScript() {
|
|
|
28730
29382
|
for (let i = 0; i < 8; i++) {
|
|
28731
29383
|
const candidate = detachedJobScriptIn(dir);
|
|
28732
29384
|
if (candidate) return candidate;
|
|
28733
|
-
const parent = (0,
|
|
29385
|
+
const parent = (0, import_node_path63.dirname)(dir);
|
|
28734
29386
|
if (parent === dir) break;
|
|
28735
29387
|
dir = parent;
|
|
28736
29388
|
}
|
|
@@ -28741,12 +29393,12 @@ function formatDetachedJobInvoke(scriptPath) {
|
|
|
28741
29393
|
if (resolved) return `node ${JSON.stringify(resolved)}`;
|
|
28742
29394
|
return "node scripts/detached-job.cjs";
|
|
28743
29395
|
}
|
|
28744
|
-
var
|
|
29396
|
+
var import_node_fs64, import_node_path63, import_node_url5, import_meta8, DETACHED_JOB_FILENAMES;
|
|
28745
29397
|
var init_detached_job_path = __esm({
|
|
28746
29398
|
"src/skills/detached-job-path.ts"() {
|
|
28747
29399
|
"use strict";
|
|
28748
|
-
|
|
28749
|
-
|
|
29400
|
+
import_node_fs64 = require("fs");
|
|
29401
|
+
import_node_path63 = require("path");
|
|
28750
29402
|
import_node_url5 = require("url");
|
|
28751
29403
|
init_packaged_runtime();
|
|
28752
29404
|
import_meta8 = {};
|
|
@@ -28834,17 +29486,35 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
28834
29486
|
lines.push(
|
|
28835
29487
|
"- Always use this worktree's `origin` remote (`git remote get-url origin` from this cwd). Never push to or open PRs against `upstream` (template remotes)."
|
|
28836
29488
|
);
|
|
28837
|
-
|
|
29489
|
+
const cursorRepo = opts?.originForge === "cursor";
|
|
29490
|
+
const entireRepo = opts?.originForge === "entire";
|
|
29491
|
+
if (cursorRepo) {
|
|
29492
|
+
lines.push(formatCursorGitDirective(opts?.originSlug));
|
|
29493
|
+
} else if (entireRepo) {
|
|
29494
|
+
lines.push(formatEntireGitDirective(opts?.originSlug));
|
|
29495
|
+
} else {
|
|
29496
|
+
lines.push(formatGitAuthModeDirective(opts?.gitAuthMode ?? "auto"));
|
|
29497
|
+
}
|
|
28838
29498
|
lines.push(
|
|
28839
29499
|
"- PR title/body and commit messages state what the change does and why (inspect the diff/commits and the user request) \u2014 never the worktree nickname or placeholder branch. Concise imperative title (Conventional Commits when it fits: feat:/fix:/chore:/docs:); body = intent, key changes, test notes."
|
|
28840
29500
|
);
|
|
28841
29501
|
lines.push(
|
|
28842
|
-
"- Stay on this workspace branch. Never push to main/master or merge locally into the main checkout. Merge the PR only when this turn is a Merge PR request or the user explicitly asked \u2014 via GitHub from this worktree (`gh pr merge` / `gh stack merge`)."
|
|
29502
|
+
cursorRepo ? "- Stay on this workspace branch. Never push to main/master or merge locally into the main checkout. Merge the PR only when this turn is a Merge PR request or the user explicitly asked \u2014 via Origin from this worktree (`origin pr merge` / `origin stack merge`)." : entireRepo ? "- Stay on this workspace branch. Never push to main/master or merge locally into the main checkout. Merge only when this turn is a Merge PR request or the user explicitly asked \u2014 via Entire from this worktree (`entire trail merge`)." : "- Stay on this workspace branch. Never push to main/master or merge locally into the main checkout. Merge the PR only when this turn is a Merge PR request or the user explicitly asked \u2014 via GitHub from this worktree (`gh pr merge` / `gh stack merge`)."
|
|
28843
29503
|
);
|
|
28844
29504
|
if (thread.prUrl) {
|
|
28845
29505
|
lines.push(
|
|
28846
29506
|
`- A PR already exists (${thread.prUrl}). Update it (push + edit title/body if the purpose drifted) instead of opening a duplicate.`
|
|
28847
29507
|
);
|
|
29508
|
+
} else if (entireRepo) {
|
|
29509
|
+
lines.push(
|
|
29510
|
+
'- Prefer a Trail: `entire trail create --title "<title>" --body "<short>"`. Take the URL from `--json`. If this branch already has a trail, `entire trail update` instead of creating another. Trails have no draft state. Do not use `gh` or `origin`.'
|
|
29511
|
+
);
|
|
29512
|
+
} else if (cursorRepo) {
|
|
29513
|
+
const slug = opts?.originSlug?.trim() || "<origin-owner/name>";
|
|
29514
|
+
const resolve3 = opts?.originSlug?.trim() ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
|
|
29515
|
+
lines.push(
|
|
29516
|
+
`- Prefer a draft PR first: \`origin pr create --draft --push -R ${slug}\` (update via \`origin pr edit -R ${slug}\`). Take the URL from \`--json url\` \u2014 do not build it. Do not use \`gh\`.${resolve3} Mark ready only when asked (\`origin pr ready\`). If the body is too long, retry with a short \`--body-file\`.`
|
|
29517
|
+
);
|
|
28848
29518
|
} else {
|
|
28849
29519
|
const slug = opts?.githubSlug ?? "<origin-owner/name>";
|
|
28850
29520
|
const resolve3 = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
|
|
@@ -28984,9 +29654,9 @@ function formatPrGateDirective() {
|
|
|
28984
29654
|
}
|
|
28985
29655
|
function formatProcessGuideDirective(opts) {
|
|
28986
29656
|
const worktree = opts?.worktreePath?.trim();
|
|
28987
|
-
const hasGraphSkill = !!worktree && (0,
|
|
28988
|
-
const hasReviewSkill = !!worktree && (0,
|
|
28989
|
-
const hasInstallSkill = !!worktree && (0,
|
|
29657
|
+
const hasGraphSkill = !!worktree && (0, import_node_fs65.existsSync)((0, import_node_path64.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
|
|
29658
|
+
const hasReviewSkill = !!worktree && (0, import_node_fs65.existsSync)((0, import_node_path64.join)(worktree, ".claude/skills/review/SKILL.md"));
|
|
29659
|
+
const hasInstallSkill = !!worktree && (0, import_node_fs65.existsSync)((0, import_node_path64.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
|
|
28990
29660
|
return [
|
|
28991
29661
|
"Process guides (recurring work only):",
|
|
28992
29662
|
hasGraphSkill ? "- Migrations, ports, batch fixes, and other fan-out: follow `.claude/skills/graph-engineering/SKILL.md` (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch around it." : null,
|
|
@@ -29026,13 +29696,14 @@ function formatArtifactDirective() {
|
|
|
29026
29696
|
function formatUiReminder() {
|
|
29027
29697
|
return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). Chat links: `[name](sideboard://artifact/<id-or-title>)` opens that pane; `[name](sideboard://file/path#L12-L40)` opens a file. ask_user only for a real multiple-choice (not hellos, \u201Cwhat next?\u201D, or after a review) \u2014 reply in chat. ask_user wakes the parent orchestrator; notify_orchestrator if blocked without a picker. Do not say artifacts/CMS UI are unavailable. Dev / preview: run_dev_script (same as the Dev button; pass name \u2014 several scripts can run at once) returns {url, port, preview} (SIDEBOARD_PORT \u2014 never guess :3000). preview=url \u2192 open url; preview=window \u2192 Electron window is the app, url is renderer/HMR only. list_run_scripts active[].url if already running; get_run_log for that script\u2019s Run-tab terminal; stop_dev_script to stop one.";
|
|
29028
29698
|
}
|
|
29029
|
-
var
|
|
29699
|
+
var import_node_fs65, import_node_path64, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
|
|
29030
29700
|
var init_instructions = __esm({
|
|
29031
29701
|
"src/agents/instructions.ts"() {
|
|
29032
29702
|
"use strict";
|
|
29033
|
-
|
|
29034
|
-
|
|
29703
|
+
import_node_fs65 = require("fs");
|
|
29704
|
+
import_node_path64 = require("path");
|
|
29035
29705
|
init_git_auth_mode();
|
|
29706
|
+
init_forge_git_directives();
|
|
29036
29707
|
init_branch_prefix();
|
|
29037
29708
|
init_worktree_labels();
|
|
29038
29709
|
init_detached_job_path();
|
|
@@ -29524,6 +30195,7 @@ function compactIssueRow(issue, opts) {
|
|
|
29524
30195
|
function formatMcpIssueList(input) {
|
|
29525
30196
|
const truncated = input.truncated || Boolean(input.commentsTruncated);
|
|
29526
30197
|
const comments = input.comments ?? [];
|
|
30198
|
+
const pageHint = input.unavailableReason ? input.unavailableReason : truncated ? input.since ? "More issues or comments match. Pass a higher limit (max 250) or a tighter query." : "More issues match. Pass a higher limit (max 250) or a tighter query." : void 0;
|
|
29527
30199
|
return {
|
|
29528
30200
|
...input.source ? { source: input.source } : {},
|
|
29529
30201
|
...input.viewer ? { viewer: input.viewer } : {},
|
|
@@ -29531,9 +30203,8 @@ function formatMcpIssueList(input) {
|
|
|
29531
30203
|
returned: input.issues.length,
|
|
29532
30204
|
truncated,
|
|
29533
30205
|
...input.since ? { since: input.since } : {},
|
|
29534
|
-
...
|
|
29535
|
-
|
|
29536
|
-
} : {},
|
|
30206
|
+
...input.unavailableReason ? { unavailableReason: input.unavailableReason } : {},
|
|
30207
|
+
...pageHint ? { hint: pageHint } : {},
|
|
29537
30208
|
issues: input.issues.map((issue) => compactIssueRow(issue, { since: input.since })),
|
|
29538
30209
|
...input.since || comments.length > 0 ? { comments } : {}
|
|
29539
30210
|
};
|
|
@@ -29550,7 +30221,8 @@ function formatListedIssuesForMcp(result, page) {
|
|
|
29550
30221
|
truncated: windowed.truncated,
|
|
29551
30222
|
since: result.since,
|
|
29552
30223
|
comments: commentWindow.items,
|
|
29553
|
-
commentsTruncated: commentWindow.truncated
|
|
30224
|
+
commentsTruncated: commentWindow.truncated,
|
|
30225
|
+
unavailableReason: result.unavailableReason
|
|
29554
30226
|
});
|
|
29555
30227
|
}
|
|
29556
30228
|
function mcpJson(payload, isError = false) {
|
|
@@ -29915,40 +30587,40 @@ __export(plan_file_exports, {
|
|
|
29915
30587
|
writePlanFile: () => writePlanFile
|
|
29916
30588
|
});
|
|
29917
30589
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
29918
|
-
const gitignoreAbs = (0,
|
|
29919
|
-
if ((0,
|
|
29920
|
-
(0,
|
|
29921
|
-
(0,
|
|
30590
|
+
const gitignoreAbs = (0, import_node_path65.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
30591
|
+
if ((0, import_node_fs66.existsSync)(gitignoreAbs)) return;
|
|
30592
|
+
(0, import_node_fs66.mkdirSync)((0, import_node_path65.dirname)(gitignoreAbs), { recursive: true });
|
|
30593
|
+
(0, import_node_fs66.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
29922
30594
|
}
|
|
29923
30595
|
function planFileAbs(worktreePath) {
|
|
29924
|
-
return (0,
|
|
30596
|
+
return (0, import_node_path65.join)(worktreePath, PLAN_FILE_REL);
|
|
29925
30597
|
}
|
|
29926
30598
|
function readTextIfPresent2(abs) {
|
|
29927
|
-
if (!(0,
|
|
30599
|
+
if (!(0, import_node_fs66.existsSync)(abs)) return null;
|
|
29928
30600
|
try {
|
|
29929
|
-
const content = (0,
|
|
30601
|
+
const content = (0, import_node_fs66.readFileSync)(abs, "utf8");
|
|
29930
30602
|
return content.trim() ? content : null;
|
|
29931
30603
|
} catch {
|
|
29932
30604
|
return null;
|
|
29933
30605
|
}
|
|
29934
30606
|
}
|
|
29935
30607
|
function readPlanFile(worktreePath) {
|
|
29936
|
-
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0,
|
|
30608
|
+
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path65.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path65.join)(worktreePath, LEGACY_PLAN_FILE_REL));
|
|
29937
30609
|
}
|
|
29938
30610
|
function writePlanFile(worktreePath, content) {
|
|
29939
30611
|
ensureAttachmentsGitignore(worktreePath);
|
|
29940
30612
|
const abs = planFileAbs(worktreePath);
|
|
29941
|
-
(0,
|
|
30613
|
+
(0, import_node_fs66.mkdirSync)((0, import_node_path65.dirname)(abs), { recursive: true });
|
|
29942
30614
|
const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
|
|
29943
|
-
(0,
|
|
30615
|
+
(0, import_node_fs66.writeFileSync)(abs, body, "utf8");
|
|
29944
30616
|
return PLAN_FILE_REL;
|
|
29945
30617
|
}
|
|
29946
|
-
var
|
|
30618
|
+
var import_node_fs66, import_node_path65;
|
|
29947
30619
|
var init_plan_file = __esm({
|
|
29948
30620
|
"src/plan/plan-file.ts"() {
|
|
29949
30621
|
"use strict";
|
|
29950
|
-
|
|
29951
|
-
|
|
30622
|
+
import_node_fs66 = require("fs");
|
|
30623
|
+
import_node_path65 = require("path");
|
|
29952
30624
|
init_workspace_scratch();
|
|
29953
30625
|
init_plan_present();
|
|
29954
30626
|
init_plan_present();
|
|
@@ -29999,9 +30671,9 @@ function recoverFinishedCursorRun(opts) {
|
|
|
29999
30671
|
return best;
|
|
30000
30672
|
}
|
|
30001
30673
|
function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
30002
|
-
if (!(0,
|
|
30674
|
+
if (!(0, import_node_fs67.existsSync)(runsPath)) return null;
|
|
30003
30675
|
try {
|
|
30004
|
-
const lines = (0,
|
|
30676
|
+
const lines = (0, import_node_fs67.readFileSync)(runsPath, "utf8").split("\n");
|
|
30005
30677
|
let best = null;
|
|
30006
30678
|
for (const line of lines) {
|
|
30007
30679
|
const trimmed = line.trim();
|
|
@@ -30027,11 +30699,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
|
30027
30699
|
return null;
|
|
30028
30700
|
}
|
|
30029
30701
|
}
|
|
30030
|
-
var
|
|
30702
|
+
var import_node_fs67;
|
|
30031
30703
|
var init_cursor_recover = __esm({
|
|
30032
30704
|
"src/agents/cursor-recover.ts"() {
|
|
30033
30705
|
"use strict";
|
|
30034
|
-
|
|
30706
|
+
import_node_fs67 = require("fs");
|
|
30035
30707
|
init_cursor_store();
|
|
30036
30708
|
}
|
|
30037
30709
|
});
|
|
@@ -30152,7 +30824,7 @@ async function startOrchestration(opts) {
|
|
|
30152
30824
|
}
|
|
30153
30825
|
return ready;
|
|
30154
30826
|
}
|
|
30155
|
-
var import_node_events, import_node_crypto19,
|
|
30827
|
+
var import_node_events, import_node_crypto19, import_node_fs68, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton2;
|
|
30156
30828
|
var init_orchestrator = __esm({
|
|
30157
30829
|
"src/orchestrator/orchestrator.ts"() {
|
|
30158
30830
|
"use strict";
|
|
@@ -30161,7 +30833,7 @@ var init_orchestrator = __esm({
|
|
|
30161
30833
|
init_task_state();
|
|
30162
30834
|
init_wait_for_turn();
|
|
30163
30835
|
import_node_crypto19 = require("crypto");
|
|
30164
|
-
|
|
30836
|
+
import_node_fs68 = require("fs");
|
|
30165
30837
|
init_error_detail();
|
|
30166
30838
|
init_run();
|
|
30167
30839
|
init_stale_lock();
|
|
@@ -30360,7 +31032,7 @@ var init_orchestrator = __esm({
|
|
|
30360
31032
|
this.lightReconcileAt.set(repoPath, Date.now());
|
|
30361
31033
|
for (const thread of listThreads()) {
|
|
30362
31034
|
if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
|
|
30363
|
-
if (!(0,
|
|
31035
|
+
if (!(0, import_node_fs68.existsSync)(thread.worktreePath)) {
|
|
30364
31036
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
30365
31037
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
30366
31038
|
}
|
|
@@ -30389,7 +31061,7 @@ var init_orchestrator = __esm({
|
|
|
30389
31061
|
}
|
|
30390
31062
|
continue;
|
|
30391
31063
|
}
|
|
30392
|
-
if (!(0,
|
|
31064
|
+
if (!(0, import_node_fs68.existsSync)(thread.worktreePath)) {
|
|
30393
31065
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
30394
31066
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
30395
31067
|
continue;
|
|
@@ -31113,7 +31785,8 @@ var init_orchestrator = __esm({
|
|
|
31113
31785
|
return;
|
|
31114
31786
|
}
|
|
31115
31787
|
thread = this.requireThread(threadId);
|
|
31116
|
-
const
|
|
31788
|
+
const turnOrigin = thread.worktreePath?.trim() ? await resolveOriginRemote(thread.worktreePath).catch(() => null) : null;
|
|
31789
|
+
const gitPrompt = expandCanonicalGitRequest(promptText, { forge: turnOrigin?.forge });
|
|
31117
31790
|
const { agentPrompt: expandedPrompt } = expandComposerPrompt(
|
|
31118
31791
|
thread.worktreePath,
|
|
31119
31792
|
gitPrompt,
|
|
@@ -31200,11 +31873,9 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
31200
31873
|
const { autoRenameBranchEnabled: autoRenameBranchEnabled2, getGithubGitAuthMode: getGithubGitAuthMode2, gitBranchPrefixSetting: gitBranchPrefixSetting2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
|
|
31201
31874
|
const gitAuthMode = getGithubGitAuthMode2();
|
|
31202
31875
|
const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
|
|
31203
|
-
githubSlug: await withTimeout(
|
|
31204
|
-
|
|
31205
|
-
|
|
31206
|
-
"resolveGithubRepoSlug"
|
|
31207
|
-
).catch(() => null),
|
|
31876
|
+
githubSlug: turnOrigin?.forge === "github" ? turnOrigin.slug : await withTimeout(resolveGithubRepoSlug(fresh.worktreePath), 8e3, "resolveGithubRepoSlug").catch(() => null),
|
|
31877
|
+
originForge: turnOrigin?.forge ?? null,
|
|
31878
|
+
originSlug: turnOrigin?.slug ?? null,
|
|
31208
31879
|
gitAuthMode,
|
|
31209
31880
|
activeRuns: annotateDevAccessRuns(
|
|
31210
31881
|
mergeWorktreeActiveRuns(
|
|
@@ -31297,7 +31968,8 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
31297
31968
|
agentPrompt,
|
|
31298
31969
|
expandedPrompt,
|
|
31299
31970
|
worktreePath: fresh.worktreePath,
|
|
31300
|
-
attachments: autoContinue ? [] : sentAttachments ?? []
|
|
31971
|
+
attachments: autoContinue ? [] : sentAttachments ?? [],
|
|
31972
|
+
gitForge: turnOrigin?.forge
|
|
31301
31973
|
});
|
|
31302
31974
|
const handle = await spawnAgentTurn(
|
|
31303
31975
|
fresh,
|
|
@@ -32871,7 +33543,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
32871
33543
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
32872
33544
|
return restored2;
|
|
32873
33545
|
}
|
|
32874
|
-
if (!(0,
|
|
33546
|
+
if (!(0, import_node_fs68.existsSync)(thread.worktreePath)) {
|
|
32875
33547
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
32876
33548
|
throw new Error(
|
|
32877
33549
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
@@ -33166,12 +33838,14 @@ __export(index_exports, {
|
|
|
33166
33838
|
CONTEXT_REVIEW_PATH: () => CONTEXT_REVIEW_PATH,
|
|
33167
33839
|
CONVENTION_SETUP_RELPATHS: () => CONVENTION_SETUP_RELPATHS,
|
|
33168
33840
|
COORDINATOR_TOOL_PLAYBOOK: () => COORDINATOR_TOOL_PLAYBOOK,
|
|
33841
|
+
CURSOR_ISSUES_UNAVAILABLE: () => CURSOR_ISSUES_UNAVAILABLE,
|
|
33169
33842
|
CURSOR_SDK_INSTALL_HINT: () => CURSOR_SDK_INSTALL_HINT,
|
|
33170
33843
|
DEFAULT_ABLETIME_HOST: () => DEFAULT_ABLETIME_HOST,
|
|
33171
33844
|
DEFAULT_RUN_LOG_TAIL_CHARS: () => DEFAULT_RUN_LOG_TAIL_CHARS,
|
|
33172
33845
|
DEFAULT_WORKTREE_SORT: () => DEFAULT_WORKTREE_SORT,
|
|
33173
33846
|
DETACHED_JOBS_DIR: () => DETACHED_JOBS_DIR,
|
|
33174
33847
|
EMPTY_MANAGED_ACCOUNTS: () => EMPTY_MANAGED_ACCOUNTS,
|
|
33848
|
+
ENTIRE_ISSUES_ARE_TRAILS: () => ENTIRE_ISSUES_ARE_TRAILS,
|
|
33175
33849
|
FAMOUS_SOCCER_TEAMS: () => FAMOUS_SOCCER_TEAMS,
|
|
33176
33850
|
FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
|
|
33177
33851
|
GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
|
|
@@ -33439,6 +34113,7 @@ __export(index_exports, {
|
|
|
33439
34113
|
createThreadWorktree: () => createThreadWorktree,
|
|
33440
34114
|
currentBranch: () => currentBranch,
|
|
33441
34115
|
cursorAdapter: () => cursorAdapter,
|
|
34116
|
+
cursorIssuesUnavailableReason: () => cursorIssuesUnavailableReason,
|
|
33442
34117
|
cursorSdkMessageToEvents: () => cursorSdkMessageToEvents,
|
|
33443
34118
|
decodeBrightsyTarget: () => decodeBrightsyTarget,
|
|
33444
34119
|
defaultScheduleName: () => defaultScheduleName,
|
|
@@ -33488,6 +34163,7 @@ __export(index_exports, {
|
|
|
33488
34163
|
ensureSlackCoordinator: () => ensureSlackCoordinator,
|
|
33489
34164
|
ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
|
|
33490
34165
|
ensureWorkspace: () => ensureWorkspace,
|
|
34166
|
+
entireUsesTrails: () => entireUsesTrails,
|
|
33491
34167
|
estimateMessageChars: () => estimateMessageChars,
|
|
33492
34168
|
estimateOccupancyTokens: () => estimateOccupancyTokens,
|
|
33493
34169
|
estimateThreadChars: () => estimateThreadChars,
|
|
@@ -33538,8 +34214,10 @@ __export(index_exports, {
|
|
|
33538
34214
|
formatClaudeUsageTooltip: () => formatClaudeUsageTooltip,
|
|
33539
34215
|
formatCloudTurnReply: () => formatCloudTurnReply,
|
|
33540
34216
|
formatConnectedOrchestratorReminder: () => formatConnectedOrchestratorReminder,
|
|
34217
|
+
formatCursorGitDirective: () => formatCursorGitDirective,
|
|
33541
34218
|
formatDetachedJobInvoke: () => formatDetachedJobInvoke,
|
|
33542
34219
|
formatDevAccessHint: () => formatDevAccessHint,
|
|
34220
|
+
formatEntireGitDirective: () => formatEntireGitDirective,
|
|
33543
34221
|
formatFetchError: () => formatFetchError,
|
|
33544
34222
|
formatGhLandError: () => formatGhLandError,
|
|
33545
34223
|
formatGitAuthModeDirective: () => formatGitAuthModeDirective,
|
|
@@ -33596,6 +34274,7 @@ __export(index_exports, {
|
|
|
33596
34274
|
getBrightsySession: () => getBrightsySession,
|
|
33597
34275
|
getCaffeinateHold: () => getCaffeinateHold,
|
|
33598
34276
|
getClaudePlanUsage: () => getClaudePlanUsage,
|
|
34277
|
+
getCursorGitStatus: () => getCursorGitStatus,
|
|
33599
34278
|
getDefaultAgent: () => getDefaultAgent,
|
|
33600
34279
|
getDefaultAutonomy: () => getDefaultAutonomy,
|
|
33601
34280
|
getDefaultEffort: () => getDefaultEffort,
|
|
@@ -33604,6 +34283,7 @@ __export(index_exports, {
|
|
|
33604
34283
|
getDefaultRunScript: () => getDefaultRunScript,
|
|
33605
34284
|
getDiff: () => getDiff,
|
|
33606
34285
|
getDiffSummary: () => getDiffSummary,
|
|
34286
|
+
getEntireGitStatus: () => getEntireGitStatus,
|
|
33607
34287
|
getGitHubIssue: () => getGitHubIssue,
|
|
33608
34288
|
getGitHubStatus: () => getGitHubStatus,
|
|
33609
34289
|
getGithubGitAuthMode: () => getGithubGitAuthMode,
|
|
@@ -33821,6 +34501,8 @@ __export(index_exports, {
|
|
|
33821
34501
|
localhostPreviewUrl: () => localhostPreviewUrl,
|
|
33822
34502
|
locksDir: () => locksDir,
|
|
33823
34503
|
loginAgent: () => loginAgent,
|
|
34504
|
+
loginCursorGit: () => loginCursorGit,
|
|
34505
|
+
loginEntireGit: () => loginEntireGit,
|
|
33824
34506
|
loginEnvPrefix: () => loginEnvPrefix,
|
|
33825
34507
|
loginManagedAccount: () => loginManagedAccount,
|
|
33826
34508
|
looksLikeComposerSkillExpansion: () => looksLikeComposerSkillExpansion,
|
|
@@ -33887,6 +34569,7 @@ __export(index_exports, {
|
|
|
33887
34569
|
orchestrationQuotaOnLimit: () => orchestrationQuotaOnLimit,
|
|
33888
34570
|
orchestrationTitleNeedsSoccerNickname: () => orchestrationTitleNeedsSoccerNickname,
|
|
33889
34571
|
orchestratorSessionPoisonedByBuiltins: () => orchestratorSessionPoisonedByBuiltins,
|
|
34572
|
+
originCli: () => originCli,
|
|
33890
34573
|
originFetchBranch: () => originFetchBranch,
|
|
33891
34574
|
originGhRepoEnv: () => originGhRepoEnv,
|
|
33892
34575
|
outboundReplyFromTurn: () => outboundReplyFromTurn,
|
|
@@ -33897,11 +34580,13 @@ __export(index_exports, {
|
|
|
33897
34580
|
parseCursorRunnerLine: () => parseCursorRunnerLine,
|
|
33898
34581
|
parseDevPreview: () => parseDevPreview,
|
|
33899
34582
|
parseDurationMs: () => parseDurationMs,
|
|
34583
|
+
parseEntireAuthContexts: () => parseEntireAuthContexts,
|
|
33900
34584
|
parseForceStopMessage: () => parseForceStopMessage,
|
|
33901
34585
|
parseGhStackViewJson: () => parseGhStackViewJson,
|
|
33902
34586
|
parseGitHubIssueNumber: () => parseGitHubIssueNumber,
|
|
33903
34587
|
parseGithubSlugFromRemoteUrl: () => parseGithubSlugFromRemoteUrl,
|
|
33904
34588
|
parseMcpList: () => parseMcpList,
|
|
34589
|
+
parseOriginAuthStatus: () => parseOriginAuthStatus,
|
|
33905
34590
|
parsePlanQuestionsInput: () => parsePlanQuestionsInput,
|
|
33906
34591
|
parsePrDetailsView: () => parsePrDetailsView,
|
|
33907
34592
|
parseSessionQuotaResetAt: () => parseSessionQuotaResetAt,
|
|
@@ -34004,9 +34689,11 @@ __export(index_exports, {
|
|
|
34004
34689
|
resolveNewThreadOptions: () => resolveNewThreadOptions,
|
|
34005
34690
|
resolveOrchChildFollowUp: () => resolveOrchChildFollowUp,
|
|
34006
34691
|
resolveOrchestratorDefaults: () => resolveOrchestratorDefaults,
|
|
34692
|
+
resolveOriginRemote: () => resolveOriginRemote,
|
|
34007
34693
|
resolvePlanMarkdown: () => resolvePlanMarkdown,
|
|
34008
34694
|
resolvePrSelector: () => resolvePrSelector,
|
|
34009
34695
|
resolvePrSelectors: () => resolvePrSelectors,
|
|
34696
|
+
resolveProjectRemoteTag: () => resolveProjectRemoteTag,
|
|
34010
34697
|
resolveProjectReviewLabel: () => resolveProjectReviewLabel,
|
|
34011
34698
|
resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
|
|
34012
34699
|
resolveRepoRoot: () => resolveRepoRoot,
|
|
@@ -34057,6 +34744,7 @@ __export(index_exports, {
|
|
|
34057
34744
|
setStatus: () => setStatus,
|
|
34058
34745
|
setVaultMasterKey: () => setVaultMasterKey,
|
|
34059
34746
|
settingsSourceLabel: () => settingsSourceLabel,
|
|
34747
|
+
setupCursorGit: () => setupCursorGit,
|
|
34060
34748
|
shiftQueuedItem: () => shiftQueuedItem,
|
|
34061
34749
|
shouldAttachPastedText: () => shouldAttachPastedText,
|
|
34062
34750
|
shouldCompactContext: () => shouldCompactContext,
|
|
@@ -35897,7 +36585,7 @@ function listPhoneSidebar(viewerLogin = phoneViewerLogin()) {
|
|
|
35897
36585
|
const badge = classifyWorktreeListBadges(group, viewerLogin, resolveProjectReviewLabel(settings, path2))[0];
|
|
35898
36586
|
const blockedBy = issueBlockedByIds(group);
|
|
35899
36587
|
return {
|
|
35900
|
-
|
|
36588
|
+
...workspaceRowLabel(group),
|
|
35901
36589
|
chats: group.map(summarize),
|
|
35902
36590
|
...tags.length > 0 ? { tags } : {},
|
|
35903
36591
|
...blockedBy.length > 0 ? { blockedBy } : {},
|
|
@@ -36343,8 +37031,8 @@ init_message_parts();
|
|
|
36343
37031
|
init_turn_live();
|
|
36344
37032
|
|
|
36345
37033
|
// src/remote/phone-media.ts
|
|
36346
|
-
var
|
|
36347
|
-
var
|
|
37034
|
+
var import_node_fs69 = require("fs");
|
|
37035
|
+
var import_node_path66 = require("path");
|
|
36348
37036
|
init_diff();
|
|
36349
37037
|
var PHONE_IMAGE_MAX_BYTES = 15e5;
|
|
36350
37038
|
var PHONE_TEXT_MAX_BYTES = 18e4;
|
|
@@ -36397,7 +37085,7 @@ function phoneImageDataUrl(worktreePath, raw) {
|
|
|
36397
37085
|
}
|
|
36398
37086
|
function phoneDirectoryListing(worktreePath, relative2) {
|
|
36399
37087
|
try {
|
|
36400
|
-
const entries = (0,
|
|
37088
|
+
const entries = (0, import_node_fs69.readdirSync)((0, import_node_path66.join)(worktreePath, relative2), { withFileTypes: true });
|
|
36401
37089
|
const dirs = new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
|
|
36402
37090
|
const names = entries.map((entry) => entry.name).filter((name) => name && !name.includes("/") && !name.includes("\0")).sort((a, b) => a.localeCompare(b));
|
|
36403
37091
|
const shown = names.slice(0, PHONE_DIR_MAX);
|
|
@@ -36423,7 +37111,7 @@ function phoneFilePreview(worktreePath, relative2, kind) {
|
|
|
36423
37111
|
}
|
|
36424
37112
|
if (relative2.toLowerCase().endsWith(".svg")) {
|
|
36425
37113
|
try {
|
|
36426
|
-
const buf = (0,
|
|
37114
|
+
const buf = (0, import_node_fs69.readFileSync)((0, import_node_path66.join)(worktreePath, relative2));
|
|
36427
37115
|
const truncated = buf.length > PHONE_TEXT_MAX_BYTES;
|
|
36428
37116
|
return {
|
|
36429
37117
|
content: buf.subarray(0, PHONE_TEXT_MAX_BYTES).toString("utf8"),
|
|
@@ -36719,9 +37407,9 @@ function githubProjectsOnIssue(raw) {
|
|
|
36719
37407
|
}
|
|
36720
37408
|
return out;
|
|
36721
37409
|
}
|
|
36722
|
-
async function readGitHubIssueProjects(number, cwd,
|
|
37410
|
+
async function readGitHubIssueProjects(number, cwd, repoArgs2) {
|
|
36723
37411
|
const result = await gh(
|
|
36724
|
-
["issue", "view", String(number), ...
|
|
37412
|
+
["issue", "view", String(number), ...repoArgs2, "--json", "projectItems"],
|
|
36725
37413
|
cwd,
|
|
36726
37414
|
{ reject: false }
|
|
36727
37415
|
);
|
|
@@ -36739,8 +37427,8 @@ async function readGitHubIssueProjects(number, cwd, repoArgs) {
|
|
|
36739
37427
|
return { projects: [] };
|
|
36740
37428
|
}
|
|
36741
37429
|
}
|
|
36742
|
-
async function listGitHubIssueProjectNames(number, cwd,
|
|
36743
|
-
const read = await readGitHubIssueProjects(number, cwd,
|
|
37430
|
+
async function listGitHubIssueProjectNames(number, cwd, repoArgs2) {
|
|
37431
|
+
const read = await readGitHubIssueProjects(number, cwd, repoArgs2);
|
|
36744
37432
|
return read.projects.map((project) => project.name).filter(Boolean);
|
|
36745
37433
|
}
|
|
36746
37434
|
function parseGitHubProjectList(stdout) {
|
|
@@ -36958,14 +37646,14 @@ async function listGitHubIssueCommentsSince(opts) {
|
|
|
36958
37646
|
}
|
|
36959
37647
|
async function getGitHubIssue(id, opts) {
|
|
36960
37648
|
const number = parseGitHubIssueNumber(id);
|
|
36961
|
-
const { cwd, repoArgs } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
37649
|
+
const { cwd, repoArgs: repoArgs2 } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
36962
37650
|
const stdout = requireGhOk(
|
|
36963
37651
|
await gh(
|
|
36964
37652
|
[
|
|
36965
37653
|
"issue",
|
|
36966
37654
|
"view",
|
|
36967
37655
|
String(number),
|
|
36968
|
-
...
|
|
37656
|
+
...repoArgs2,
|
|
36969
37657
|
"--json",
|
|
36970
37658
|
"number,title,body,url,state,labels,assignees,comments,author"
|
|
36971
37659
|
],
|
|
@@ -36984,7 +37672,7 @@ async function getGitHubIssue(id, opts) {
|
|
|
36984
37672
|
throw new Error(`GitHub issue not found: #${number}`);
|
|
36985
37673
|
}
|
|
36986
37674
|
const issue = toGitHubIssue(parsed);
|
|
36987
|
-
const projects = await readGitHubIssueProjects(number, cwd,
|
|
37675
|
+
const projects = await readGitHubIssueProjects(number, cwd, repoArgs2);
|
|
36988
37676
|
issue.projects = projects.projects;
|
|
36989
37677
|
if (projects.error) issue.projectsError = projects.error;
|
|
36990
37678
|
return issue;
|
|
@@ -36993,10 +37681,10 @@ async function commentGitHubIssue(input, opts) {
|
|
|
36993
37681
|
const number = parseGitHubIssueNumber(input.id);
|
|
36994
37682
|
const body = input.body.trim();
|
|
36995
37683
|
if (!body) throw new Error("GitHub comment body is required");
|
|
36996
|
-
const { cwd, repoArgs } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
37684
|
+
const { cwd, repoArgs: repoArgs2 } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
36997
37685
|
const stdout = requireGhOk(
|
|
36998
37686
|
await gh(
|
|
36999
|
-
["issue", "comment", String(number), ...
|
|
37687
|
+
["issue", "comment", String(number), ...repoArgs2, "--body", body],
|
|
37000
37688
|
cwd,
|
|
37001
37689
|
{ reject: false }
|
|
37002
37690
|
),
|
|
@@ -37038,21 +37726,21 @@ async function updateGitHubIssue(input, opts) {
|
|
|
37038
37726
|
"github_update_issue needs at least one of title, body, state, labels, project, parent, relations, removeRelations"
|
|
37039
37727
|
);
|
|
37040
37728
|
}
|
|
37041
|
-
const { cwd, repoArgs } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
37729
|
+
const { cwd, repoArgs: repoArgs2 } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
37042
37730
|
if (state === "closed" || state === "close") {
|
|
37043
37731
|
requireGhOk(
|
|
37044
|
-
await gh(["issue", "close", String(number), ...
|
|
37732
|
+
await gh(["issue", "close", String(number), ...repoArgs2], cwd, { reject: false }),
|
|
37045
37733
|
`GitHub close #${number}`
|
|
37046
37734
|
);
|
|
37047
37735
|
} else if (state === "open" || state === "reopen") {
|
|
37048
37736
|
requireGhOk(
|
|
37049
|
-
await gh(["issue", "reopen", String(number), ...
|
|
37737
|
+
await gh(["issue", "reopen", String(number), ...repoArgs2], cwd, { reject: false }),
|
|
37050
37738
|
`GitHub reopen #${number}`
|
|
37051
37739
|
);
|
|
37052
37740
|
} else if (state) {
|
|
37053
37741
|
throw new Error(`GitHub issue state must be open or closed (got ${input.state})`);
|
|
37054
37742
|
}
|
|
37055
|
-
const args = ["issue", "edit", String(number), ...
|
|
37743
|
+
const args = ["issue", "edit", String(number), ...repoArgs2];
|
|
37056
37744
|
if (title) args.push("--title", title);
|
|
37057
37745
|
if (body !== void 0) args.push("--body", body);
|
|
37058
37746
|
if (input.labels !== void 0) {
|
|
@@ -37064,7 +37752,7 @@ async function updateGitHubIssue(input, opts) {
|
|
|
37064
37752
|
if (remove.length) args.push("--remove-label", remove.join(","));
|
|
37065
37753
|
}
|
|
37066
37754
|
if (input.project !== void 0) {
|
|
37067
|
-
const current = await listGitHubIssueProjectNames(number, cwd,
|
|
37755
|
+
const current = await listGitHubIssueProjectNames(number, cwd, repoArgs2);
|
|
37068
37756
|
if (isGitHubNoneToken(input.project)) {
|
|
37069
37757
|
for (const name of current) args.push("--remove-project", name);
|
|
37070
37758
|
} else {
|
|
@@ -37090,7 +37778,7 @@ async function updateGitHubIssue(input, opts) {
|
|
|
37090
37778
|
for (const rel of addRelations ?? []) {
|
|
37091
37779
|
args.push(githubRelationEditFlag(rel.type, false), String(parseGitHubIssueNumber(rel.issue)));
|
|
37092
37780
|
}
|
|
37093
|
-
const editChanged = args.length > 3 +
|
|
37781
|
+
const editChanged = args.length > 3 + repoArgs2.length;
|
|
37094
37782
|
if (editChanged) {
|
|
37095
37783
|
requireGhOk(await gh(args, cwd, { reject: false }), `GitHub edit #${number}`);
|
|
37096
37784
|
}
|
|
@@ -37105,8 +37793,8 @@ async function createGitHubIssue(input, opts) {
|
|
|
37105
37793
|
parentNumber ? `Spin-off of #${parentNumber}.` : null,
|
|
37106
37794
|
input.body?.trim() || null
|
|
37107
37795
|
].filter(Boolean);
|
|
37108
|
-
const { cwd, repoArgs } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
37109
|
-
const args = ["issue", "create", ...
|
|
37796
|
+
const { cwd, repoArgs: repoArgs2 } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
37797
|
+
const args = ["issue", "create", ...repoArgs2, "--title", title];
|
|
37110
37798
|
if (bodyParts.length) args.push("--body", bodyParts.join("\n\n"));
|
|
37111
37799
|
const created = await gh([...args, "--json", "number,url,title"], cwd, { reject: false });
|
|
37112
37800
|
if (created.exitCode === 0 && created.stdout.trim()) {
|
|
@@ -37219,12 +37907,12 @@ async function persistLinearTokens(data, viewer) {
|
|
|
37219
37907
|
organizationName: viewer?.organizationName
|
|
37220
37908
|
});
|
|
37221
37909
|
}
|
|
37222
|
-
async function fetchLinearViewer(
|
|
37910
|
+
async function fetchLinearViewer(accessToken3) {
|
|
37223
37911
|
const res = await httpFetch(LINEAR_GRAPHQL, {
|
|
37224
37912
|
method: "POST",
|
|
37225
37913
|
headers: {
|
|
37226
37914
|
"Content-Type": "application/json",
|
|
37227
|
-
Authorization: linearAuthorizationHeader(
|
|
37915
|
+
Authorization: linearAuthorizationHeader(accessToken3)
|
|
37228
37916
|
},
|
|
37229
37917
|
body: JSON.stringify({
|
|
37230
37918
|
query: "{ viewer { name organization { name } } }"
|
|
@@ -38520,6 +39208,18 @@ async function validateLinearApiKey(apiKey) {
|
|
|
38520
39208
|
}
|
|
38521
39209
|
|
|
38522
39210
|
// src/integrations/issues.ts
|
|
39211
|
+
var CURSOR_ISSUES_UNAVAILABLE = "Cursor Origin has no issue tracker. Tickets for this repo come from Linear or AbleTime (Settings \u2192 Issues).";
|
|
39212
|
+
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.";
|
|
39213
|
+
async function cursorIssuesUnavailableReason(repoPath) {
|
|
39214
|
+
try {
|
|
39215
|
+
const remote = await resolveOriginRemote(repoPath);
|
|
39216
|
+
if (remote?.forge === "cursor") return CURSOR_ISSUES_UNAVAILABLE;
|
|
39217
|
+
if (remote?.forge === "entire") return ENTIRE_ISSUES_ARE_TRAILS;
|
|
39218
|
+
return null;
|
|
39219
|
+
} catch {
|
|
39220
|
+
return null;
|
|
39221
|
+
}
|
|
39222
|
+
}
|
|
38523
39223
|
function assigneeKey(assignee) {
|
|
38524
39224
|
return (assignee ?? "").trim().toLowerCase();
|
|
38525
39225
|
}
|
|
@@ -38681,6 +39381,17 @@ async function listIssues(repoPath, opts) {
|
|
|
38681
39381
|
...since ? { since, comments: commentsFromAbleTimeIssues(tasks, issues2, since) } : {}
|
|
38682
39382
|
};
|
|
38683
39383
|
}
|
|
39384
|
+
const unavailableReason = await cursorIssuesUnavailableReason(repoPath);
|
|
39385
|
+
if (unavailableReason) {
|
|
39386
|
+
return {
|
|
39387
|
+
source,
|
|
39388
|
+
preferredSource,
|
|
39389
|
+
linearConnected,
|
|
39390
|
+
abletimeConnected,
|
|
39391
|
+
issues: [],
|
|
39392
|
+
unavailableReason
|
|
39393
|
+
};
|
|
39394
|
+
}
|
|
38684
39395
|
const [issues, login] = await Promise.all([
|
|
38685
39396
|
listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit, updatedSince: since }),
|
|
38686
39397
|
githubViewerLogin(repoPath)
|
|
@@ -39303,7 +40014,7 @@ function handleRemoteInbound(text7, opts) {
|
|
|
39303
40014
|
}
|
|
39304
40015
|
|
|
39305
40016
|
// src/remote/phone-board-sync.ts
|
|
39306
|
-
var
|
|
40017
|
+
var import_node_path67 = require("path");
|
|
39307
40018
|
var import_chokidar = require("chokidar");
|
|
39308
40019
|
init_orchestrator();
|
|
39309
40020
|
init_paths();
|
|
@@ -39356,7 +40067,7 @@ function subscribePhoneBoard(notify) {
|
|
|
39356
40067
|
threads.on("error", () => void 0);
|
|
39357
40068
|
const data = (0, import_chokidar.watch)(appDataDir(), { ignoreInitial: true, depth: 0 });
|
|
39358
40069
|
const onData = (changed) => {
|
|
39359
|
-
const name = (0,
|
|
40070
|
+
const name = (0, import_node_path67.basename)(changed);
|
|
39360
40071
|
if (name !== "workspaces.json" && name !== "removed-workspaces.json" && name !== "settings.json") return;
|
|
39361
40072
|
notify();
|
|
39362
40073
|
};
|
|
@@ -40603,9 +41314,9 @@ var SlackRelayHub = class {
|
|
|
40603
41314
|
};
|
|
40604
41315
|
|
|
40605
41316
|
// src/relay/static.ts
|
|
40606
|
-
var
|
|
41317
|
+
var import_node_fs70 = require("fs");
|
|
40607
41318
|
var import_promises = require("fs/promises");
|
|
40608
|
-
var
|
|
41319
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
40609
41320
|
var TYPES = {
|
|
40610
41321
|
".css": "text/css; charset=utf-8",
|
|
40611
41322
|
".html": "text/html; charset=utf-8",
|
|
@@ -40636,9 +41347,9 @@ function resolveStaticPath(root, requestUrl) {
|
|
|
40636
41347
|
return null;
|
|
40637
41348
|
}
|
|
40638
41349
|
if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
|
|
40639
|
-
const rootResolved =
|
|
40640
|
-
const candidate =
|
|
40641
|
-
if (candidate !== rootResolved && !candidate.startsWith(rootResolved +
|
|
41350
|
+
const rootResolved = import_node_path68.default.resolve(root);
|
|
41351
|
+
const candidate = import_node_path68.default.resolve(rootResolved, `.${pathname}`);
|
|
41352
|
+
if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path68.default.sep)) {
|
|
40642
41353
|
return null;
|
|
40643
41354
|
}
|
|
40644
41355
|
return candidate;
|
|
@@ -40652,7 +41363,7 @@ async function fileSize(file) {
|
|
|
40652
41363
|
}
|
|
40653
41364
|
}
|
|
40654
41365
|
function sendFile(req, res, file, size) {
|
|
40655
|
-
const ext =
|
|
41366
|
+
const ext = import_node_path68.default.extname(file).toLowerCase();
|
|
40656
41367
|
res.writeHead(200, {
|
|
40657
41368
|
"Content-Type": TYPES[ext] ?? "application/octet-stream",
|
|
40658
41369
|
"Content-Length": size,
|
|
@@ -40662,7 +41373,7 @@ function sendFile(req, res, file, size) {
|
|
|
40662
41373
|
res.end();
|
|
40663
41374
|
return true;
|
|
40664
41375
|
}
|
|
40665
|
-
(0,
|
|
41376
|
+
(0, import_node_fs70.createReadStream)(file).pipe(res);
|
|
40666
41377
|
return true;
|
|
40667
41378
|
}
|
|
40668
41379
|
async function tryServeStatic(req, res, root) {
|
|
@@ -40671,7 +41382,7 @@ async function tryServeStatic(req, res, root) {
|
|
|
40671
41382
|
if (!candidate) return false;
|
|
40672
41383
|
const direct = await fileSize(candidate);
|
|
40673
41384
|
if (direct != null) return sendFile(req, res, candidate, direct);
|
|
40674
|
-
const asIndex =
|
|
41385
|
+
const asIndex = import_node_path68.default.join(candidate, "index.html");
|
|
40675
41386
|
const indexSize = await fileSize(asIndex);
|
|
40676
41387
|
if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
|
|
40677
41388
|
return false;
|
|
@@ -41014,14 +41725,15 @@ init_protocol();
|
|
|
41014
41725
|
|
|
41015
41726
|
// src/relay/accounts.ts
|
|
41016
41727
|
var import_node_crypto24 = require("crypto");
|
|
41017
|
-
var
|
|
41728
|
+
var import_node_fs71 = require("fs");
|
|
41018
41729
|
var import_node_module7 = require("module");
|
|
41019
|
-
var
|
|
41730
|
+
var import_node_path69 = require("path");
|
|
41020
41731
|
var GITHUB_ACCOUNT_ISSUER = "https://github.com";
|
|
41732
|
+
var CURSOR_ACCOUNT_ISSUER = "https://api.cursor.com/v1/origin";
|
|
41021
41733
|
var RELAY_DEVICE_CAP = 3;
|
|
41022
41734
|
function thisModuleFile3() {
|
|
41023
41735
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
41024
|
-
return cjsFile || process.argv[1] || (0,
|
|
41736
|
+
return cjsFile || process.argv[1] || (0, import_node_path69.join)(process.cwd(), "package.json");
|
|
41025
41737
|
}
|
|
41026
41738
|
function openDatabase(filePath) {
|
|
41027
41739
|
const req = (0, import_node_module7.createRequire)(thisModuleFile3());
|
|
@@ -41058,8 +41770,8 @@ function assertRelayAccountsDurable(filePath) {
|
|
|
41058
41770
|
if (process.env.SIDEBOARD_RELAY_ACCOUNTS_EPHEMERAL === "1") return;
|
|
41059
41771
|
if (process.env.NODE_ENV !== "production") return;
|
|
41060
41772
|
if (process.platform !== "linux") return;
|
|
41061
|
-
const dir = (0,
|
|
41062
|
-
const mounts = (0,
|
|
41773
|
+
const dir = (0, import_node_fs71.realpathSync)((0, import_node_path69.dirname)(filePath));
|
|
41774
|
+
const mounts = (0, import_node_fs71.readFileSync)("/proc/mounts", "utf8");
|
|
41063
41775
|
const point = longestMountPoint(dir, mounts);
|
|
41064
41776
|
if (point === "/") {
|
|
41065
41777
|
throw new Error(
|
|
@@ -41070,7 +41782,7 @@ function assertRelayAccountsDurable(filePath) {
|
|
|
41070
41782
|
var RelayAccountStore = class {
|
|
41071
41783
|
db;
|
|
41072
41784
|
constructor(filePath) {
|
|
41073
|
-
(0,
|
|
41785
|
+
(0, import_node_fs71.mkdirSync)((0, import_node_path69.dirname)(filePath), { recursive: true });
|
|
41074
41786
|
this.db = openDatabase(filePath);
|
|
41075
41787
|
this.db.exec(`
|
|
41076
41788
|
CREATE TABLE IF NOT EXISTS accounts (
|
|
@@ -41270,20 +41982,224 @@ var RelayAccountStore = class {
|
|
|
41270
41982
|
}
|
|
41271
41983
|
};
|
|
41272
41984
|
|
|
41985
|
+
// src/relay/account-cursor.ts
|
|
41986
|
+
var import_node_crypto25 = require("crypto");
|
|
41987
|
+
var JWKS_URL = "https://api.cursor.com/v1/origin/keys";
|
|
41988
|
+
var RECEIPT_TYP = "origin-user-confirmation-receipt+jwt";
|
|
41989
|
+
var usedJti = /* @__PURE__ */ new Map();
|
|
41990
|
+
function b64urlJson(segment) {
|
|
41991
|
+
return JSON.parse(b64urlBuf(segment).toString("utf8"));
|
|
41992
|
+
}
|
|
41993
|
+
function b64urlBuf(segment) {
|
|
41994
|
+
const pad = segment.length % 4 === 0 ? "" : "=".repeat(4 - segment.length % 4);
|
|
41995
|
+
return Buffer.from(segment.replace(/-/g, "+").replace(/_/g, "/") + pad, "base64");
|
|
41996
|
+
}
|
|
41997
|
+
function rememberJti(jti, expMs, nowMs) {
|
|
41998
|
+
for (const [id, exp] of usedJti) {
|
|
41999
|
+
if (exp < nowMs) usedJti.delete(id);
|
|
42000
|
+
}
|
|
42001
|
+
if (usedJti.has(jti)) return false;
|
|
42002
|
+
usedJti.set(jti, expMs);
|
|
42003
|
+
return true;
|
|
42004
|
+
}
|
|
42005
|
+
function cursorAuthorizeUrl(clientId, redirectUri, state) {
|
|
42006
|
+
const url = new URL("https://cursor.com/codebase/apps/user-confirmation");
|
|
42007
|
+
url.searchParams.set("client_id", clientId);
|
|
42008
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
42009
|
+
url.searchParams.set("state", state);
|
|
42010
|
+
return url.toString();
|
|
42011
|
+
}
|
|
42012
|
+
async function cursorIdentityFromReceipt(receipt, expected, fetchImpl, nowMs = Date.now()) {
|
|
42013
|
+
const parts = receipt.split(".");
|
|
42014
|
+
if (parts.length !== 3 || !parts[0] || !parts[1] || !parts[2]) {
|
|
42015
|
+
throw new Error("Cursor sign-in receipt was not a signed token.");
|
|
42016
|
+
}
|
|
42017
|
+
const [hSeg, pSeg, sSeg] = parts;
|
|
42018
|
+
const header = b64urlJson(hSeg);
|
|
42019
|
+
if (header.alg !== "EdDSA" || header.typ !== RECEIPT_TYP || typeof header.kid !== "string") {
|
|
42020
|
+
throw new Error("Cursor sign-in receipt was not a user confirmation.");
|
|
42021
|
+
}
|
|
42022
|
+
const payload = b64urlJson(pSeg);
|
|
42023
|
+
if (payload.iss !== CURSOR_ACCOUNT_ISSUER) {
|
|
42024
|
+
throw new Error("Cursor sign-in receipt came from an unexpected issuer.");
|
|
42025
|
+
}
|
|
42026
|
+
if (payload.aud !== expected.clientId) throw new Error("Cursor sign-in receipt was for a different app.");
|
|
42027
|
+
if (payload.state !== expected.state) throw new Error("Cursor sign-in did not match this attempt.");
|
|
42028
|
+
const exp = typeof payload.exp === "number" ? payload.exp : 0;
|
|
42029
|
+
if (!exp || exp * 1e3 < nowMs) throw new Error("Cursor sign-in receipt expired.");
|
|
42030
|
+
const sub = typeof payload.sub === "string" ? payload.sub.trim() : "";
|
|
42031
|
+
if (!sub) throw new Error("Cursor did not return an account id.");
|
|
42032
|
+
const jti = typeof payload.jti === "string" ? payload.jti.trim() : "";
|
|
42033
|
+
if (!jti) throw new Error("Cursor sign-in receipt was missing an id.");
|
|
42034
|
+
const jwksRes = await fetchImpl(JWKS_URL);
|
|
42035
|
+
const body = await jwksRes.json();
|
|
42036
|
+
const jwk = (body.keys ?? []).find(
|
|
42037
|
+
(key2) => key2.kid === header.kid && key2.kty === "OKP" && key2.crv === "Ed25519" && key2.x
|
|
42038
|
+
);
|
|
42039
|
+
if (!jwk?.x) throw new Error("Cursor did not publish the key that signed this receipt.");
|
|
42040
|
+
const key = (0, import_node_crypto25.createPublicKey)({ key: { kty: "OKP", crv: "Ed25519", x: jwk.x }, format: "jwk" });
|
|
42041
|
+
const ok = (0, import_node_crypto25.verify)(null, Buffer.from(`${hSeg}.${pSeg}`), key, b64urlBuf(sSeg));
|
|
42042
|
+
if (!ok) throw new Error("Cursor sign-in receipt signature did not verify.");
|
|
42043
|
+
if (!rememberJti(jti, exp * 1e3, nowMs)) throw new Error("Cursor sign-in receipt was already used.");
|
|
42044
|
+
const email = typeof payload.email === "string" && payload.email.trim() ? payload.email.trim() : null;
|
|
42045
|
+
return {
|
|
42046
|
+
issuer: CURSOR_ACCOUNT_ISSUER,
|
|
42047
|
+
subject: sub,
|
|
42048
|
+
email,
|
|
42049
|
+
emailVerified: Boolean(email)
|
|
42050
|
+
};
|
|
42051
|
+
}
|
|
42052
|
+
function cursorGitHostEntry() {
|
|
42053
|
+
return {
|
|
42054
|
+
label: "Cursor",
|
|
42055
|
+
requiresClientSecret: false,
|
|
42056
|
+
credentialParam: "confirmation_receipt",
|
|
42057
|
+
authorizeUrl(client, redirectUri, state) {
|
|
42058
|
+
return cursorAuthorizeUrl(client.clientId, redirectUri, state);
|
|
42059
|
+
},
|
|
42060
|
+
fetchIdentity(client, receipt, _redirectUri, state, fetchImpl) {
|
|
42061
|
+
return cursorIdentityFromReceipt(receipt, { clientId: client.clientId, state }, fetchImpl);
|
|
42062
|
+
}
|
|
42063
|
+
};
|
|
42064
|
+
}
|
|
42065
|
+
|
|
42066
|
+
// src/relay/account-entire.ts
|
|
42067
|
+
var import_node_crypto26 = require("crypto");
|
|
42068
|
+
var ENTIRE_AUTHORIZE_ORIGIN = "https://auth.entire.io";
|
|
42069
|
+
var ENTIRE_DEFAULT_ISSUER = "https://us.auth.entire.io";
|
|
42070
|
+
var ISSUER_SUFFIX = ".auth.entire.io";
|
|
42071
|
+
function entireAccountIssuer(value) {
|
|
42072
|
+
const raw = value?.trim() ?? "";
|
|
42073
|
+
if (!raw) return null;
|
|
42074
|
+
let url;
|
|
42075
|
+
try {
|
|
42076
|
+
url = new URL(raw);
|
|
42077
|
+
} catch {
|
|
42078
|
+
return null;
|
|
42079
|
+
}
|
|
42080
|
+
if (url.protocol !== "https:" || url.username || url.password || url.port) return null;
|
|
42081
|
+
if (url.pathname !== "/" && url.pathname !== "") return null;
|
|
42082
|
+
if (url.search || url.hash) return null;
|
|
42083
|
+
const host = url.hostname.toLowerCase();
|
|
42084
|
+
if (!host.endsWith(ISSUER_SUFFIX)) return null;
|
|
42085
|
+
const label = host.slice(0, -ISSUER_SUFFIX.length);
|
|
42086
|
+
if (!/^[a-z0-9]+$/.test(label)) return null;
|
|
42087
|
+
return `https://${host}`;
|
|
42088
|
+
}
|
|
42089
|
+
function newEntireCodeVerifier() {
|
|
42090
|
+
return (0, import_node_crypto26.randomBytes)(32).toString("base64url");
|
|
42091
|
+
}
|
|
42092
|
+
function entireCodeChallenge(verifier) {
|
|
42093
|
+
return (0, import_node_crypto26.createHash)("sha256").update(verifier).digest("base64url");
|
|
42094
|
+
}
|
|
42095
|
+
function entireAuthorizeUrl(clientId, redirectUri, state, codeChallenge) {
|
|
42096
|
+
const url = new URL("/authorize", ENTIRE_AUTHORIZE_ORIGIN);
|
|
42097
|
+
url.searchParams.set("client_id", clientId);
|
|
42098
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
42099
|
+
url.searchParams.set("response_type", "code");
|
|
42100
|
+
url.searchParams.set("scope", "openid email");
|
|
42101
|
+
url.searchParams.set("state", state);
|
|
42102
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
42103
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
42104
|
+
return url.toString();
|
|
42105
|
+
}
|
|
42106
|
+
async function readJson3(res) {
|
|
42107
|
+
const text7 = await res.text();
|
|
42108
|
+
if (!text7) return {};
|
|
42109
|
+
try {
|
|
42110
|
+
return JSON.parse(text7);
|
|
42111
|
+
} catch {
|
|
42112
|
+
throw new Error("Entire returned a non-JSON response.");
|
|
42113
|
+
}
|
|
42114
|
+
}
|
|
42115
|
+
function accessToken(body) {
|
|
42116
|
+
const token = body.access_token;
|
|
42117
|
+
if (typeof token === "string" && token.trim()) return token.trim();
|
|
42118
|
+
const described = body.error_description;
|
|
42119
|
+
const code = body.error;
|
|
42120
|
+
const message = typeof described === "string" && described.trim() ? described : code;
|
|
42121
|
+
throw new Error(
|
|
42122
|
+
typeof message === "string" && message.trim() ? message : "Entire rejected the sign-in code."
|
|
42123
|
+
);
|
|
42124
|
+
}
|
|
42125
|
+
async function entireIdentityFromCode(client, code, redirectUri, ctx, fetchImpl) {
|
|
42126
|
+
if (!ctx.codeVerifier) throw new Error("Entire sign-in could not be verified.");
|
|
42127
|
+
const issuer = ctx.issuer?.trim() ? entireAccountIssuer(ctx.issuer) : ENTIRE_DEFAULT_ISSUER;
|
|
42128
|
+
if (!issuer) throw new Error("Entire sign-in came from an unexpected issuer.");
|
|
42129
|
+
const body = new URLSearchParams({
|
|
42130
|
+
grant_type: "authorization_code",
|
|
42131
|
+
code,
|
|
42132
|
+
redirect_uri: redirectUri,
|
|
42133
|
+
client_id: client.clientId,
|
|
42134
|
+
code_verifier: ctx.codeVerifier
|
|
42135
|
+
});
|
|
42136
|
+
const secret = client.clientSecret?.trim() ?? "";
|
|
42137
|
+
const headers = {
|
|
42138
|
+
Accept: "application/json",
|
|
42139
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
42140
|
+
};
|
|
42141
|
+
if (secret) {
|
|
42142
|
+
headers.Authorization = `Basic ${Buffer.from(`${client.clientId}:${secret}`).toString("base64")}`;
|
|
42143
|
+
}
|
|
42144
|
+
const tokenRes = await fetchImpl(`${issuer}/oauth/token`, {
|
|
42145
|
+
method: "POST",
|
|
42146
|
+
redirect: "error",
|
|
42147
|
+
headers,
|
|
42148
|
+
body
|
|
42149
|
+
});
|
|
42150
|
+
const token = accessToken(await readJson3(tokenRes));
|
|
42151
|
+
const userRes = await fetchImpl(`${issuer}/userinfo`, {
|
|
42152
|
+
redirect: "error",
|
|
42153
|
+
headers: { Accept: "application/json", Authorization: `Bearer ${token}` }
|
|
42154
|
+
});
|
|
42155
|
+
if (!userRes.ok) throw new Error("Entire did not return an account.");
|
|
42156
|
+
const user = await readJson3(userRes);
|
|
42157
|
+
const subject = typeof user.sub === "string" ? user.sub.trim() : "";
|
|
42158
|
+
if (!subject) throw new Error("Entire did not return an account id.");
|
|
42159
|
+
const email = typeof user.email === "string" ? user.email.trim() : "";
|
|
42160
|
+
const emailVerified = user.email_verified === true && Boolean(email);
|
|
42161
|
+
return {
|
|
42162
|
+
issuer,
|
|
42163
|
+
subject,
|
|
42164
|
+
email: emailVerified ? email : null,
|
|
42165
|
+
emailVerified
|
|
42166
|
+
};
|
|
42167
|
+
}
|
|
42168
|
+
function entireGitHostEntry() {
|
|
42169
|
+
return {
|
|
42170
|
+
label: "Entire",
|
|
42171
|
+
requiresClientSecret: false,
|
|
42172
|
+
credentialParam: "code",
|
|
42173
|
+
authorizeUrl(client, redirectUri, state, ctx) {
|
|
42174
|
+
if (!ctx.codeVerifier) throw new Error("Entire sign-in could not start.");
|
|
42175
|
+
return entireAuthorizeUrl(client.clientId, redirectUri, state, entireCodeChallenge(ctx.codeVerifier));
|
|
42176
|
+
},
|
|
42177
|
+
fetchIdentity(client, code, redirectUri, _state, fetchImpl, ctx) {
|
|
42178
|
+
return entireIdentityFromCode(client, code, redirectUri, ctx, fetchImpl);
|
|
42179
|
+
}
|
|
42180
|
+
};
|
|
42181
|
+
}
|
|
42182
|
+
|
|
41273
42183
|
// src/relay/account-oauth.ts
|
|
41274
|
-
var RELAY_GIT_HOSTS = ["github"];
|
|
42184
|
+
var RELAY_GIT_HOSTS = ["github", "cursor", "entire"];
|
|
41275
42185
|
var REMOTE_LOGIN_PATH = "/remote/login";
|
|
41276
42186
|
var REMOTE_OAUTH_CALLBACK_PATH = "/remote/oauth/callback";
|
|
41277
42187
|
var REMOTE_OAUTH_RESULT_PATH = "/remote/oauth/result";
|
|
41278
42188
|
var REMOTE_LOGOUT_PATH = "/remote/logout";
|
|
41279
42189
|
var STATE_RE = /^[A-Za-z0-9_-]{16,128}$/;
|
|
41280
42190
|
var LOGIN_TTL_MS = 10 * 60 * 1e3;
|
|
42191
|
+
var EMPTY_AUTH = { codeVerifier: null, issuer: null };
|
|
41281
42192
|
var RelayLoginSessions = class {
|
|
41282
42193
|
waiting = /* @__PURE__ */ new Map();
|
|
41283
42194
|
results = /* @__PURE__ */ new Map();
|
|
41284
|
-
begin(state, provider, accountId) {
|
|
42195
|
+
begin(state, provider, accountId, codeVerifier = null) {
|
|
41285
42196
|
this.sweep();
|
|
41286
|
-
this.waiting.set(state, {
|
|
42197
|
+
this.waiting.set(state, {
|
|
42198
|
+
provider,
|
|
42199
|
+
accountId,
|
|
42200
|
+
codeVerifier,
|
|
42201
|
+
expiresAt: Date.now() + LOGIN_TTL_MS
|
|
42202
|
+
});
|
|
41287
42203
|
}
|
|
41288
42204
|
takeLogin(state) {
|
|
41289
42205
|
this.sweep();
|
|
@@ -41318,24 +42234,29 @@ var RelayLoginSessions = class {
|
|
|
41318
42234
|
var GIT_HOST_AUTH = {
|
|
41319
42235
|
github: {
|
|
41320
42236
|
label: "GitHub",
|
|
41321
|
-
|
|
41322
|
-
|
|
42237
|
+
requiresClientSecret: true,
|
|
42238
|
+
credentialParam: "code",
|
|
42239
|
+
authorizeUrl: (client, redirectUri, state) => githubAuthorizeUrl(client, redirectUri, state),
|
|
41323
42240
|
fetchIdentity: fetchGithubIdentity
|
|
41324
|
-
}
|
|
42241
|
+
},
|
|
42242
|
+
cursor: cursorGitHostEntry(),
|
|
42243
|
+
entire: entireGitHostEntry()
|
|
41325
42244
|
};
|
|
41326
|
-
function
|
|
41327
|
-
|
|
41328
|
-
}
|
|
41329
|
-
function relayAuthorizeUrl(provider, client, redirectUri, state) {
|
|
41330
|
-
const host = GIT_HOST_AUTH[provider];
|
|
41331
|
-
const url = new URL(host.authorizeUrl);
|
|
42245
|
+
function githubAuthorizeUrl(client, redirectUri, state) {
|
|
42246
|
+
const url = new URL("https://github.com/login/oauth/authorize");
|
|
41332
42247
|
url.searchParams.set("client_id", client.clientId);
|
|
41333
42248
|
url.searchParams.set("redirect_uri", redirectUri);
|
|
41334
|
-
url.searchParams.set("scope",
|
|
42249
|
+
url.searchParams.set("scope", "user:email");
|
|
41335
42250
|
url.searchParams.set("state", state);
|
|
41336
42251
|
return url.toString();
|
|
41337
42252
|
}
|
|
41338
|
-
|
|
42253
|
+
function providerOf(value) {
|
|
42254
|
+
return RELAY_GIT_HOSTS.includes(value) ? value : null;
|
|
42255
|
+
}
|
|
42256
|
+
function relayAuthorizeUrl(provider, client, redirectUri, state, ctx = EMPTY_AUTH) {
|
|
42257
|
+
return GIT_HOST_AUTH[provider].authorizeUrl(client, redirectUri, state, ctx);
|
|
42258
|
+
}
|
|
42259
|
+
async function readJson4(res) {
|
|
41339
42260
|
const text7 = await res.text();
|
|
41340
42261
|
if (!text7) return {};
|
|
41341
42262
|
try {
|
|
@@ -41344,7 +42265,7 @@ async function readJson3(res) {
|
|
|
41344
42265
|
throw new Error("Sign-in provider returned a non-JSON response.");
|
|
41345
42266
|
}
|
|
41346
42267
|
}
|
|
41347
|
-
function
|
|
42268
|
+
function accessToken2(body) {
|
|
41348
42269
|
const token = body.access_token;
|
|
41349
42270
|
if (typeof token !== "string" || !token.trim()) {
|
|
41350
42271
|
const message = body.error_description;
|
|
@@ -41352,7 +42273,10 @@ function accessToken(body) {
|
|
|
41352
42273
|
}
|
|
41353
42274
|
return token.trim();
|
|
41354
42275
|
}
|
|
41355
|
-
async function fetchGithubIdentity(client, code, redirectUri, fetchImpl) {
|
|
42276
|
+
async function fetchGithubIdentity(client, code, redirectUri, state, fetchImpl, _ctx) {
|
|
42277
|
+
void state;
|
|
42278
|
+
void _ctx;
|
|
42279
|
+
if (!client.clientSecret) throw new Error("GitHub sign-in is not configured on this relay.");
|
|
41356
42280
|
const tokenRes = await fetchImpl("https://github.com/login/oauth/access_token", {
|
|
41357
42281
|
method: "POST",
|
|
41358
42282
|
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
|
@@ -41363,17 +42287,17 @@ async function fetchGithubIdentity(client, code, redirectUri, fetchImpl) {
|
|
|
41363
42287
|
redirect_uri: redirectUri
|
|
41364
42288
|
})
|
|
41365
42289
|
});
|
|
41366
|
-
const token =
|
|
42290
|
+
const token = accessToken2(await readJson4(tokenRes));
|
|
41367
42291
|
const userRes = await fetchImpl("https://api.github.com/user", {
|
|
41368
42292
|
headers: { Authorization: `Bearer ${token}`, Accept: "application/vnd.github+json", "User-Agent": "sideboard-relay" }
|
|
41369
42293
|
});
|
|
41370
|
-
const user = await
|
|
42294
|
+
const user = await readJson4(userRes);
|
|
41371
42295
|
const subject = typeof user.id === "number" ? String(user.id) : "";
|
|
41372
42296
|
if (!subject) throw new Error("GitHub did not return an account id.");
|
|
41373
42297
|
const emailRes = await fetchImpl("https://api.github.com/user/emails", {
|
|
41374
42298
|
headers: { Authorization: `Bearer ${token}`, Accept: "application/vnd.github+json", "User-Agent": "sideboard-relay" }
|
|
41375
42299
|
});
|
|
41376
|
-
const emails = await
|
|
42300
|
+
const emails = await readJson4(emailRes);
|
|
41377
42301
|
const list = Array.isArray(emails) ? emails : [];
|
|
41378
42302
|
const primary = list.find((row2) => row2.primary === true && row2.verified === true);
|
|
41379
42303
|
const anyVerified = list.find((row2) => row2.verified === true);
|
|
@@ -41381,8 +42305,8 @@ async function fetchGithubIdentity(client, code, redirectUri, fetchImpl) {
|
|
|
41381
42305
|
const email = chosen && typeof chosen.email === "string" ? chosen.email : null;
|
|
41382
42306
|
return { issuer: GITHUB_ACCOUNT_ISSUER, subject, email, emailVerified: Boolean(email) };
|
|
41383
42307
|
}
|
|
41384
|
-
async function fetchRelayIdentity(provider, client,
|
|
41385
|
-
return GIT_HOST_AUTH[provider].fetchIdentity(client,
|
|
42308
|
+
async function fetchRelayIdentity(provider, client, credential, redirectUri, state, fetchImpl, ctx = EMPTY_AUTH) {
|
|
42309
|
+
return GIT_HOST_AUTH[provider].fetchIdentity(client, credential, redirectUri, state, fetchImpl, ctx);
|
|
41386
42310
|
}
|
|
41387
42311
|
async function readBody(req) {
|
|
41388
42312
|
const chunks = [];
|
|
@@ -41492,7 +42416,8 @@ async function handleRelayAccountHttp(opts) {
|
|
|
41492
42416
|
return true;
|
|
41493
42417
|
}
|
|
41494
42418
|
const client = opts.oauth[provider];
|
|
41495
|
-
|
|
42419
|
+
const host = provider ? GIT_HOST_AUTH[provider] : null;
|
|
42420
|
+
if (!client?.clientId || host?.requiresClientSecret && !client.clientSecret) {
|
|
41496
42421
|
sendJson(opts.res, 503, {
|
|
41497
42422
|
ok: false,
|
|
41498
42423
|
error: `${GIT_HOST_AUTH[provider].label} sign-in is not configured on this relay.`
|
|
@@ -41508,21 +42433,26 @@ async function handleRelayAccountHttp(opts) {
|
|
|
41508
42433
|
return true;
|
|
41509
42434
|
}
|
|
41510
42435
|
}
|
|
41511
|
-
|
|
41512
|
-
|
|
42436
|
+
const codeVerifier = provider === "entire" ? newEntireCodeVerifier() : null;
|
|
42437
|
+
const auth = { codeVerifier, issuer: null };
|
|
42438
|
+
opts.sessions.begin(state, provider, accountId, codeVerifier);
|
|
42439
|
+
sendJson(opts.res, 200, {
|
|
42440
|
+
ok: true,
|
|
42441
|
+
url: relayAuthorizeUrl(provider, client, redirectUri, state, auth)
|
|
42442
|
+
});
|
|
41513
42443
|
return true;
|
|
41514
42444
|
}
|
|
41515
42445
|
if (method === "GET" && path2 === REMOTE_OAUTH_CALLBACK_PATH) {
|
|
41516
42446
|
const url = new URL(reqUrl, origin);
|
|
41517
42447
|
const state = url.searchParams.get("state")?.trim() ?? "";
|
|
41518
|
-
const code = url.searchParams.get("code")?.trim() ?? "";
|
|
41519
42448
|
const providerError = url.searchParams.get("error")?.trim() ?? "";
|
|
41520
42449
|
const pending = STATE_RE.test(state) ? opts.sessions.takeLogin(state) : null;
|
|
41521
42450
|
if (!pending) {
|
|
41522
42451
|
sendHtml(opts.res, 400, "Sideboard", "<h1>Sign-in expired</h1><p>Return to Sideboard and try again.</p>");
|
|
41523
42452
|
return true;
|
|
41524
42453
|
}
|
|
41525
|
-
|
|
42454
|
+
const credential = url.searchParams.get(GIT_HOST_AUTH[pending.provider].credentialParam)?.trim() ?? "";
|
|
42455
|
+
if (providerError || !credential) {
|
|
41526
42456
|
const message = providerError || "Sign-in was cancelled.";
|
|
41527
42457
|
opts.sessions.putResult(state, { ok: false, error: message });
|
|
41528
42458
|
sendHtml(opts.res, 400, "Sideboard", `<h1>Could not sign in</h1><p>${escapeHtml2(message)}</p>`);
|
|
@@ -41535,7 +42465,15 @@ async function handleRelayAccountHttp(opts) {
|
|
|
41535
42465
|
return true;
|
|
41536
42466
|
}
|
|
41537
42467
|
try {
|
|
41538
|
-
const identity = await fetchRelayIdentity(
|
|
42468
|
+
const identity = await fetchRelayIdentity(
|
|
42469
|
+
pending.provider,
|
|
42470
|
+
client,
|
|
42471
|
+
credential,
|
|
42472
|
+
redirectUri,
|
|
42473
|
+
state,
|
|
42474
|
+
fetchImpl,
|
|
42475
|
+
{ codeVerifier: pending.codeVerifier, issuer: url.searchParams.get("iss") }
|
|
42476
|
+
);
|
|
41539
42477
|
const signed = opts.store.signIn(identity, pending.accountId);
|
|
41540
42478
|
opts.sessions.putResult(state, {
|
|
41541
42479
|
ok: true,
|
|
@@ -42091,9 +43029,138 @@ init_run();
|
|
|
42091
43029
|
init_gh_errors();
|
|
42092
43030
|
init_git_auth_mode();
|
|
42093
43031
|
init_worktree();
|
|
43032
|
+
init_pr_write();
|
|
42094
43033
|
init_stack();
|
|
42095
43034
|
init_branch_prefix();
|
|
42096
43035
|
init_agent_git_actions();
|
|
43036
|
+
|
|
43037
|
+
// src/integrations/cursor-git.ts
|
|
43038
|
+
init_install();
|
|
43039
|
+
init_run();
|
|
43040
|
+
function parseOriginAuthStatus(text7) {
|
|
43041
|
+
const account = text7.match(/^Account:\s+(.+)$/m)?.[1]?.trim() || null;
|
|
43042
|
+
const authMethod = text7.match(/^Auth method:\s+(.+)$/m)?.[1]?.trim() || null;
|
|
43043
|
+
return { account, authMethod };
|
|
43044
|
+
}
|
|
43045
|
+
async function getCursorGitStatus() {
|
|
43046
|
+
const which = await run("which", ["origin"], { reject: false, timeoutMs: 5e3 });
|
|
43047
|
+
if (which.exitCode !== 0 || !which.stdout.trim()) {
|
|
43048
|
+
return {
|
|
43049
|
+
installed: false,
|
|
43050
|
+
connected: false,
|
|
43051
|
+
account: null,
|
|
43052
|
+
authMethod: null,
|
|
43053
|
+
reason: "origin CLI not found on PATH"
|
|
43054
|
+
};
|
|
43055
|
+
}
|
|
43056
|
+
const status = await run("origin", ["auth", "status"], { reject: false, timeoutMs: 15e3 });
|
|
43057
|
+
const text7 = `${status.stdout}
|
|
43058
|
+
${status.stderr}`;
|
|
43059
|
+
const parsed = parseOriginAuthStatus(text7);
|
|
43060
|
+
if (status.exitCode === 0 && parsed.account) {
|
|
43061
|
+
return {
|
|
43062
|
+
installed: true,
|
|
43063
|
+
connected: true,
|
|
43064
|
+
account: parsed.account,
|
|
43065
|
+
authMethod: parsed.authMethod,
|
|
43066
|
+
reason: null
|
|
43067
|
+
};
|
|
43068
|
+
}
|
|
43069
|
+
return {
|
|
43070
|
+
installed: true,
|
|
43071
|
+
connected: false,
|
|
43072
|
+
account: null,
|
|
43073
|
+
authMethod: null,
|
|
43074
|
+
reason: status.stderr.trim() || status.stdout.trim() || "Not signed in to Cursor (Settings \u2192 Git \u2192 Cursor, or origin auth login)"
|
|
43075
|
+
};
|
|
43076
|
+
}
|
|
43077
|
+
async function loginCursorGit() {
|
|
43078
|
+
const status = await getCursorGitStatus();
|
|
43079
|
+
if (!status.installed) {
|
|
43080
|
+
return { ok: false, message: status.reason || "origin CLI not found on PATH" };
|
|
43081
|
+
}
|
|
43082
|
+
await openInSystemTerminal("origin auth login");
|
|
43083
|
+
return {
|
|
43084
|
+
ok: true,
|
|
43085
|
+
openedTerminal: true,
|
|
43086
|
+
command: "origin auth login",
|
|
43087
|
+
message: "Opened Terminal to run: origin auth login"
|
|
43088
|
+
};
|
|
43089
|
+
}
|
|
43090
|
+
async function setupCursorGit() {
|
|
43091
|
+
const status = await getCursorGitStatus();
|
|
43092
|
+
if (!status.installed) {
|
|
43093
|
+
return { ok: false, message: status.reason || "origin CLI not found on PATH" };
|
|
43094
|
+
}
|
|
43095
|
+
const result = await run("origin", ["auth", "setup-git"], {
|
|
43096
|
+
reject: false,
|
|
43097
|
+
timeoutMs: 2e4
|
|
43098
|
+
});
|
|
43099
|
+
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");
|
|
43100
|
+
return {
|
|
43101
|
+
ok: result.exitCode === 0,
|
|
43102
|
+
command: "origin auth setup-git",
|
|
43103
|
+
message,
|
|
43104
|
+
stdout: result.stdout,
|
|
43105
|
+
stderr: result.stderr,
|
|
43106
|
+
exitCode: result.exitCode
|
|
43107
|
+
};
|
|
43108
|
+
}
|
|
43109
|
+
|
|
43110
|
+
// src/integrations/entire-git.ts
|
|
43111
|
+
init_install();
|
|
43112
|
+
init_run();
|
|
43113
|
+
function parseEntireAuthContexts(text7) {
|
|
43114
|
+
for (const line of text7.split("\n")) {
|
|
43115
|
+
if (!/\(active\)/i.test(line)) continue;
|
|
43116
|
+
const cols = line.replace(/\(active\)/gi, "").trim().split(/\s{2,}/).map((part) => part.trim()).filter(Boolean);
|
|
43117
|
+
const handle = cols[1] || cols[0] || null;
|
|
43118
|
+
if (handle && !/^context$/i.test(handle)) return { account: handle };
|
|
43119
|
+
}
|
|
43120
|
+
return { account: null };
|
|
43121
|
+
}
|
|
43122
|
+
async function getEntireGitStatus() {
|
|
43123
|
+
const which = await run("which", ["entire"], { reject: false, timeoutMs: 5e3 });
|
|
43124
|
+
if (which.exitCode !== 0 || !which.stdout.trim()) {
|
|
43125
|
+
return {
|
|
43126
|
+
installed: false,
|
|
43127
|
+
connected: false,
|
|
43128
|
+
account: null,
|
|
43129
|
+
reason: "entire CLI not found on PATH"
|
|
43130
|
+
};
|
|
43131
|
+
}
|
|
43132
|
+
const status = await run("entire", ["auth", "contexts"], { reject: false, timeoutMs: 15e3 });
|
|
43133
|
+
const parsed = parseEntireAuthContexts(status.stdout);
|
|
43134
|
+
if (status.exitCode === 0 && parsed.account) {
|
|
43135
|
+
return {
|
|
43136
|
+
installed: true,
|
|
43137
|
+
connected: true,
|
|
43138
|
+
account: parsed.account,
|
|
43139
|
+
reason: null
|
|
43140
|
+
};
|
|
43141
|
+
}
|
|
43142
|
+
return {
|
|
43143
|
+
installed: true,
|
|
43144
|
+
connected: false,
|
|
43145
|
+
account: null,
|
|
43146
|
+
reason: status.stderr.trim() || "Not signed in to Entire (Settings \u2192 Git \u2192 Entire, or entire login)"
|
|
43147
|
+
};
|
|
43148
|
+
}
|
|
43149
|
+
async function loginEntireGit() {
|
|
43150
|
+
const status = await getEntireGitStatus();
|
|
43151
|
+
if (!status.installed) {
|
|
43152
|
+
return { ok: false, message: status.reason || "entire CLI not found on PATH" };
|
|
43153
|
+
}
|
|
43154
|
+
await openInSystemTerminal("entire login");
|
|
43155
|
+
return {
|
|
43156
|
+
ok: true,
|
|
43157
|
+
openedTerminal: true,
|
|
43158
|
+
command: "entire login",
|
|
43159
|
+
message: "Opened Terminal to run: entire login"
|
|
43160
|
+
};
|
|
43161
|
+
}
|
|
43162
|
+
|
|
43163
|
+
// src/index.ts
|
|
42097
43164
|
init_abletime();
|
|
42098
43165
|
init_abletime_mcp();
|
|
42099
43166
|
init_abletime_oauth();
|
|
@@ -42174,7 +43241,7 @@ init_stage_files();
|
|
|
42174
43241
|
init_consume_attachments();
|
|
42175
43242
|
|
|
42176
43243
|
// src/composer/pasted-text.ts
|
|
42177
|
-
var
|
|
43244
|
+
var import_node_crypto27 = require("crypto");
|
|
42178
43245
|
var PASTE_ATTACH_MIN_CHARS = 1200;
|
|
42179
43246
|
var PASTE_ATTACH_MIN_LINES = 15;
|
|
42180
43247
|
var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
|
|
@@ -42201,7 +43268,7 @@ function nextPastedTextName(existing) {
|
|
|
42201
43268
|
}
|
|
42202
43269
|
function buildPastedTextAttachment(text7, opts) {
|
|
42203
43270
|
return {
|
|
42204
|
-
id: opts?.id ?? (0,
|
|
43271
|
+
id: opts?.id ?? (0, import_node_crypto27.randomUUID)(),
|
|
42205
43272
|
name: opts?.name ?? "Pasted text #1.txt",
|
|
42206
43273
|
kind: "file",
|
|
42207
43274
|
path: opts?.path,
|
|
@@ -42276,22 +43343,22 @@ init_error_detail();
|
|
|
42276
43343
|
init_cursor_stream_cutoff();
|
|
42277
43344
|
|
|
42278
43345
|
// src/agents/tool-result-clip.ts
|
|
42279
|
-
var
|
|
42280
|
-
var
|
|
43346
|
+
var import_node_fs72 = require("fs");
|
|
43347
|
+
var import_node_path70 = require("path");
|
|
42281
43348
|
init_workspace_scratch();
|
|
42282
43349
|
init_error_detail();
|
|
42283
43350
|
function spillPath(cwd, prefix) {
|
|
42284
43351
|
const stamp = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
42285
43352
|
const safe = prefix.replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "tool";
|
|
42286
|
-
return (0,
|
|
43353
|
+
return (0, import_node_path70.join)(cwd, CLI_DIR, `${safe}-${stamp}.txt`);
|
|
42287
43354
|
}
|
|
42288
43355
|
function spillToolResultToCli(content, opts) {
|
|
42289
43356
|
const cwd = opts?.cwd?.trim();
|
|
42290
43357
|
if (!cwd || !content) return null;
|
|
42291
43358
|
const file = spillPath(cwd, opts?.prefix ?? "tool-result");
|
|
42292
43359
|
try {
|
|
42293
|
-
(0,
|
|
42294
|
-
(0,
|
|
43360
|
+
(0, import_node_fs72.mkdirSync)((0, import_node_path70.join)(cwd, CLI_DIR), { recursive: true });
|
|
43361
|
+
(0, import_node_fs72.writeFileSync)(file, content, "utf8");
|
|
42295
43362
|
return file;
|
|
42296
43363
|
} catch {
|
|
42297
43364
|
return null;
|
|
@@ -42377,8 +43444,8 @@ function createClippedMcpServer() {
|
|
|
42377
43444
|
|
|
42378
43445
|
// src/mcp/server.ts
|
|
42379
43446
|
var import_zod11 = require("zod");
|
|
42380
|
-
var
|
|
42381
|
-
var
|
|
43447
|
+
var import_node_crypto30 = require("crypto");
|
|
43448
|
+
var import_node_path74 = require("path");
|
|
42382
43449
|
init_orchestrator();
|
|
42383
43450
|
init_task_state();
|
|
42384
43451
|
init_worktree();
|
|
@@ -43148,11 +44215,15 @@ function fail2(err) {
|
|
|
43148
44215
|
true
|
|
43149
44216
|
);
|
|
43150
44217
|
}
|
|
44218
|
+
async function cursorIssueBlock(repoPath) {
|
|
44219
|
+
const cwd = await resolveRepoRoot((repoPath ?? "").trim() || process.cwd());
|
|
44220
|
+
return cursorIssuesUnavailableReason(cwd);
|
|
44221
|
+
}
|
|
43151
44222
|
var repoPathSchema = import_zod6.z.string().optional().describe("Workspace / worktree path. Omit on a worktree turn (uses cwd).");
|
|
43152
44223
|
function registerGithubIssueTools(server) {
|
|
43153
44224
|
server.tool(
|
|
43154
44225
|
"github_search_issues",
|
|
43155
|
-
"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).",
|
|
44226
|
+
"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).",
|
|
43156
44227
|
{
|
|
43157
44228
|
query: import_zod6.z.string().optional().describe("Search text (title, body, identifiers). Omit to list by assignee only."),
|
|
43158
44229
|
assignee: import_zod6.z.string().optional().describe("me, unassigned, all, or a GitHub login. Default: all when query is set, otherwise me."),
|
|
@@ -43164,6 +44235,15 @@ function registerGithubIssueTools(server) {
|
|
|
43164
44235
|
try {
|
|
43165
44236
|
const cwd = await resolveRepoRoot((repoPath ?? "").trim() || process.cwd());
|
|
43166
44237
|
const page = clampMcpIssueLimit(limit);
|
|
44238
|
+
const blocked = await cursorIssuesUnavailableReason(cwd);
|
|
44239
|
+
if (blocked) {
|
|
44240
|
+
return mcpJson(
|
|
44241
|
+
formatListedIssuesForMcp(
|
|
44242
|
+
{ source: "github", issues: [], unavailableReason: blocked },
|
|
44243
|
+
page
|
|
44244
|
+
)
|
|
44245
|
+
);
|
|
44246
|
+
}
|
|
43167
44247
|
const since = updatedSince ? parseIssueSince(updatedSince) : void 0;
|
|
43168
44248
|
const issues = await listGitHubIssues(cwd, {
|
|
43169
44249
|
query,
|
|
@@ -43199,6 +44279,8 @@ function registerGithubIssueTools(server) {
|
|
|
43199
44279
|
{ repoPath: repoPathSchema },
|
|
43200
44280
|
async ({ repoPath }) => {
|
|
43201
44281
|
try {
|
|
44282
|
+
const blocked = await cursorIssueBlock(repoPath);
|
|
44283
|
+
if (blocked) throw new Error(blocked);
|
|
43202
44284
|
return text4({ projects: await listGitHubProjects({ repoPath }) });
|
|
43203
44285
|
} catch (err) {
|
|
43204
44286
|
return fail2(err);
|
|
@@ -43211,6 +44293,8 @@ function registerGithubIssueTools(server) {
|
|
|
43211
44293
|
{ id: import_zod6.z.string(), include: mcpIssueIncludeSchema, repoPath: repoPathSchema },
|
|
43212
44294
|
async ({ id, include, repoPath }) => {
|
|
43213
44295
|
try {
|
|
44296
|
+
const blocked = await cursorIssueBlock(repoPath);
|
|
44297
|
+
if (blocked) throw new Error(blocked);
|
|
43214
44298
|
return text4(formatGitHubIssuePayload(await getGitHubIssue(id, { repoPath }), include));
|
|
43215
44299
|
} catch (err) {
|
|
43216
44300
|
return fail2(err);
|
|
@@ -43239,6 +44323,8 @@ function registerGithubIssueTools(server) {
|
|
|
43239
44323
|
{ id: import_zod6.z.string(), body: import_zod6.z.string(), repoPath: repoPathSchema },
|
|
43240
44324
|
async ({ id, body, repoPath }) => {
|
|
43241
44325
|
try {
|
|
44326
|
+
const blocked = await cursorIssueBlock(repoPath);
|
|
44327
|
+
if (blocked) throw new Error(blocked);
|
|
43242
44328
|
return text4(await commentGitHubIssue({ id, body }, { repoPath }));
|
|
43243
44329
|
} catch (err) {
|
|
43244
44330
|
return fail2(err);
|
|
@@ -43266,6 +44352,8 @@ function registerGithubIssueTools(server) {
|
|
|
43266
44352
|
},
|
|
43267
44353
|
async (args) => {
|
|
43268
44354
|
try {
|
|
44355
|
+
const blocked = await cursorIssueBlock(args.repoPath);
|
|
44356
|
+
if (blocked) throw new Error(blocked);
|
|
43269
44357
|
return text4(await updateGitHubIssue(args, { repoPath: args.repoPath }));
|
|
43270
44358
|
} catch (err) {
|
|
43271
44359
|
return fail2(err);
|
|
@@ -43283,6 +44371,8 @@ function registerGithubIssueTools(server) {
|
|
|
43283
44371
|
},
|
|
43284
44372
|
async (args) => {
|
|
43285
44373
|
try {
|
|
44374
|
+
const blocked = await cursorIssueBlock(args.repoPath);
|
|
44375
|
+
if (blocked) throw new Error(blocked);
|
|
43286
44376
|
return text4(await createGitHubIssue(args, { repoPath: args.repoPath }));
|
|
43287
44377
|
} catch (err) {
|
|
43288
44378
|
return fail2(err);
|
|
@@ -43970,8 +45060,8 @@ function registerScheduleTools(server) {
|
|
|
43970
45060
|
}
|
|
43971
45061
|
|
|
43972
45062
|
// src/agent-rpc/handlers.ts
|
|
43973
|
-
var
|
|
43974
|
-
var
|
|
45063
|
+
var import_node_crypto28 = require("crypto");
|
|
45064
|
+
var import_node_path71 = require("path");
|
|
43975
45065
|
init_wait_for_job();
|
|
43976
45066
|
init_wait_for_turn();
|
|
43977
45067
|
|
|
@@ -44053,7 +45143,7 @@ var handlePermissionAsk = async (params, _ctx) => {
|
|
|
44053
45143
|
// src/agent-rpc/handlers.ts
|
|
44054
45144
|
init_protocol2();
|
|
44055
45145
|
function presentArtifactResult(input) {
|
|
44056
|
-
const id = input.artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${(0,
|
|
45146
|
+
const id = input.artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${(0, import_node_crypto28.randomUUID)().slice(0, 8)}`;
|
|
44057
45147
|
return {
|
|
44058
45148
|
ok: true,
|
|
44059
45149
|
artifact_id: id,
|
|
@@ -44078,7 +45168,7 @@ function invalidParams2(message) {
|
|
|
44078
45168
|
function jobCwd(rec) {
|
|
44079
45169
|
const raw = str7(rec.cwd).trim();
|
|
44080
45170
|
if (!raw) throw invalidParams2("cwd is required");
|
|
44081
|
-
if (!(0,
|
|
45171
|
+
if (!(0, import_node_path71.isAbsolute)(raw)) throw invalidParams2("cwd must be an absolute path");
|
|
44082
45172
|
return raw;
|
|
44083
45173
|
}
|
|
44084
45174
|
async function handleRuntimePing(_params, _ctx) {
|
|
@@ -44211,27 +45301,27 @@ init_gh_errors();
|
|
|
44211
45301
|
init_git_auth_mode();
|
|
44212
45302
|
|
|
44213
45303
|
// src/board/load-home-board.ts
|
|
44214
|
-
var
|
|
44215
|
-
var
|
|
45304
|
+
var import_node_fs74 = require("fs");
|
|
45305
|
+
var import_node_path73 = require("path");
|
|
44216
45306
|
init_worktree();
|
|
44217
45307
|
init_paths();
|
|
44218
45308
|
|
|
44219
45309
|
// src/board/board-pins.ts
|
|
44220
|
-
var
|
|
44221
|
-
var
|
|
44222
|
-
var
|
|
45310
|
+
var import_node_crypto29 = require("crypto");
|
|
45311
|
+
var import_node_fs73 = require("fs");
|
|
45312
|
+
var import_node_path72 = require("path");
|
|
44223
45313
|
init_paths();
|
|
44224
45314
|
init_home_board();
|
|
44225
45315
|
var FILE = "home-board-pins.json";
|
|
44226
45316
|
var VERSION = 1;
|
|
44227
45317
|
function pinsFile() {
|
|
44228
|
-
return (0,
|
|
45318
|
+
return (0, import_node_path72.join)(appDataDir(), FILE);
|
|
44229
45319
|
}
|
|
44230
45320
|
function readDisk() {
|
|
44231
45321
|
const path2 = pinsFile();
|
|
44232
|
-
if (!(0,
|
|
45322
|
+
if (!(0, import_node_fs73.existsSync)(path2)) return [];
|
|
44233
45323
|
try {
|
|
44234
|
-
const raw = JSON.parse((0,
|
|
45324
|
+
const raw = JSON.parse((0, import_node_fs73.readFileSync)(path2, "utf8"));
|
|
44235
45325
|
if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
|
|
44236
45326
|
return raw.items.filter((item) => item?.id && item.kind && item.ref);
|
|
44237
45327
|
} catch {
|
|
@@ -44239,8 +45329,8 @@ function readDisk() {
|
|
|
44239
45329
|
}
|
|
44240
45330
|
}
|
|
44241
45331
|
function writeDisk(items) {
|
|
44242
|
-
(0,
|
|
44243
|
-
(0,
|
|
45332
|
+
(0, import_node_fs73.mkdirSync)(appDataDir(), { recursive: true });
|
|
45333
|
+
(0, import_node_fs73.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
|
|
44244
45334
|
}
|
|
44245
45335
|
function listBoardPins() {
|
|
44246
45336
|
return readDisk();
|
|
@@ -44249,7 +45339,7 @@ function addBoardPin(input) {
|
|
|
44249
45339
|
const ref = input.ref.trim();
|
|
44250
45340
|
if (!ref) throw new Error("Board item needs a ref");
|
|
44251
45341
|
const pin = {
|
|
44252
|
-
id: (0,
|
|
45342
|
+
id: (0, import_node_crypto29.randomUUID)(),
|
|
44253
45343
|
kind: input.kind,
|
|
44254
45344
|
ref,
|
|
44255
45345
|
repoPath: input.repoPath.trim(),
|
|
@@ -44292,7 +45382,7 @@ function replaceBoardPins(items) {
|
|
|
44292
45382
|
}
|
|
44293
45383
|
function clearBoardPins() {
|
|
44294
45384
|
try {
|
|
44295
|
-
(0,
|
|
45385
|
+
(0, import_node_fs73.unlinkSync)(pinsFile());
|
|
44296
45386
|
} catch {
|
|
44297
45387
|
}
|
|
44298
45388
|
}
|
|
@@ -44309,7 +45399,7 @@ function homeBoardWorkspaceKey(workspaces) {
|
|
|
44309
45399
|
return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
|
|
44310
45400
|
}
|
|
44311
45401
|
function cacheFile() {
|
|
44312
|
-
return (0,
|
|
45402
|
+
return (0, import_node_path73.join)(appDataDir(), "home-board-cache.json");
|
|
44313
45403
|
}
|
|
44314
45404
|
function emptyInputs() {
|
|
44315
45405
|
return {
|
|
@@ -44335,9 +45425,9 @@ function shouldCacheHomeBoardInputs(inputs) {
|
|
|
44335
45425
|
}
|
|
44336
45426
|
function readDiskCache() {
|
|
44337
45427
|
const path2 = cacheFile();
|
|
44338
|
-
if (!(0,
|
|
45428
|
+
if (!(0, import_node_fs74.existsSync)(path2)) return null;
|
|
44339
45429
|
try {
|
|
44340
|
-
const raw = JSON.parse((0,
|
|
45430
|
+
const raw = JSON.parse((0, import_node_fs74.readFileSync)(path2, "utf8"));
|
|
44341
45431
|
if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
|
|
44342
45432
|
return null;
|
|
44343
45433
|
}
|
|
@@ -44351,14 +45441,14 @@ function readDiskCache() {
|
|
|
44351
45441
|
}
|
|
44352
45442
|
function writeDiskCache(entry) {
|
|
44353
45443
|
try {
|
|
44354
|
-
(0,
|
|
44355
|
-
(0,
|
|
45444
|
+
(0, import_node_fs74.mkdirSync)(appDataDir(), { recursive: true });
|
|
45445
|
+
(0, import_node_fs74.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
|
|
44356
45446
|
} catch {
|
|
44357
45447
|
}
|
|
44358
45448
|
}
|
|
44359
45449
|
function deleteDiskCache() {
|
|
44360
45450
|
try {
|
|
44361
|
-
(0,
|
|
45451
|
+
(0, import_node_fs74.unlinkSync)(cacheFile());
|
|
44362
45452
|
} catch {
|
|
44363
45453
|
}
|
|
44364
45454
|
}
|
|
@@ -44543,13 +45633,13 @@ async function startMcpServer() {
|
|
|
44543
45633
|
if (!worktreeProfile) {
|
|
44544
45634
|
server.tool(
|
|
44545
45635
|
"list_projects",
|
|
44546
|
-
"List registered projects (git repos). Each line is name, path,
|
|
45636
|
+
"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.",
|
|
44547
45637
|
{},
|
|
44548
45638
|
async () => {
|
|
44549
45639
|
const workspaces = orch.listWorkspaces();
|
|
44550
45640
|
const lines = await Promise.all(
|
|
44551
45641
|
workspaces.map(async (w) => {
|
|
44552
|
-
const
|
|
45642
|
+
const tag = await resolveProjectRemoteTag(w.path).catch(() => null);
|
|
44553
45643
|
let profile;
|
|
44554
45644
|
try {
|
|
44555
45645
|
profile = resolveViewerProfileForRepo(w.path);
|
|
@@ -44557,7 +45647,7 @@ async function startMcpServer() {
|
|
|
44557
45647
|
profile = resolveViewerProfile();
|
|
44558
45648
|
}
|
|
44559
45649
|
const suffix = formatWorkspaceProfileSuffix(profile);
|
|
44560
|
-
return
|
|
45650
|
+
return tag ? `${w.name} ${w.path} ${tag}${suffix}` : `${w.name} ${w.path}${suffix}`;
|
|
44561
45651
|
})
|
|
44562
45652
|
);
|
|
44563
45653
|
return {
|
|
@@ -44574,7 +45664,7 @@ async function startMcpServer() {
|
|
|
44574
45664
|
async () => {
|
|
44575
45665
|
const threads = orch.getThreads();
|
|
44576
45666
|
const lines = threads.map((t) => {
|
|
44577
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID2 ? "Orchestration" : (0,
|
|
45667
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID2 ? "Orchestration" : (0, import_node_path74.basename)(t.repoPath) || t.repoPath;
|
|
44578
45668
|
const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
|
|
44579
45669
|
const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
|
|
44580
45670
|
const preview = lastMessagePreview(t.messages, 80);
|
|
@@ -45182,7 +46272,7 @@ async function startMcpServer() {
|
|
|
45182
46272
|
const ident = issue?.identifier ?? ref.trim();
|
|
45183
46273
|
const attachments = issue ? [
|
|
45184
46274
|
{
|
|
45185
|
-
id: (0,
|
|
46275
|
+
id: (0, import_node_crypto30.randomUUID)(),
|
|
45186
46276
|
name: issue.identifier,
|
|
45187
46277
|
kind: "issue",
|
|
45188
46278
|
content: [
|
|
@@ -45404,7 +46494,7 @@ async function startMcpServer() {
|
|
|
45404
46494
|
error: true,
|
|
45405
46495
|
action,
|
|
45406
46496
|
lastError: message,
|
|
45407
|
-
hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_chat so the worktree agent
|
|
46497
|
+
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
|
|
45408
46498
|
},
|
|
45409
46499
|
true
|
|
45410
46500
|
);
|
|
@@ -45714,7 +46804,7 @@ async function startMcpServer() {
|
|
|
45714
46804
|
);
|
|
45715
46805
|
server.tool(
|
|
45716
46806
|
"list_issues",
|
|
45717
|
-
"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.",
|
|
46807
|
+
"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.",
|
|
45718
46808
|
{
|
|
45719
46809
|
repoPath: import_zod11.z.string(),
|
|
45720
46810
|
query: import_zod11.z.string().optional().describe("Search title, identifier, or description"),
|
|
@@ -45744,7 +46834,7 @@ init_protocol2();
|
|
|
45744
46834
|
init_metadata();
|
|
45745
46835
|
|
|
45746
46836
|
// src/agent-rpc/server.ts
|
|
45747
|
-
var
|
|
46837
|
+
var import_node_crypto31 = require("crypto");
|
|
45748
46838
|
var import_node_http6 = require("http");
|
|
45749
46839
|
var import_ws5 = require("ws");
|
|
45750
46840
|
init_protocol2();
|
|
@@ -45753,7 +46843,7 @@ function tokensEqual(a, b) {
|
|
|
45753
46843
|
const left = Buffer.from(a);
|
|
45754
46844
|
const right = Buffer.from(b);
|
|
45755
46845
|
if (left.length !== right.length) return false;
|
|
45756
|
-
return (0,
|
|
46846
|
+
return (0, import_node_crypto31.timingSafeEqual)(left, right);
|
|
45757
46847
|
}
|
|
45758
46848
|
function authTokenFromUpgrade(req) {
|
|
45759
46849
|
try {
|
|
@@ -45786,9 +46876,9 @@ var AgentRpcServer = class {
|
|
|
45786
46876
|
async listen(opts = {}) {
|
|
45787
46877
|
const host = opts.host ?? "127.0.0.1";
|
|
45788
46878
|
const port = opts.port ?? 0;
|
|
45789
|
-
const authToken = (0,
|
|
46879
|
+
const authToken = (0, import_node_crypto31.randomBytes)(24).toString("base64url");
|
|
45790
46880
|
this.meta = {
|
|
45791
|
-
runtimeId: (0,
|
|
46881
|
+
runtimeId: (0, import_node_crypto31.randomUUID)(),
|
|
45792
46882
|
pid: process.pid,
|
|
45793
46883
|
protocolVersion: AGENT_RPC_PROTOCOL_VERSION,
|
|
45794
46884
|
authToken,
|
|
@@ -46587,11 +47677,11 @@ init_model_context();
|
|
|
46587
47677
|
init_meta();
|
|
46588
47678
|
|
|
46589
47679
|
// src/slack/workspaces.ts
|
|
46590
|
-
var
|
|
47680
|
+
var import_node_path75 = require("path");
|
|
46591
47681
|
init_paths();
|
|
46592
47682
|
init_secure_file();
|
|
46593
47683
|
function storePath2() {
|
|
46594
|
-
return (0,
|
|
47684
|
+
return (0, import_node_path75.join)(appDataDir(), "slack-workspaces.json");
|
|
46595
47685
|
}
|
|
46596
47686
|
function readStore2() {
|
|
46597
47687
|
try {
|
|
@@ -46682,7 +47772,7 @@ function slackTokenFor(ws, kind = "read") {
|
|
|
46682
47772
|
}
|
|
46683
47773
|
|
|
46684
47774
|
// src/slack/oauth.ts
|
|
46685
|
-
var
|
|
47775
|
+
var import_node_crypto32 = require("crypto");
|
|
46686
47776
|
init_app_settings();
|
|
46687
47777
|
var SLACK_BOT_SCOPES = [
|
|
46688
47778
|
"app_mentions:read",
|
|
@@ -46776,7 +47866,7 @@ async function startSlackOAuth(opts) {
|
|
|
46776
47866
|
throw new SlackOAuthCancelledError();
|
|
46777
47867
|
}
|
|
46778
47868
|
const { clientId } = slackOAuthCredentials();
|
|
46779
|
-
const state = (0,
|
|
47869
|
+
const state = (0, import_node_crypto32.randomBytes)(16).toString("hex");
|
|
46780
47870
|
const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
|
|
46781
47871
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
46782
47872
|
const pollIntervalMs = opts?.pollIntervalMs ?? 400;
|
|
@@ -46838,19 +47928,19 @@ init_turn_live();
|
|
|
46838
47928
|
init_thread_store();
|
|
46839
47929
|
|
|
46840
47930
|
// src/slack/reply-target.ts
|
|
46841
|
-
var
|
|
46842
|
-
var
|
|
47931
|
+
var import_node_fs75 = require("fs");
|
|
47932
|
+
var import_node_path76 = require("path");
|
|
46843
47933
|
init_paths();
|
|
46844
47934
|
init_private_file();
|
|
46845
47935
|
init_secure_file();
|
|
46846
47936
|
function storePath3() {
|
|
46847
|
-
return (0,
|
|
47937
|
+
return (0, import_node_path76.join)(appDataDir(), "slack-reply-to.json");
|
|
46848
47938
|
}
|
|
46849
47939
|
function readStore3() {
|
|
46850
47940
|
const path2 = storePath3();
|
|
46851
|
-
if (!(0,
|
|
47941
|
+
if (!(0, import_node_fs75.existsSync)(path2)) return {};
|
|
46852
47942
|
try {
|
|
46853
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
47943
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs75.readFileSync)(path2, "utf8"));
|
|
46854
47944
|
return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
|
|
46855
47945
|
} catch {
|
|
46856
47946
|
return {};
|
|
@@ -47685,7 +48775,7 @@ function resolveSlackListenMode(opts) {
|
|
|
47685
48775
|
init_protocol();
|
|
47686
48776
|
|
|
47687
48777
|
// src/relay/account-login.ts
|
|
47688
|
-
var
|
|
48778
|
+
var import_node_crypto33 = require("crypto");
|
|
47689
48779
|
init_fetch();
|
|
47690
48780
|
init_protocol();
|
|
47691
48781
|
var RemoteAccountLoginCancelled = class extends Error {
|
|
@@ -47740,7 +48830,7 @@ async function relayFetch(fetchImpl, url, init) {
|
|
|
47740
48830
|
throw relayFetchError(err, url);
|
|
47741
48831
|
}
|
|
47742
48832
|
}
|
|
47743
|
-
async function
|
|
48833
|
+
async function readJson5(res, url) {
|
|
47744
48834
|
try {
|
|
47745
48835
|
return await res.json();
|
|
47746
48836
|
} catch {
|
|
@@ -47753,7 +48843,7 @@ async function readJson4(res, url) {
|
|
|
47753
48843
|
async function startRemoteAccountLogin(opts) {
|
|
47754
48844
|
if (opts.signal?.aborted) throw new RemoteAccountLoginCancelled();
|
|
47755
48845
|
const origin = (opts.origin ?? remoteAccountHttpOrigin()).replace(/\/+$/, "");
|
|
47756
|
-
const state = (0,
|
|
48846
|
+
const state = (0, import_node_crypto33.randomBytes)(16).toString("hex");
|
|
47757
48847
|
const timeoutMs = opts.timeoutMs ?? 5 * 6e4;
|
|
47758
48848
|
const pollIntervalMs = opts.pollIntervalMs ?? 400;
|
|
47759
48849
|
const linkToken = opts.linkToken?.trim() ?? "";
|
|
@@ -47767,7 +48857,7 @@ async function startRemoteAccountLogin(opts) {
|
|
|
47767
48857
|
...linkToken ? { accountToken: linkToken } : {}
|
|
47768
48858
|
})
|
|
47769
48859
|
});
|
|
47770
|
-
const startBody = await
|
|
48860
|
+
const startBody = await readJson5(started, startUrl);
|
|
47771
48861
|
if (!started.ok || !startBody.url) {
|
|
47772
48862
|
throw new Error(startBody.error || `Could not start sign-in (HTTP ${started.status}).`);
|
|
47773
48863
|
}
|
|
@@ -47815,8 +48905,8 @@ async function disconnectRemoteAccount(opts) {
|
|
|
47815
48905
|
}
|
|
47816
48906
|
|
|
47817
48907
|
// src/slack/outbound-watch.ts
|
|
47818
|
-
var
|
|
47819
|
-
var
|
|
48908
|
+
var import_node_fs76 = require("fs");
|
|
48909
|
+
var import_node_path77 = require("path");
|
|
47820
48910
|
init_paths();
|
|
47821
48911
|
init_private_file();
|
|
47822
48912
|
init_secure_file();
|
|
@@ -47829,7 +48919,7 @@ var POLL_INTERVAL_MS = 12e3;
|
|
|
47829
48919
|
var lastPollMs = 0;
|
|
47830
48920
|
var nameCache = /* @__PURE__ */ new Map();
|
|
47831
48921
|
function storePath4() {
|
|
47832
|
-
return (0,
|
|
48922
|
+
return (0, import_node_path77.join)(appDataDir(), "slack-outbound-watch.json");
|
|
47833
48923
|
}
|
|
47834
48924
|
function watchId(teamId, channelId, ts) {
|
|
47835
48925
|
return `${teamId}:${channelId}:${ts}`;
|
|
@@ -47842,9 +48932,9 @@ function tsNewer(a, b) {
|
|
|
47842
48932
|
}
|
|
47843
48933
|
function readStore4() {
|
|
47844
48934
|
const path2 = storePath4();
|
|
47845
|
-
if (!(0,
|
|
48935
|
+
if (!(0, import_node_fs76.existsSync)(path2)) return [];
|
|
47846
48936
|
try {
|
|
47847
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
48937
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs76.readFileSync)(path2, "utf8"));
|
|
47848
48938
|
return Array.isArray(parsed?.watches) ? parsed.watches : [];
|
|
47849
48939
|
} catch {
|
|
47850
48940
|
return [];
|
|
@@ -48211,12 +49301,14 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48211
49301
|
CONTEXT_REVIEW_PATH,
|
|
48212
49302
|
CONVENTION_SETUP_RELPATHS,
|
|
48213
49303
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
49304
|
+
CURSOR_ISSUES_UNAVAILABLE,
|
|
48214
49305
|
CURSOR_SDK_INSTALL_HINT,
|
|
48215
49306
|
DEFAULT_ABLETIME_HOST,
|
|
48216
49307
|
DEFAULT_RUN_LOG_TAIL_CHARS,
|
|
48217
49308
|
DEFAULT_WORKTREE_SORT,
|
|
48218
49309
|
DETACHED_JOBS_DIR,
|
|
48219
49310
|
EMPTY_MANAGED_ACCOUNTS,
|
|
49311
|
+
ENTIRE_ISSUES_ARE_TRAILS,
|
|
48220
49312
|
FAMOUS_SOCCER_TEAMS,
|
|
48221
49313
|
FOLLOW_UP_BEHAVIORS,
|
|
48222
49314
|
GITHUB_GIT_AUTH_MODES,
|
|
@@ -48484,6 +49576,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48484
49576
|
createThreadWorktree,
|
|
48485
49577
|
currentBranch,
|
|
48486
49578
|
cursorAdapter,
|
|
49579
|
+
cursorIssuesUnavailableReason,
|
|
48487
49580
|
cursorSdkMessageToEvents,
|
|
48488
49581
|
decodeBrightsyTarget,
|
|
48489
49582
|
defaultScheduleName,
|
|
@@ -48533,6 +49626,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48533
49626
|
ensureSlackCoordinator,
|
|
48534
49627
|
ensureSlackDeviceIdentity,
|
|
48535
49628
|
ensureWorkspace,
|
|
49629
|
+
entireUsesTrails,
|
|
48536
49630
|
estimateMessageChars,
|
|
48537
49631
|
estimateOccupancyTokens,
|
|
48538
49632
|
estimateThreadChars,
|
|
@@ -48583,8 +49677,10 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48583
49677
|
formatClaudeUsageTooltip,
|
|
48584
49678
|
formatCloudTurnReply,
|
|
48585
49679
|
formatConnectedOrchestratorReminder,
|
|
49680
|
+
formatCursorGitDirective,
|
|
48586
49681
|
formatDetachedJobInvoke,
|
|
48587
49682
|
formatDevAccessHint,
|
|
49683
|
+
formatEntireGitDirective,
|
|
48588
49684
|
formatFetchError,
|
|
48589
49685
|
formatGhLandError,
|
|
48590
49686
|
formatGitAuthModeDirective,
|
|
@@ -48641,6 +49737,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48641
49737
|
getBrightsySession,
|
|
48642
49738
|
getCaffeinateHold,
|
|
48643
49739
|
getClaudePlanUsage,
|
|
49740
|
+
getCursorGitStatus,
|
|
48644
49741
|
getDefaultAgent,
|
|
48645
49742
|
getDefaultAutonomy,
|
|
48646
49743
|
getDefaultEffort,
|
|
@@ -48649,6 +49746,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48649
49746
|
getDefaultRunScript,
|
|
48650
49747
|
getDiff,
|
|
48651
49748
|
getDiffSummary,
|
|
49749
|
+
getEntireGitStatus,
|
|
48652
49750
|
getGitHubIssue,
|
|
48653
49751
|
getGitHubStatus,
|
|
48654
49752
|
getGithubGitAuthMode,
|
|
@@ -48866,6 +49964,8 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48866
49964
|
localhostPreviewUrl,
|
|
48867
49965
|
locksDir,
|
|
48868
49966
|
loginAgent,
|
|
49967
|
+
loginCursorGit,
|
|
49968
|
+
loginEntireGit,
|
|
48869
49969
|
loginEnvPrefix,
|
|
48870
49970
|
loginManagedAccount,
|
|
48871
49971
|
looksLikeComposerSkillExpansion,
|
|
@@ -48932,6 +50032,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48932
50032
|
orchestrationQuotaOnLimit,
|
|
48933
50033
|
orchestrationTitleNeedsSoccerNickname,
|
|
48934
50034
|
orchestratorSessionPoisonedByBuiltins,
|
|
50035
|
+
originCli,
|
|
48935
50036
|
originFetchBranch,
|
|
48936
50037
|
originGhRepoEnv,
|
|
48937
50038
|
outboundReplyFromTurn,
|
|
@@ -48942,11 +50043,13 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48942
50043
|
parseCursorRunnerLine,
|
|
48943
50044
|
parseDevPreview,
|
|
48944
50045
|
parseDurationMs,
|
|
50046
|
+
parseEntireAuthContexts,
|
|
48945
50047
|
parseForceStopMessage,
|
|
48946
50048
|
parseGhStackViewJson,
|
|
48947
50049
|
parseGitHubIssueNumber,
|
|
48948
50050
|
parseGithubSlugFromRemoteUrl,
|
|
48949
50051
|
parseMcpList,
|
|
50052
|
+
parseOriginAuthStatus,
|
|
48950
50053
|
parsePlanQuestionsInput,
|
|
48951
50054
|
parsePrDetailsView,
|
|
48952
50055
|
parseSessionQuotaResetAt,
|
|
@@ -49049,9 +50152,11 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
49049
50152
|
resolveNewThreadOptions,
|
|
49050
50153
|
resolveOrchChildFollowUp,
|
|
49051
50154
|
resolveOrchestratorDefaults,
|
|
50155
|
+
resolveOriginRemote,
|
|
49052
50156
|
resolvePlanMarkdown,
|
|
49053
50157
|
resolvePrSelector,
|
|
49054
50158
|
resolvePrSelectors,
|
|
50159
|
+
resolveProjectRemoteTag,
|
|
49055
50160
|
resolveProjectReviewLabel,
|
|
49056
50161
|
resolveQuotaFallbackAgent,
|
|
49057
50162
|
resolveRepoRoot,
|
|
@@ -49102,6 +50207,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
49102
50207
|
setStatus,
|
|
49103
50208
|
setVaultMasterKey,
|
|
49104
50209
|
settingsSourceLabel,
|
|
50210
|
+
setupCursorGit,
|
|
49105
50211
|
shiftQueuedItem,
|
|
49106
50212
|
shouldAttachPastedText,
|
|
49107
50213
|
shouldCompactContext,
|