@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/mcp/run-stdio.cjs
CHANGED
|
@@ -2541,6 +2541,7 @@ var run_exports = {};
|
|
|
2541
2541
|
__export(run_exports, {
|
|
2542
2542
|
gh: () => gh,
|
|
2543
2543
|
git: () => git,
|
|
2544
|
+
originCli: () => originCli,
|
|
2544
2545
|
resolveGhAuthToken: () => resolveGhAuthToken,
|
|
2545
2546
|
resolveGitDirsForLockRecovery: () => resolveGitDirsForLockRecovery,
|
|
2546
2547
|
run: () => run
|
|
@@ -2621,6 +2622,17 @@ ${result.stderr}`
|
|
|
2621
2622
|
}
|
|
2622
2623
|
return result;
|
|
2623
2624
|
}
|
|
2625
|
+
async function originCli(args, cwd, opts) {
|
|
2626
|
+
return run("origin", args, {
|
|
2627
|
+
cwd,
|
|
2628
|
+
reject: opts?.reject,
|
|
2629
|
+
timeoutMs: opts?.timeoutMs,
|
|
2630
|
+
env: {
|
|
2631
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
2632
|
+
NO_COLOR: "1"
|
|
2633
|
+
}
|
|
2634
|
+
});
|
|
2635
|
+
}
|
|
2624
2636
|
async function gh(args, cwd, opts) {
|
|
2625
2637
|
return run("gh", args, {
|
|
2626
2638
|
cwd,
|
|
@@ -6528,9 +6540,9 @@ var init_app_settings = __esm({
|
|
|
6528
6540
|
});
|
|
6529
6541
|
|
|
6530
6542
|
// src/git/git-auth-mode.ts
|
|
6531
|
-
function githubHttpsInsteadOfEntries(
|
|
6543
|
+
function githubHttpsInsteadOfEntries(remoteUrl2) {
|
|
6532
6544
|
const entries = [...HTTPS_REWRITE];
|
|
6533
|
-
const url =
|
|
6545
|
+
const url = remoteUrl2?.trim() ?? "";
|
|
6534
6546
|
const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
|
|
6535
6547
|
if (scpAlias?.[1]) {
|
|
6536
6548
|
entries.push({
|
|
@@ -6737,6 +6749,58 @@ var init_git_auth_mode = __esm({
|
|
|
6737
6749
|
}
|
|
6738
6750
|
});
|
|
6739
6751
|
|
|
6752
|
+
// src/git/remote-forge.ts
|
|
6753
|
+
function formatRemoteTag(remote) {
|
|
6754
|
+
const name = remote.forge === "other" ? remote.host : remote.forge;
|
|
6755
|
+
return `${name}:${remote.slug}`;
|
|
6756
|
+
}
|
|
6757
|
+
function forgeForHost(host) {
|
|
6758
|
+
const h = host.toLowerCase();
|
|
6759
|
+
if (h === "github.com" || h.startsWith("github.com-")) return "github";
|
|
6760
|
+
if (h === "origin.cursor.com") return "cursor";
|
|
6761
|
+
if (h === "entire.io" || h.endsWith(".entire.io") || h === "entire.com" || h.endsWith(".entire.com")) {
|
|
6762
|
+
return "entire";
|
|
6763
|
+
}
|
|
6764
|
+
return "other";
|
|
6765
|
+
}
|
|
6766
|
+
function repoFromParts(host, owner, name) {
|
|
6767
|
+
if (!host || !owner || !name || owner.includes("@")) return null;
|
|
6768
|
+
const normalized = host.toLowerCase();
|
|
6769
|
+
return {
|
|
6770
|
+
forge: forgeForHost(normalized),
|
|
6771
|
+
host: normalized,
|
|
6772
|
+
slug: `${owner}/${name}`
|
|
6773
|
+
};
|
|
6774
|
+
}
|
|
6775
|
+
function parseRemoteRepo(url) {
|
|
6776
|
+
const trimmed = url.trim().replace(/\.git$/i, "");
|
|
6777
|
+
if (!trimmed) return null;
|
|
6778
|
+
if (trimmed.toLowerCase().startsWith("entire://")) {
|
|
6779
|
+
const parts = trimmed.slice("entire://".length).replace(/^\/+/, "").split("/").filter(Boolean);
|
|
6780
|
+
if (parts.length === 2) return { forge: "entire", host: "entire.io", slug: `${parts[0]}/${parts[1]}` };
|
|
6781
|
+
if (parts.length >= 3) {
|
|
6782
|
+
return repoFromParts(parts[0], parts[1], parts[2]);
|
|
6783
|
+
}
|
|
6784
|
+
return null;
|
|
6785
|
+
}
|
|
6786
|
+
const ssh = trimmed.match(/^git@([^:]+):([^/]+)\/([^/]+)$/i);
|
|
6787
|
+
if (ssh?.[1] && ssh[2] && ssh[3]) return repoFromParts(ssh[1], ssh[2], ssh[3]);
|
|
6788
|
+
try {
|
|
6789
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
6790
|
+
const parsed = new URL(withScheme);
|
|
6791
|
+
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
6792
|
+
if (parts.length < 2) return null;
|
|
6793
|
+
return repoFromParts(parsed.hostname, parts[parts.length - 2], parts[parts.length - 1]);
|
|
6794
|
+
} catch {
|
|
6795
|
+
return null;
|
|
6796
|
+
}
|
|
6797
|
+
}
|
|
6798
|
+
var init_remote_forge = __esm({
|
|
6799
|
+
"src/git/remote-forge.ts"() {
|
|
6800
|
+
"use strict";
|
|
6801
|
+
}
|
|
6802
|
+
});
|
|
6803
|
+
|
|
6740
6804
|
// src/git/list-prs.ts
|
|
6741
6805
|
function normalizePrListState(state) {
|
|
6742
6806
|
const key = (state ?? "").trim().toLowerCase();
|
|
@@ -7105,42 +7169,6 @@ var init_list_prs = __esm({
|
|
|
7105
7169
|
}
|
|
7106
7170
|
});
|
|
7107
7171
|
|
|
7108
|
-
// src/util/enqueue-by-key.ts
|
|
7109
|
-
function enqueueByKey(key, fn) {
|
|
7110
|
-
const prev = tails.get(key) ?? Promise.resolve();
|
|
7111
|
-
const next = prev.then(fn, fn);
|
|
7112
|
-
tails.set(
|
|
7113
|
-
key,
|
|
7114
|
-
next.then(
|
|
7115
|
-
() => void 0,
|
|
7116
|
-
() => void 0
|
|
7117
|
-
)
|
|
7118
|
-
);
|
|
7119
|
-
return next;
|
|
7120
|
-
}
|
|
7121
|
-
var tails;
|
|
7122
|
-
var init_enqueue_by_key = __esm({
|
|
7123
|
-
"src/util/enqueue-by-key.ts"() {
|
|
7124
|
-
"use strict";
|
|
7125
|
-
tails = /* @__PURE__ */ new Map();
|
|
7126
|
-
}
|
|
7127
|
-
});
|
|
7128
|
-
|
|
7129
|
-
// src/git/repo-git-lock.ts
|
|
7130
|
-
function repoLockKey(repoPath) {
|
|
7131
|
-
const trimmed = repoPath.replace(/\/+$/, "");
|
|
7132
|
-
return `git-worktree:${trimmed || "/"}`;
|
|
7133
|
-
}
|
|
7134
|
-
function withRepoGitLock(repoPath, fn) {
|
|
7135
|
-
return enqueueByKey(repoLockKey(repoPath), fn);
|
|
7136
|
-
}
|
|
7137
|
-
var init_repo_git_lock = __esm({
|
|
7138
|
-
"src/git/repo-git-lock.ts"() {
|
|
7139
|
-
"use strict";
|
|
7140
|
-
init_enqueue_by_key();
|
|
7141
|
-
}
|
|
7142
|
-
});
|
|
7143
|
-
|
|
7144
7172
|
// src/git/pr-gates.ts
|
|
7145
7173
|
function prIsInMergeQueue(gate) {
|
|
7146
7174
|
if (gate.isInMergeQueue) return true;
|
|
@@ -7273,6 +7301,381 @@ var init_pr_gates = __esm({
|
|
|
7273
7301
|
}
|
|
7274
7302
|
});
|
|
7275
7303
|
|
|
7304
|
+
// src/git/cursor-pr.ts
|
|
7305
|
+
function repoArgs(slug) {
|
|
7306
|
+
return ["-R", slug];
|
|
7307
|
+
}
|
|
7308
|
+
function cursorHeadBranch(head, slug) {
|
|
7309
|
+
const branch = head.trim().replace(/^refs\/heads\//, "");
|
|
7310
|
+
const owner = slug.split("/")[0];
|
|
7311
|
+
if (owner && branch.startsWith(`${owner}:`)) return branch.slice(owner.length + 1);
|
|
7312
|
+
return branch;
|
|
7313
|
+
}
|
|
7314
|
+
function cursorMergeFields(value) {
|
|
7315
|
+
if (typeof value === "string" && value.trim()) {
|
|
7316
|
+
const upper = value.trim().toUpperCase();
|
|
7317
|
+
return { mergeable: upper, mergeStateStatus: upper };
|
|
7318
|
+
}
|
|
7319
|
+
if (value && typeof value === "object") {
|
|
7320
|
+
const row = value;
|
|
7321
|
+
const conflictState = String(row.mergeConflictState ?? "").trim().toUpperCase();
|
|
7322
|
+
if ("hasMergeConflicts" in row || conflictState) {
|
|
7323
|
+
if (conflictState.includes("PENDING")) {
|
|
7324
|
+
return { mergeable: "UNKNOWN", mergeStateStatus: "UNKNOWN" };
|
|
7325
|
+
}
|
|
7326
|
+
const conflicting = row.hasMergeConflicts === true || conflictState.includes("CONFLICT") && !conflictState.includes("CLEAN");
|
|
7327
|
+
if (conflicting) return { mergeable: "CONFLICTING", mergeStateStatus: "DIRTY" };
|
|
7328
|
+
if (row.hasMergeConflicts === false || conflictState.includes("CLEAN")) {
|
|
7329
|
+
return { mergeable: "MERGEABLE", mergeStateStatus: "CLEAN" };
|
|
7330
|
+
}
|
|
7331
|
+
}
|
|
7332
|
+
const verdict = String(row.verdict ?? row.verdictKind ?? "").trim().toUpperCase();
|
|
7333
|
+
if (verdict === "BLOCKED") return { mergeable: null, mergeStateStatus: "BLOCKED" };
|
|
7334
|
+
if (verdict === "MERGEABLE") return { mergeable: "MERGEABLE", mergeStateStatus: "CLEAN" };
|
|
7335
|
+
const status = String(row.status ?? row.state ?? row.mergeable ?? "").trim().toUpperCase();
|
|
7336
|
+
return { mergeable: status || null, mergeStateStatus: status || null };
|
|
7337
|
+
}
|
|
7338
|
+
return { mergeable: null, mergeStateStatus: null };
|
|
7339
|
+
}
|
|
7340
|
+
function cursorReviewDecision(value) {
|
|
7341
|
+
const raw = typeof value === "string" ? value.trim().toUpperCase().replace(/[\s-]+/g, "_") : "";
|
|
7342
|
+
if (!raw) return null;
|
|
7343
|
+
if (raw === "REQUIRED" || raw === "REVIEW_REQUIRED") return "REVIEW_REQUIRED";
|
|
7344
|
+
if (raw === "CHANGES_REQUESTED") return "CHANGES_REQUESTED";
|
|
7345
|
+
if (raw === "APPROVED") return "APPROVED";
|
|
7346
|
+
return raw;
|
|
7347
|
+
}
|
|
7348
|
+
function cursorViewToPrMeta(view) {
|
|
7349
|
+
const merge = cursorMergeFields(view.mergeability ?? view.mergeable);
|
|
7350
|
+
const author = view.author ?? {};
|
|
7351
|
+
return {
|
|
7352
|
+
number: Number(view.number),
|
|
7353
|
+
title: String(view.title ?? ""),
|
|
7354
|
+
url: String(view.url ?? ""),
|
|
7355
|
+
state: String(view.state ?? ""),
|
|
7356
|
+
isDraft: Boolean(view.isDraft),
|
|
7357
|
+
reviewDecision: cursorReviewDecision(view.reviewDecision),
|
|
7358
|
+
baseRefName: String(view.baseRefName ?? ""),
|
|
7359
|
+
headRefName: String(view.headRefName ?? ""),
|
|
7360
|
+
isInMergeQueue: false,
|
|
7361
|
+
mergeable: merge.mergeable,
|
|
7362
|
+
mergeStateStatus: merge.mergeStateStatus,
|
|
7363
|
+
authorLogin: author.login?.trim() || null,
|
|
7364
|
+
reviewerLogins: [],
|
|
7365
|
+
labels: labelNames(view.labels)
|
|
7366
|
+
};
|
|
7367
|
+
}
|
|
7368
|
+
function loginOf(author) {
|
|
7369
|
+
if (!author || typeof author !== "object") return "";
|
|
7370
|
+
const row = author;
|
|
7371
|
+
for (const key of ["login", "handle", "email", "displayName", "name", "id"]) {
|
|
7372
|
+
const value = row[key];
|
|
7373
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
7374
|
+
}
|
|
7375
|
+
return "";
|
|
7376
|
+
}
|
|
7377
|
+
function upperState(value, isDraft) {
|
|
7378
|
+
const raw = typeof value === "string" ? value.trim().toUpperCase() : "";
|
|
7379
|
+
if (raw === "DRAFT") return "OPEN";
|
|
7380
|
+
if (raw === "OPEN" || raw === "CLOSED" || raw === "MERGED") return raw;
|
|
7381
|
+
return isDraft ? "OPEN" : raw;
|
|
7382
|
+
}
|
|
7383
|
+
function normalizeOriginPr(raw) {
|
|
7384
|
+
const isDraft = raw.isDraft === true || String(raw.status ?? raw.state ?? "").toLowerCase() === "draft";
|
|
7385
|
+
const login = loginOf(raw.author);
|
|
7386
|
+
const author = raw.author && typeof raw.author === "object" ? { ...raw.author, login: login || "unknown" } : login ? { login } : { login: "unknown" };
|
|
7387
|
+
return {
|
|
7388
|
+
...raw,
|
|
7389
|
+
isDraft,
|
|
7390
|
+
state: upperState(raw.state ?? raw.status, isDraft),
|
|
7391
|
+
author,
|
|
7392
|
+
body: raw.body ?? raw.description ?? "",
|
|
7393
|
+
isCrossRepository: false,
|
|
7394
|
+
reviewDecision: cursorReviewDecision(raw.reviewDecision),
|
|
7395
|
+
reviewRequests: originReviewRequests(raw.reviewRequests)
|
|
7396
|
+
};
|
|
7397
|
+
}
|
|
7398
|
+
function originReviewRequests(raw) {
|
|
7399
|
+
if (!Array.isArray(raw)) return raw;
|
|
7400
|
+
return raw.map(originReviewer).filter((row) => row != null);
|
|
7401
|
+
}
|
|
7402
|
+
function originReviewer(raw) {
|
|
7403
|
+
if (typeof raw === "string" && raw.trim()) return { login: raw.trim() };
|
|
7404
|
+
if (!raw || typeof raw !== "object") return null;
|
|
7405
|
+
const row = raw;
|
|
7406
|
+
if (typeof row.login === "string" && row.login.trim()) return row;
|
|
7407
|
+
const kind = String(row.kind ?? row.__typename ?? "").toLowerCase();
|
|
7408
|
+
const slug = typeof row.slug === "string" ? row.slug.trim() : "";
|
|
7409
|
+
const name = typeof row.name === "string" ? row.name.trim() : "";
|
|
7410
|
+
const id = typeof row.id === "string" ? row.id.trim() : "";
|
|
7411
|
+
if (kind.includes("team") || kind.includes("group") || slug.includes("/") && !row.login) {
|
|
7412
|
+
return { __typename: "Team", slug: slug || name, name };
|
|
7413
|
+
}
|
|
7414
|
+
if (kind.includes("service") || kind.includes("bot")) {
|
|
7415
|
+
const login2 = name || id || "cursor-bot";
|
|
7416
|
+
return { __typename: "Bot", login: login2.toLowerCase().endsWith("[bot]") ? login2 : `${login2}[bot]` };
|
|
7417
|
+
}
|
|
7418
|
+
const login = name || id;
|
|
7419
|
+
return login ? { login } : null;
|
|
7420
|
+
}
|
|
7421
|
+
function originChecksToRuns(stdout) {
|
|
7422
|
+
let parsed;
|
|
7423
|
+
try {
|
|
7424
|
+
parsed = JSON.parse(stdout);
|
|
7425
|
+
} catch {
|
|
7426
|
+
return [];
|
|
7427
|
+
}
|
|
7428
|
+
const rows = Array.isArray(parsed) ? parsed : [];
|
|
7429
|
+
return rows.map((row) => {
|
|
7430
|
+
const item = row ?? {};
|
|
7431
|
+
const conclusion = typeof item.conclusion === "string" ? item.conclusion.toLowerCase() : "";
|
|
7432
|
+
const status = typeof item.status === "string" ? item.status.toLowerCase() : "";
|
|
7433
|
+
const bucket = conclusion === "success" || conclusion === "neutral" ? "pass" : conclusion === "failure" || conclusion === "timed_out" || conclusion === "action_required" ? "fail" : conclusion === "cancelled" ? "cancel" : conclusion === "skipped" ? "skipping" : "pending";
|
|
7434
|
+
const state = conclusion || status || "pending";
|
|
7435
|
+
const link = typeof item.link === "string" ? item.link : typeof item.detailsUrl === "string" ? item.detailsUrl : null;
|
|
7436
|
+
const description = typeof item.summary === "string" ? item.summary : typeof item.description === "string" ? item.description : null;
|
|
7437
|
+
return {
|
|
7438
|
+
name: String(item.name ?? "check"),
|
|
7439
|
+
state,
|
|
7440
|
+
bucket,
|
|
7441
|
+
startedAt: typeof item.startedAt === "string" ? item.startedAt : null,
|
|
7442
|
+
completedAt: typeof item.completedAt === "string" ? item.completedAt : null,
|
|
7443
|
+
link,
|
|
7444
|
+
description,
|
|
7445
|
+
workflow: typeof item.group === "string" ? item.group : null,
|
|
7446
|
+
kind: "ci"
|
|
7447
|
+
};
|
|
7448
|
+
});
|
|
7449
|
+
}
|
|
7450
|
+
function listedHasLabels(pr, labels) {
|
|
7451
|
+
if (labels.length === 0) return true;
|
|
7452
|
+
const have = new Set((pr.labels ?? []).map((name) => name.toLowerCase()));
|
|
7453
|
+
return labels.every((label) => have.has(label.toLowerCase()));
|
|
7454
|
+
}
|
|
7455
|
+
async function listCursorPrs(repoPath, slug, opts, head) {
|
|
7456
|
+
const resolved = resolveListPrsOptions(opts);
|
|
7457
|
+
const limit = Math.max(1, Math.min(250, resolved.limit ?? 200));
|
|
7458
|
+
const fetchLimit = prListFetchLimit(limit, resolved.reviewer);
|
|
7459
|
+
const useSearch = resolved.labels.length > 0 || Boolean(resolved.reviewer) || Boolean(resolved.query);
|
|
7460
|
+
const state = resolved.draft === true ? "draft" : resolved.state;
|
|
7461
|
+
const args = [
|
|
7462
|
+
"pr",
|
|
7463
|
+
"list",
|
|
7464
|
+
...repoArgs(slug),
|
|
7465
|
+
"--state",
|
|
7466
|
+
state,
|
|
7467
|
+
"--limit",
|
|
7468
|
+
String(fetchLimit),
|
|
7469
|
+
"--json",
|
|
7470
|
+
useSearch ? SEARCH_LIST_FIELDS : PLAIN_LIST_FIELDS
|
|
7471
|
+
];
|
|
7472
|
+
if (head?.trim()) args.push("--head", head.trim());
|
|
7473
|
+
if (useSearch) {
|
|
7474
|
+
for (const label of resolved.labels) args.push("--label", label);
|
|
7475
|
+
if (resolved.query) args.push("--search", resolved.query);
|
|
7476
|
+
else if (resolved.labels.length === 0) {
|
|
7477
|
+
const token = state === "all" ? "is:open OR is:closed OR is:merged" : `is:${state}`;
|
|
7478
|
+
args.push("--search", token);
|
|
7479
|
+
}
|
|
7480
|
+
}
|
|
7481
|
+
const { stdout, exitCode } = await originCli(args, repoPath, { reject: false, timeoutMs: 2e4 });
|
|
7482
|
+
if (exitCode !== 0 || !stdout.trim()) return [];
|
|
7483
|
+
let parsed;
|
|
7484
|
+
try {
|
|
7485
|
+
parsed = JSON.parse(stdout);
|
|
7486
|
+
} catch {
|
|
7487
|
+
return [];
|
|
7488
|
+
}
|
|
7489
|
+
if (!Array.isArray(parsed)) return [];
|
|
7490
|
+
const normalized = parsed.filter((row) => row && typeof row === "object").map((row) => normalizeOriginPr(row));
|
|
7491
|
+
const listed = applyPrListResponse(JSON.stringify(normalized), { ...opts, limit: void 0 });
|
|
7492
|
+
return listed.filter((pr) => listedHasLabels(pr, resolved.labels)).slice(0, limit);
|
|
7493
|
+
}
|
|
7494
|
+
async function viewCursorPr(repoPath, slug, selector, fields) {
|
|
7495
|
+
const { stdout, exitCode } = await originCli(
|
|
7496
|
+
["pr", "view", selector, ...repoArgs(slug), "--json", fields],
|
|
7497
|
+
repoPath,
|
|
7498
|
+
{ reject: false, timeoutMs: 2e4 }
|
|
7499
|
+
);
|
|
7500
|
+
if (exitCode !== 0 || !stdout.trim()) return null;
|
|
7501
|
+
try {
|
|
7502
|
+
const parsed = JSON.parse(stdout);
|
|
7503
|
+
return normalizeOriginPr(parsed);
|
|
7504
|
+
} catch {
|
|
7505
|
+
return null;
|
|
7506
|
+
}
|
|
7507
|
+
}
|
|
7508
|
+
async function createOrUpdateCursorPr(repoPath, slug, opts) {
|
|
7509
|
+
const branch = cursorHeadBranch(opts.head, slug);
|
|
7510
|
+
const existing = await originCli(
|
|
7511
|
+
["pr", "view", branch, ...repoArgs(slug), "--json", "url"],
|
|
7512
|
+
repoPath,
|
|
7513
|
+
{ reject: false, timeoutMs: 2e4 }
|
|
7514
|
+
);
|
|
7515
|
+
if (existing.exitCode === 0 && existing.stdout.trim()) {
|
|
7516
|
+
let url2 = "";
|
|
7517
|
+
try {
|
|
7518
|
+
url2 = String(JSON.parse(existing.stdout).url ?? "");
|
|
7519
|
+
} catch {
|
|
7520
|
+
url2 = "";
|
|
7521
|
+
}
|
|
7522
|
+
if (url2) {
|
|
7523
|
+
await originCli(
|
|
7524
|
+
["pr", "edit", branch, ...repoArgs(slug), "--title", opts.title, "-F", opts.bodyFile],
|
|
7525
|
+
repoPath,
|
|
7526
|
+
{ reject: false, timeoutMs: 2e4 }
|
|
7527
|
+
);
|
|
7528
|
+
return url2;
|
|
7529
|
+
}
|
|
7530
|
+
}
|
|
7531
|
+
const args = [
|
|
7532
|
+
"pr",
|
|
7533
|
+
"create",
|
|
7534
|
+
...repoArgs(slug),
|
|
7535
|
+
"--title",
|
|
7536
|
+
opts.title,
|
|
7537
|
+
"-F",
|
|
7538
|
+
opts.bodyFile,
|
|
7539
|
+
"--base",
|
|
7540
|
+
opts.base,
|
|
7541
|
+
"--head",
|
|
7542
|
+
branch,
|
|
7543
|
+
"--push"
|
|
7544
|
+
];
|
|
7545
|
+
if (opts.draft) args.push("--draft");
|
|
7546
|
+
const created = await originCli(args, repoPath, { reject: false, timeoutMs: 6e4 });
|
|
7547
|
+
if (created.exitCode !== 0) {
|
|
7548
|
+
throw new Error(created.stderr.trim() || created.stdout.trim() || "origin pr create failed");
|
|
7549
|
+
}
|
|
7550
|
+
const printed = created.stdout.trim().split("\n").find((line) => line.startsWith("http"));
|
|
7551
|
+
if (printed) return printed;
|
|
7552
|
+
const viewed = await viewCursorPr(repoPath, slug, branch, "url");
|
|
7553
|
+
const url = typeof viewed?.url === "string" ? viewed.url.trim() : "";
|
|
7554
|
+
return url || created.stdout.trim();
|
|
7555
|
+
}
|
|
7556
|
+
async function readyCursorPr(repoPath, slug, selector) {
|
|
7557
|
+
const ready = await originCli(["pr", "ready", selector, ...repoArgs(slug)], repoPath, {
|
|
7558
|
+
reject: false,
|
|
7559
|
+
timeoutMs: 2e4
|
|
7560
|
+
});
|
|
7561
|
+
if (ready.exitCode !== 0) {
|
|
7562
|
+
throw new Error(ready.stderr.trim() || ready.stdout.trim() || "Could not mark the Cursor pull request ready");
|
|
7563
|
+
}
|
|
7564
|
+
}
|
|
7565
|
+
async function mergeCursorPr(repoPath, slug, selector, method) {
|
|
7566
|
+
const args = ["pr", "merge", selector, ...repoArgs(slug)];
|
|
7567
|
+
if (method === "merge") args.push("--merge");
|
|
7568
|
+
else if (method === "squash") args.push("--squash");
|
|
7569
|
+
const merged = await originCli(args, repoPath, {
|
|
7570
|
+
reject: false,
|
|
7571
|
+
timeoutMs: 6e4
|
|
7572
|
+
});
|
|
7573
|
+
if (merged.exitCode !== 0) {
|
|
7574
|
+
throw new Error(merged.stderr.trim() || merged.stdout.trim() || "origin pr merge failed");
|
|
7575
|
+
}
|
|
7576
|
+
}
|
|
7577
|
+
async function fetchCursorPrHead(repoPath, slug, number, localBranch) {
|
|
7578
|
+
const view = await viewCursorPr(repoPath, slug, String(number), "headRefName");
|
|
7579
|
+
const head = typeof view?.headRefName === "string" ? view.headRefName.trim() : "";
|
|
7580
|
+
if (!head) {
|
|
7581
|
+
throw new Error(`Could not resolve the head branch for Cursor pull request #${number}`);
|
|
7582
|
+
}
|
|
7583
|
+
const result = await git(["fetch", "origin", `${head}:${localBranch}`], repoPath, { reject: false });
|
|
7584
|
+
if (result.exitCode !== 0) {
|
|
7585
|
+
throw new Error((result.stderr || result.stdout).trim() || `git fetch origin ${head} failed`);
|
|
7586
|
+
}
|
|
7587
|
+
}
|
|
7588
|
+
async function cursorPrChecks(repoPath, slug, selector) {
|
|
7589
|
+
const { stdout, exitCode, stderr } = await originCli(
|
|
7590
|
+
["pr", "checks", selector, ...repoArgs(slug), "--json", "name,status,conclusion,detailsUrl,startedAt,completedAt,summary,group,link"],
|
|
7591
|
+
repoPath,
|
|
7592
|
+
{ reject: false, timeoutMs: 2e4 }
|
|
7593
|
+
);
|
|
7594
|
+
const err = stderr.trim();
|
|
7595
|
+
let ci;
|
|
7596
|
+
if (!stdout.trim()) {
|
|
7597
|
+
if (/no pull request|not found|no change/i.test(err)) return null;
|
|
7598
|
+
if (exitCode !== 0 && err) throw new Error(err);
|
|
7599
|
+
ci = [];
|
|
7600
|
+
} else {
|
|
7601
|
+
ci = originChecksToRuns(stdout);
|
|
7602
|
+
}
|
|
7603
|
+
const view = await viewCursorPr(
|
|
7604
|
+
repoPath,
|
|
7605
|
+
slug,
|
|
7606
|
+
selector,
|
|
7607
|
+
"url,baseRefName,reviewDecision,mergeability"
|
|
7608
|
+
);
|
|
7609
|
+
if (!view) return ci;
|
|
7610
|
+
return cursorChecksWithGate(ci, cursorViewToPrMeta(view));
|
|
7611
|
+
}
|
|
7612
|
+
function cursorChecksWithGate(ci, meta) {
|
|
7613
|
+
const gate = {
|
|
7614
|
+
mergeable: meta.mergeable,
|
|
7615
|
+
mergeStateStatus: meta.mergeStateStatus,
|
|
7616
|
+
reviewDecision: meta.reviewDecision,
|
|
7617
|
+
baseRefName: meta.baseRefName,
|
|
7618
|
+
url: meta.url,
|
|
7619
|
+
isInMergeQueue: meta.isInMergeQueue
|
|
7620
|
+
};
|
|
7621
|
+
const review = (gate.reviewDecision ?? "").toUpperCase();
|
|
7622
|
+
const hasReviewRow = review === "CHANGES_REQUESTED" || review === "REVIEW_REQUIRED";
|
|
7623
|
+
const gateRows = buildMergeGateChecks(gate, {
|
|
7624
|
+
suppressGenericBlocked: ci.some((check) => check.bucket === "fail") || hasReviewRow
|
|
7625
|
+
});
|
|
7626
|
+
return [...gateRows, ...ci];
|
|
7627
|
+
}
|
|
7628
|
+
var PLAIN_LIST_FIELDS, SEARCH_LIST_FIELDS, VIEW_FIELDS, CURSOR_PR_VIEW_FIELDS;
|
|
7629
|
+
var init_cursor_pr = __esm({
|
|
7630
|
+
"src/git/cursor-pr.ts"() {
|
|
7631
|
+
"use strict";
|
|
7632
|
+
init_run();
|
|
7633
|
+
init_remote_forge();
|
|
7634
|
+
init_list_prs();
|
|
7635
|
+
init_pr_gates();
|
|
7636
|
+
PLAIN_LIST_FIELDS = "number,title,headRefName,url,author,state,isDraft,reviewDecision";
|
|
7637
|
+
SEARCH_LIST_FIELDS = `${PLAIN_LIST_FIELDS},labels,reviewRequests`;
|
|
7638
|
+
VIEW_FIELDS = "number,title,body,url,state,isDraft,reviewDecision,author,createdAt,baseRefName,headRefName,additions,deletions,changedFiles,commits,comments,reviews,labels,mergeability";
|
|
7639
|
+
CURSOR_PR_VIEW_FIELDS = VIEW_FIELDS;
|
|
7640
|
+
}
|
|
7641
|
+
});
|
|
7642
|
+
|
|
7643
|
+
// src/util/enqueue-by-key.ts
|
|
7644
|
+
function enqueueByKey(key, fn) {
|
|
7645
|
+
const prev = tails.get(key) ?? Promise.resolve();
|
|
7646
|
+
const next = prev.then(fn, fn);
|
|
7647
|
+
tails.set(
|
|
7648
|
+
key,
|
|
7649
|
+
next.then(
|
|
7650
|
+
() => void 0,
|
|
7651
|
+
() => void 0
|
|
7652
|
+
)
|
|
7653
|
+
);
|
|
7654
|
+
return next;
|
|
7655
|
+
}
|
|
7656
|
+
var tails;
|
|
7657
|
+
var init_enqueue_by_key = __esm({
|
|
7658
|
+
"src/util/enqueue-by-key.ts"() {
|
|
7659
|
+
"use strict";
|
|
7660
|
+
tails = /* @__PURE__ */ new Map();
|
|
7661
|
+
}
|
|
7662
|
+
});
|
|
7663
|
+
|
|
7664
|
+
// src/git/repo-git-lock.ts
|
|
7665
|
+
function repoLockKey(repoPath) {
|
|
7666
|
+
const trimmed = repoPath.replace(/\/+$/, "");
|
|
7667
|
+
return `git-worktree:${trimmed || "/"}`;
|
|
7668
|
+
}
|
|
7669
|
+
function withRepoGitLock(repoPath, fn) {
|
|
7670
|
+
return enqueueByKey(repoLockKey(repoPath), fn);
|
|
7671
|
+
}
|
|
7672
|
+
var init_repo_git_lock = __esm({
|
|
7673
|
+
"src/git/repo-git-lock.ts"() {
|
|
7674
|
+
"use strict";
|
|
7675
|
+
init_enqueue_by_key();
|
|
7676
|
+
}
|
|
7677
|
+
});
|
|
7678
|
+
|
|
7276
7679
|
// src/git/stack.ts
|
|
7277
7680
|
async function detectGhStack(cwd) {
|
|
7278
7681
|
const now = Date.now();
|
|
@@ -7951,11 +8354,11 @@ __export(worktree_exports, {
|
|
|
7951
8354
|
connectedPrSelectors: () => connectedPrSelectors,
|
|
7952
8355
|
countUnpushedVsOrigin: () => countUnpushedVsOrigin,
|
|
7953
8356
|
createExistingBranchWorktree: () => createExistingBranchWorktree,
|
|
7954
|
-
createOrUpdatePr: () => createOrUpdatePr,
|
|
7955
8357
|
createThreadWorktree: () => createThreadWorktree,
|
|
7956
8358
|
currentBranch: () => currentBranch,
|
|
7957
8359
|
detectLocalMergeConflicts: () => detectLocalMergeConflicts,
|
|
7958
8360
|
ensureGhPreferOrigin: () => ensureGhPreferOrigin,
|
|
8361
|
+
entireUsesTrails: () => entireUsesTrails,
|
|
7959
8362
|
fastForwardMainCheckoutIfSafe: () => fastForwardMainCheckoutIfSafe,
|
|
7960
8363
|
fetchOriginForWorktree: () => fetchOriginForWorktree,
|
|
7961
8364
|
fetchPrHead: () => fetchPrHead,
|
|
@@ -7965,7 +8368,6 @@ __export(worktree_exports, {
|
|
|
7965
8368
|
getPrForHeadBranch: () => getPrForHeadBranch,
|
|
7966
8369
|
getPrMeta: () => getPrMeta,
|
|
7967
8370
|
ghHeadRef: () => ghHeadRef,
|
|
7968
|
-
ghPrCreateAssigneeArgs: () => ghPrCreateAssigneeArgs,
|
|
7969
8371
|
ghRepoSelectArgs: () => ghRepoSelectArgs,
|
|
7970
8372
|
githubAgentGitEnv: () => githubAgentGitEnv,
|
|
7971
8373
|
isDefaultishSourceRef: () => isDefaultishSourceRef,
|
|
@@ -7989,8 +8391,10 @@ __export(worktree_exports, {
|
|
|
7989
8391
|
resolveDefaultBranch: () => resolveDefaultBranch,
|
|
7990
8392
|
resolveDiffBaseRef: () => resolveDiffBaseRef,
|
|
7991
8393
|
resolveGithubRepoSlug: () => resolveGithubRepoSlug,
|
|
8394
|
+
resolveOriginRemote: () => resolveOriginRemote,
|
|
7992
8395
|
resolvePrSelector: () => resolvePrSelector,
|
|
7993
8396
|
resolvePrSelectors: () => resolvePrSelectors,
|
|
8397
|
+
resolveProjectRemoteTag: () => resolveProjectRemoteTag,
|
|
7994
8398
|
resolveRepoRoot: () => resolveRepoRoot,
|
|
7995
8399
|
resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
|
|
7996
8400
|
slugify: () => slugify,
|
|
@@ -8004,31 +8408,6 @@ __export(worktree_exports, {
|
|
|
8004
8408
|
worktreeNameFromPath: () => worktreeNameFromPath,
|
|
8005
8409
|
worktreeSlugForTicket: () => worktreeSlugForTicket
|
|
8006
8410
|
});
|
|
8007
|
-
async function lookupGithubGraphqlReset(cwd) {
|
|
8008
|
-
const result = await gh(["api", "rate_limit"], cwd, { reject: false });
|
|
8009
|
-
if (result.exitCode !== 0 || !result.stdout.trim()) return void 0;
|
|
8010
|
-
try {
|
|
8011
|
-
const data = JSON.parse(result.stdout);
|
|
8012
|
-
const reset = data.resources?.graphql?.reset;
|
|
8013
|
-
return typeof reset === "number" ? reset : void 0;
|
|
8014
|
-
} catch {
|
|
8015
|
-
return void 0;
|
|
8016
|
-
}
|
|
8017
|
-
}
|
|
8018
|
-
async function formatPrCreateFailure(raw, cwd, ctx) {
|
|
8019
|
-
if (!isGhRateLimitError(raw)) {
|
|
8020
|
-
return formatGhLandError(raw, {
|
|
8021
|
-
targetedRepo: ctx?.slug,
|
|
8022
|
-
headRef: ctx?.head
|
|
8023
|
-
});
|
|
8024
|
-
}
|
|
8025
|
-
const resetAt = await lookupGithubGraphqlReset(cwd);
|
|
8026
|
-
return formatGhLandError(raw, {
|
|
8027
|
-
resetAt,
|
|
8028
|
-
targetedRepo: ctx?.slug,
|
|
8029
|
-
headRef: ctx?.head
|
|
8030
|
-
});
|
|
8031
|
-
}
|
|
8032
8411
|
function slugify(input) {
|
|
8033
8412
|
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
8034
8413
|
}
|
|
@@ -8051,25 +8430,39 @@ function canonicalizeRepoPath(path) {
|
|
|
8051
8430
|
}
|
|
8052
8431
|
}
|
|
8053
8432
|
function parseGithubSlugFromRemoteUrl(url) {
|
|
8054
|
-
const
|
|
8055
|
-
|
|
8056
|
-
const github = trimmed.match(/github\.com[:/]([^/]+)\/([^/]+)$/i);
|
|
8057
|
-
if (github?.[1] && github[2]) return `${github[1]}/${github[2]}`;
|
|
8058
|
-
const sshAlias = trimmed.match(/^git@[^:]+:([^/]+)\/([^/]+)$/i);
|
|
8059
|
-
if (sshAlias?.[1] && sshAlias[2]) return `${sshAlias[1]}/${sshAlias[2]}`;
|
|
8060
|
-
return null;
|
|
8433
|
+
const parsed = parseRemoteRepo(url);
|
|
8434
|
+
return parsed?.forge === "github" ? parsed.slug : null;
|
|
8061
8435
|
}
|
|
8062
|
-
async function
|
|
8436
|
+
async function remoteUrl(repoPath, remote) {
|
|
8063
8437
|
const result = await git(["remote", "get-url", remote], repoPath, {
|
|
8064
8438
|
reject: false,
|
|
8065
8439
|
timeoutMs: 5e3
|
|
8066
8440
|
});
|
|
8067
8441
|
if (result.exitCode !== 0 || !result.stdout.trim()) return null;
|
|
8068
|
-
return
|
|
8442
|
+
return result.stdout.trim();
|
|
8443
|
+
}
|
|
8444
|
+
async function slugFromGitRemote(repoPath, remote) {
|
|
8445
|
+
const url = await remoteUrl(repoPath, remote);
|
|
8446
|
+
if (!url) return null;
|
|
8447
|
+
return parseGithubSlugFromRemoteUrl(url);
|
|
8448
|
+
}
|
|
8449
|
+
async function resolveOriginRemote(repoPath) {
|
|
8450
|
+
const url = await remoteUrl(repoPath, "origin");
|
|
8451
|
+
if (!url) return null;
|
|
8452
|
+
return parseRemoteRepo(url);
|
|
8453
|
+
}
|
|
8454
|
+
async function resolveProjectRemoteTag(repoPath) {
|
|
8455
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
8456
|
+
if (origin) return formatRemoteTag(origin);
|
|
8457
|
+
const slug = await resolveGithubRepoSlug(repoPath);
|
|
8458
|
+
return slug ? `github:${slug}` : null;
|
|
8069
8459
|
}
|
|
8070
8460
|
async function resolveGithubRepoSlug(repoPath) {
|
|
8071
|
-
const
|
|
8072
|
-
if (
|
|
8461
|
+
const originUrl = await remoteUrl(repoPath, "origin");
|
|
8462
|
+
if (originUrl) {
|
|
8463
|
+
const parsed = parseRemoteRepo(originUrl);
|
|
8464
|
+
return parsed?.forge === "github" ? parsed.slug : null;
|
|
8465
|
+
}
|
|
8073
8466
|
const hasAlt = Boolean(await slugFromGitRemote(repoPath, "upstream")) || Boolean(await slugFromGitRemote(repoPath, "github"));
|
|
8074
8467
|
if (!hasAlt) {
|
|
8075
8468
|
const viaGh = await gh(
|
|
@@ -8115,6 +8508,8 @@ ${view.stderr}`;
|
|
|
8115
8508
|
});
|
|
8116
8509
|
}
|
|
8117
8510
|
async function originGhRepoEnv(cwd, opts) {
|
|
8511
|
+
const origin = await resolveOriginRemote(cwd);
|
|
8512
|
+
if (origin?.forge === "cursor") return { ORIGIN_REPO: origin.slug };
|
|
8118
8513
|
await ensureGhPreferOrigin(cwd);
|
|
8119
8514
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
8120
8515
|
const mode = opts?.mode ?? getGithubGitAuthMode();
|
|
@@ -8229,7 +8624,16 @@ async function listBranches(repoPath, opts) {
|
|
|
8229
8624
|
}
|
|
8230
8625
|
return sorted.filter((b) => keep.has(b.name));
|
|
8231
8626
|
}
|
|
8627
|
+
function entireUsesTrails() {
|
|
8628
|
+
return new Error(
|
|
8629
|
+
"This checkout is on Entire. Trails replace pull requests \u2014 use `entire trail` (Settings \u2192 Git \u2192 Entire), not `gh`."
|
|
8630
|
+
);
|
|
8631
|
+
}
|
|
8232
8632
|
async function listPrs(repoPath, opts) {
|
|
8633
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
8634
|
+
if (origin?.forge === "entire") return [];
|
|
8635
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
8636
|
+
if (cursorSlug) return listCursorPrs(repoPath, cursorSlug, opts);
|
|
8233
8637
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
8234
8638
|
const resolved = resolveListPrsOptions(opts);
|
|
8235
8639
|
const limit = resolved.limit ?? 200;
|
|
@@ -8266,6 +8670,18 @@ function prInfoFromGhView(view) {
|
|
|
8266
8670
|
};
|
|
8267
8671
|
}
|
|
8268
8672
|
async function getPr(repoPath, number) {
|
|
8673
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
8674
|
+
if (origin?.forge === "entire") return null;
|
|
8675
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
8676
|
+
if (cursorSlug) {
|
|
8677
|
+
const view = await viewCursorPr(
|
|
8678
|
+
repoPath,
|
|
8679
|
+
cursorSlug,
|
|
8680
|
+
String(number),
|
|
8681
|
+
"number,title,headRefName,url,author,isDraft,state"
|
|
8682
|
+
);
|
|
8683
|
+
return view ? prInfoFromGhView(view) : null;
|
|
8684
|
+
}
|
|
8269
8685
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
8270
8686
|
const args = [
|
|
8271
8687
|
"pr",
|
|
@@ -8327,6 +8743,13 @@ function connectedPrSelectors(thread, currentHeadPrUrl) {
|
|
|
8327
8743
|
async function getPrForHeadBranch(repoPath, branch) {
|
|
8328
8744
|
const head = normalizeGitBranchName(branch);
|
|
8329
8745
|
if (!head || isDefaultishSourceRef(head)) return null;
|
|
8746
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
8747
|
+
if (origin?.forge === "entire") return null;
|
|
8748
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
8749
|
+
if (cursorSlug) {
|
|
8750
|
+
const rows = await listCursorPrs(repoPath, cursorSlug, { state: "open", limit: 5 }, head);
|
|
8751
|
+
return rows[0] ?? null;
|
|
8752
|
+
}
|
|
8330
8753
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
8331
8754
|
const listHead = slug ? ghHeadRef(slug, head) : head;
|
|
8332
8755
|
const listArgs = [
|
|
@@ -8491,6 +8914,10 @@ async function probeLocalMergeGate(cwd, gate) {
|
|
|
8491
8914
|
return { gate, files: [] };
|
|
8492
8915
|
}
|
|
8493
8916
|
async function getPrChecks(cwd, selector) {
|
|
8917
|
+
const origin = await resolveOriginRemote(cwd);
|
|
8918
|
+
if (origin?.forge === "entire") return null;
|
|
8919
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
8920
|
+
if (cursorSlug) return cursorPrChecks(cwd, cursorSlug, selector);
|
|
8494
8921
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
8495
8922
|
const args = [
|
|
8496
8923
|
"pr",
|
|
@@ -8546,6 +8973,18 @@ async function getPrChecks(cwd, selector) {
|
|
|
8546
8973
|
return [...gateRows, ...ciChecks];
|
|
8547
8974
|
}
|
|
8548
8975
|
async function getPrMeta(cwd, selector) {
|
|
8976
|
+
const origin = await resolveOriginRemote(cwd);
|
|
8977
|
+
if (origin?.forge === "entire") return null;
|
|
8978
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
8979
|
+
if (cursorSlug) {
|
|
8980
|
+
const view = await viewCursorPr(
|
|
8981
|
+
cwd,
|
|
8982
|
+
cursorSlug,
|
|
8983
|
+
selector,
|
|
8984
|
+
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,author,labels,mergeability"
|
|
8985
|
+
);
|
|
8986
|
+
return view ? cursorViewToPrMeta(view) : null;
|
|
8987
|
+
}
|
|
8549
8988
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
8550
8989
|
const viewArgs = [
|
|
8551
8990
|
"pr",
|
|
@@ -8674,6 +9113,13 @@ function parsePrDetailsView(view) {
|
|
|
8674
9113
|
};
|
|
8675
9114
|
}
|
|
8676
9115
|
async function getPrDetails(cwd, selector) {
|
|
9116
|
+
const origin = await resolveOriginRemote(cwd);
|
|
9117
|
+
if (origin?.forge === "entire") return null;
|
|
9118
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
9119
|
+
if (cursorSlug) {
|
|
9120
|
+
const view2 = await viewCursorPr(cwd, cursorSlug, selector, CURSOR_PR_VIEW_FIELDS);
|
|
9121
|
+
return view2 ? parsePrDetailsView(view2) : null;
|
|
9122
|
+
}
|
|
8677
9123
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
8678
9124
|
const viewArgs = ["pr", "view", selector, "--json", PR_DETAILS_JSON_FIELDS];
|
|
8679
9125
|
if (slug) viewArgs.push("--repo", slug);
|
|
@@ -8693,6 +9139,13 @@ async function getPrDetails(cwd, selector) {
|
|
|
8693
9139
|
return parsePrDetailsView(view);
|
|
8694
9140
|
}
|
|
8695
9141
|
async function fetchPrHead(repoPath, number, localBranch) {
|
|
9142
|
+
const origin = await resolveOriginRemote(repoPath);
|
|
9143
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
9144
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
9145
|
+
if (cursorSlug) {
|
|
9146
|
+
await fetchCursorPrHead(repoPath, cursorSlug, number, localBranch);
|
|
9147
|
+
return;
|
|
9148
|
+
}
|
|
8696
9149
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
8697
9150
|
const refspec = `+pull/${number}/head:${localBranch}`;
|
|
8698
9151
|
const errors = [];
|
|
@@ -8835,10 +9288,10 @@ async function originRemoteUrl(cwd) {
|
|
|
8835
9288
|
const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
|
|
8836
9289
|
return result.exitCode === 0 ? result.stdout.trim() : "";
|
|
8837
9290
|
}
|
|
8838
|
-
function githubHttpsRetryEnv(
|
|
9291
|
+
function githubHttpsRetryEnv(remoteUrl2) {
|
|
8839
9292
|
return {
|
|
8840
9293
|
GIT_TERMINAL_PROMPT: "0",
|
|
8841
|
-
...githubAgentGitEnv(void 0, { remoteUrl })
|
|
9294
|
+
...githubAgentGitEnv(void 0, { remoteUrl: remoteUrl2 })
|
|
8842
9295
|
};
|
|
8843
9296
|
}
|
|
8844
9297
|
async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
@@ -8852,11 +9305,11 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
|
8852
9305
|
}
|
|
8853
9306
|
const token = await resolveGithubAgentToken(mode, repoPath);
|
|
8854
9307
|
if (!token) return false;
|
|
8855
|
-
const
|
|
9308
|
+
const remoteUrl2 = await originRemoteUrl(repoPath);
|
|
8856
9309
|
const tryHttps = async (header) => git(args, repoPath, {
|
|
8857
9310
|
reject: false,
|
|
8858
9311
|
timeoutMs,
|
|
8859
|
-
env: githubHttpsRetryEnv(
|
|
9312
|
+
env: githubHttpsRetryEnv(remoteUrl2),
|
|
8860
9313
|
config: {
|
|
8861
9314
|
"http.extraHeader": header
|
|
8862
9315
|
}
|
|
@@ -9205,10 +9658,10 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
9205
9658
|
sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
|
|
9206
9659
|
);
|
|
9207
9660
|
}
|
|
9208
|
-
const
|
|
9661
|
+
const remoteUrl2 = await originRemoteUrl(worktreePath);
|
|
9209
9662
|
const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
|
|
9210
9663
|
reject: false,
|
|
9211
|
-
env: githubHttpsRetryEnv(
|
|
9664
|
+
env: githubHttpsRetryEnv(remoteUrl2),
|
|
9212
9665
|
config: {
|
|
9213
9666
|
"http.extraHeader": header
|
|
9214
9667
|
}
|
|
@@ -9221,6 +9674,40 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
9221
9674
|
const httpsErr = (basicPush.stderr || bearer.stderr || bearer.stdout).trim();
|
|
9222
9675
|
throw new Error(httpsErr || sshErr || `git push origin ${branchName} failed`);
|
|
9223
9676
|
}
|
|
9677
|
+
async function markCursorPrReady(cwd, slug, selector) {
|
|
9678
|
+
const view = await viewCursorPr(cwd, slug, selector, "url,state,isDraft");
|
|
9679
|
+
if (!view) throw new Error("Could not load the Cursor pull request");
|
|
9680
|
+
const url = String(view.url ?? "");
|
|
9681
|
+
const state = String(view.state ?? "").toUpperCase();
|
|
9682
|
+
const isDraft = Boolean(view.isDraft);
|
|
9683
|
+
if (state === "MERGED" || state === "CLOSED") {
|
|
9684
|
+
return { url, state, isDraft: false };
|
|
9685
|
+
}
|
|
9686
|
+
if (isDraft) {
|
|
9687
|
+
if (await isDirty(cwd)) {
|
|
9688
|
+
throw new Error(
|
|
9689
|
+
"Commit and push local work before marking the pull request ready for review."
|
|
9690
|
+
);
|
|
9691
|
+
}
|
|
9692
|
+
const unpushed = await countUnpushedVsOrigin(cwd);
|
|
9693
|
+
if (unpushed > 0) {
|
|
9694
|
+
throw new Error(
|
|
9695
|
+
"Push this branch to origin before marking the pull request ready for review."
|
|
9696
|
+
);
|
|
9697
|
+
}
|
|
9698
|
+
await readyCursorPr(cwd, slug, selector);
|
|
9699
|
+
}
|
|
9700
|
+
return { url, state: state || "OPEN", isDraft: false };
|
|
9701
|
+
}
|
|
9702
|
+
async function mergeCursorPullRequest(cwd, slug, selector, method) {
|
|
9703
|
+
const view = await viewCursorPr(cwd, slug, selector, "url,state,isDraft");
|
|
9704
|
+
if (!view) throw new Error("Could not load the Cursor pull request");
|
|
9705
|
+
const url = String(view.url ?? "");
|
|
9706
|
+
if (String(view.state ?? "").toUpperCase() === "MERGED") return { url, state: "MERGED" };
|
|
9707
|
+
if (view.isDraft) await readyCursorPr(cwd, slug, selector);
|
|
9708
|
+
await mergeCursorPr(cwd, slug, selector, method);
|
|
9709
|
+
return { url, state: "MERGED" };
|
|
9710
|
+
}
|
|
9224
9711
|
async function runPrReady(cwd, selector, slug) {
|
|
9225
9712
|
const readyArgs = ["pr", "ready", selector];
|
|
9226
9713
|
if (slug) readyArgs.push("--repo", slug);
|
|
@@ -9232,6 +9719,10 @@ async function runPrReady(cwd, selector, slug) {
|
|
|
9232
9719
|
}
|
|
9233
9720
|
}
|
|
9234
9721
|
async function markPrReady(cwd, selector) {
|
|
9722
|
+
const origin = await resolveOriginRemote(cwd);
|
|
9723
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
9724
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
9725
|
+
if (cursorSlug) return markCursorPrReady(cwd, cursorSlug, selector);
|
|
9235
9726
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
9236
9727
|
const viewArgs = ["pr", "view", selector, "--json", "url,state,isDraft"];
|
|
9237
9728
|
if (slug) viewArgs.push("--repo", slug);
|
|
@@ -9270,6 +9761,10 @@ async function markPrReady(cwd, selector) {
|
|
|
9270
9761
|
return { url, state: state || "OPEN", isDraft: false };
|
|
9271
9762
|
}
|
|
9272
9763
|
async function mergePr(cwd, selector, opts) {
|
|
9764
|
+
const origin = await resolveOriginRemote(cwd);
|
|
9765
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
9766
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
9767
|
+
if (cursorSlug) return mergeCursorPullRequest(cwd, cursorSlug, selector, opts?.method ?? "squash");
|
|
9273
9768
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
9274
9769
|
const viewArgs = ["pr", "view", selector, "--json", "url,state,isDraft,number"];
|
|
9275
9770
|
if (slug) viewArgs.push("--repo", slug);
|
|
@@ -9328,128 +9823,16 @@ async function mergePr(cwd, selector, opts) {
|
|
|
9328
9823
|
}
|
|
9329
9824
|
return { url, state: "MERGED" };
|
|
9330
9825
|
}
|
|
9331
|
-
function ghPrCreateAssigneeArgs(assignee) {
|
|
9332
|
-
const raw = assignee?.trim();
|
|
9333
|
-
if (raw && /^(none|unassigned)$/i.test(raw)) return [];
|
|
9334
|
-
return ["--assignee", raw || "@me"];
|
|
9335
|
-
}
|
|
9336
|
-
async function createOrUpdatePr(worktreePath, opts) {
|
|
9337
|
-
await ensureGhPreferOrigin(worktreePath);
|
|
9338
|
-
const slug = await resolveGithubRepoSlug(worktreePath);
|
|
9339
|
-
if (!slug) {
|
|
9340
|
-
throw new Error(
|
|
9341
|
-
"Could not resolve the origin GitHub repo (owner/name) for this worktree. Check that `git remote get-url origin` points at github.com."
|
|
9342
|
-
);
|
|
9343
|
-
}
|
|
9344
|
-
const repoArgs = ghRepoSelectArgs(slug);
|
|
9345
|
-
const headRef = ghHeadRef(slug, opts.head);
|
|
9346
|
-
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
9347
|
-
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
9348
|
-
const bodyFile = (0, import_node_path21.join)(
|
|
9349
|
-
(0, import_node_os7.tmpdir)(),
|
|
9350
|
-
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto4.randomBytes)(6).toString("hex")}.md`
|
|
9351
|
-
);
|
|
9352
|
-
(0, import_node_fs18.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
9353
|
-
`, "utf8");
|
|
9354
|
-
const bodyArgs = ["--body-file", bodyFile];
|
|
9355
|
-
try {
|
|
9356
|
-
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
9357
|
-
...opts,
|
|
9358
|
-
slug,
|
|
9359
|
-
repoArgs,
|
|
9360
|
-
headRef,
|
|
9361
|
-
branchOnly,
|
|
9362
|
-
bodyArgs
|
|
9363
|
-
});
|
|
9364
|
-
} finally {
|
|
9365
|
-
try {
|
|
9366
|
-
(0, import_node_fs18.unlinkSync)(bodyFile);
|
|
9367
|
-
} catch {
|
|
9368
|
-
}
|
|
9369
|
-
}
|
|
9370
|
-
}
|
|
9371
|
-
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
9372
|
-
const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
|
|
9373
|
-
const existing = await gh(
|
|
9374
|
-
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
9375
|
-
worktreePath,
|
|
9376
|
-
{ reject: false }
|
|
9377
|
-
);
|
|
9378
|
-
if (existing.exitCode === 0 && existing.stdout.trim() && !opts.web) {
|
|
9379
|
-
const url2 = existing.stdout.trim();
|
|
9380
|
-
await gh(
|
|
9381
|
-
[
|
|
9382
|
-
...repoArgs,
|
|
9383
|
-
"pr",
|
|
9384
|
-
"edit",
|
|
9385
|
-
branchOnly,
|
|
9386
|
-
"--title",
|
|
9387
|
-
opts.title,
|
|
9388
|
-
...bodyArgs
|
|
9389
|
-
],
|
|
9390
|
-
worktreePath,
|
|
9391
|
-
{ reject: false }
|
|
9392
|
-
);
|
|
9393
|
-
return url2;
|
|
9394
|
-
}
|
|
9395
|
-
if (opts.web) {
|
|
9396
|
-
const args2 = [
|
|
9397
|
-
...repoArgs,
|
|
9398
|
-
"pr",
|
|
9399
|
-
"create",
|
|
9400
|
-
"--web",
|
|
9401
|
-
"--title",
|
|
9402
|
-
opts.title,
|
|
9403
|
-
...bodyArgs,
|
|
9404
|
-
"--base",
|
|
9405
|
-
opts.base,
|
|
9406
|
-
"--head",
|
|
9407
|
-
headRef
|
|
9408
|
-
];
|
|
9409
|
-
if (opts.draft) args2.push("--draft");
|
|
9410
|
-
args2.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
9411
|
-
await gh(args2, worktreePath, { reject: false });
|
|
9412
|
-
const again = await gh(
|
|
9413
|
-
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
9414
|
-
worktreePath,
|
|
9415
|
-
{ reject: false }
|
|
9416
|
-
);
|
|
9417
|
-
return again.stdout.trim() || "";
|
|
9418
|
-
}
|
|
9419
|
-
const args = [
|
|
9420
|
-
...repoArgs,
|
|
9421
|
-
"pr",
|
|
9422
|
-
"create",
|
|
9423
|
-
"--title",
|
|
9424
|
-
opts.title,
|
|
9425
|
-
...bodyArgs,
|
|
9426
|
-
"--base",
|
|
9427
|
-
opts.base,
|
|
9428
|
-
"--head",
|
|
9429
|
-
headRef
|
|
9430
|
-
];
|
|
9431
|
-
if (opts.draft) args.push("--draft");
|
|
9432
|
-
args.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
9433
|
-
const created = await gh(args, worktreePath, { reject: false });
|
|
9434
|
-
if (created.exitCode !== 0) {
|
|
9435
|
-
const raw = created.stderr.trim() || created.stdout.trim() || "gh pr create failed";
|
|
9436
|
-
throw new Error(await formatPrCreateFailure(raw, worktreePath, { slug, head: headRef }));
|
|
9437
|
-
}
|
|
9438
|
-
const url = created.stdout.trim().split("\n").find((l) => l.startsWith("http")) ?? created.stdout.trim();
|
|
9439
|
-
return url;
|
|
9440
|
-
}
|
|
9441
9826
|
function suggestSlug(source) {
|
|
9442
9827
|
const base = slugify(source || "thread");
|
|
9443
9828
|
const stamp = Date.now().toString(36).slice(-4);
|
|
9444
9829
|
return `${base || "thread"}-${stamp}`;
|
|
9445
9830
|
}
|
|
9446
|
-
var
|
|
9831
|
+
var import_node_fs18, import_node_path21, PR_INFO_JSON_FIELDS, PR_DETAILS_JSON_FIELDS;
|
|
9447
9832
|
var init_worktree = __esm({
|
|
9448
9833
|
"src/git/worktree.ts"() {
|
|
9449
9834
|
"use strict";
|
|
9450
|
-
import_node_crypto4 = require("crypto");
|
|
9451
9835
|
import_node_fs18 = require("fs");
|
|
9452
|
-
import_node_os7 = require("os");
|
|
9453
9836
|
import_node_path21 = require("path");
|
|
9454
9837
|
init_paths();
|
|
9455
9838
|
init_worktree_labels();
|
|
@@ -9457,6 +9840,8 @@ var init_worktree = __esm({
|
|
|
9457
9840
|
init_worktree_exclude();
|
|
9458
9841
|
init_git_auth_mode();
|
|
9459
9842
|
init_run();
|
|
9843
|
+
init_remote_forge();
|
|
9844
|
+
init_cursor_pr();
|
|
9460
9845
|
init_list_prs();
|
|
9461
9846
|
init_repo_git_lock();
|
|
9462
9847
|
init_app_settings();
|
|
@@ -9561,7 +9946,7 @@ function uniqueAttachmentName(dir, originalName) {
|
|
|
9561
9946
|
const candidate = `${stem}-${i}${ext}`;
|
|
9562
9947
|
if (!(0, import_node_fs19.existsSync)((0, import_node_path22.join)(dir, candidate))) return candidate;
|
|
9563
9948
|
}
|
|
9564
|
-
return `${stem}-${(0,
|
|
9949
|
+
return `${stem}-${(0, import_node_crypto4.randomUUID)()}${ext}`;
|
|
9565
9950
|
}
|
|
9566
9951
|
function previewDataUrlFromBuf(filePath, buf) {
|
|
9567
9952
|
if (!isImageFilePath(filePath)) return void 0;
|
|
@@ -9573,7 +9958,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
9573
9958
|
if (isImageFilePath(name)) {
|
|
9574
9959
|
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
9575
9960
|
return {
|
|
9576
|
-
id: (0,
|
|
9961
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
9577
9962
|
name,
|
|
9578
9963
|
kind: "file",
|
|
9579
9964
|
path: opts.path,
|
|
@@ -9586,7 +9971,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
9586
9971
|
}
|
|
9587
9972
|
if (buf.length > MAX_INLINE_BYTES) {
|
|
9588
9973
|
return {
|
|
9589
|
-
id: (0,
|
|
9974
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
9590
9975
|
name,
|
|
9591
9976
|
kind: "file",
|
|
9592
9977
|
path: opts.path,
|
|
@@ -9595,7 +9980,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
9595
9980
|
}
|
|
9596
9981
|
if (buf.includes(0)) {
|
|
9597
9982
|
return {
|
|
9598
|
-
id: (0,
|
|
9983
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
9599
9984
|
name,
|
|
9600
9985
|
kind: "file",
|
|
9601
9986
|
path: opts.path,
|
|
@@ -9603,7 +9988,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
9603
9988
|
};
|
|
9604
9989
|
}
|
|
9605
9990
|
return {
|
|
9606
|
-
id: (0,
|
|
9991
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
9607
9992
|
name,
|
|
9608
9993
|
kind: "file",
|
|
9609
9994
|
path: opts.path,
|
|
@@ -9627,7 +10012,7 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
|
9627
10012
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
9628
10013
|
} catch (err) {
|
|
9629
10014
|
out.push({
|
|
9630
|
-
id: (0,
|
|
10015
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
9631
10016
|
name: originalName,
|
|
9632
10017
|
kind: "file",
|
|
9633
10018
|
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -9651,7 +10036,7 @@ function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
|
9651
10036
|
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
9652
10037
|
} catch (err) {
|
|
9653
10038
|
out.push({
|
|
9654
|
-
id: (0,
|
|
10039
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
9655
10040
|
name: originalName,
|
|
9656
10041
|
kind: "file",
|
|
9657
10042
|
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -9706,7 +10091,7 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
9706
10091
|
for (const rel of relativePaths) {
|
|
9707
10092
|
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
9708
10093
|
out.push({
|
|
9709
|
-
id: (0,
|
|
10094
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
9710
10095
|
name: (0, import_node_path22.basename)(rel) || "file",
|
|
9711
10096
|
kind: "file",
|
|
9712
10097
|
content: `(invalid path: ${rel})`
|
|
@@ -9722,7 +10107,7 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
9722
10107
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
9723
10108
|
} catch (err) {
|
|
9724
10109
|
out.push({
|
|
9725
|
-
id: (0,
|
|
10110
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
9726
10111
|
name,
|
|
9727
10112
|
kind: "file",
|
|
9728
10113
|
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -9731,13 +10116,13 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
9731
10116
|
}
|
|
9732
10117
|
return out;
|
|
9733
10118
|
}
|
|
9734
|
-
var import_node_fs19, import_node_path22,
|
|
10119
|
+
var import_node_fs19, import_node_path22, import_node_crypto4, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
|
|
9735
10120
|
var init_stage_files = __esm({
|
|
9736
10121
|
"src/composer/stage-files.ts"() {
|
|
9737
10122
|
"use strict";
|
|
9738
10123
|
import_node_fs19 = require("fs");
|
|
9739
10124
|
import_node_path22 = require("path");
|
|
9740
|
-
|
|
10125
|
+
import_node_crypto4 = require("crypto");
|
|
9741
10126
|
init_workspace_scratch();
|
|
9742
10127
|
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
9743
10128
|
"png",
|
|
@@ -9836,7 +10221,7 @@ function pathIsInside(parent, child) {
|
|
|
9836
10221
|
}
|
|
9837
10222
|
function defaultWorktreesRoot(repoPath) {
|
|
9838
10223
|
const slug = (0, import_node_path23.basename)(repoPath.replace(/\/+$/, "")) || "repo";
|
|
9839
|
-
return (0, import_node_path23.join)((0,
|
|
10224
|
+
return (0, import_node_path23.join)((0, import_node_os7.homedir)(), "sideboard", "workspaces", slug);
|
|
9840
10225
|
}
|
|
9841
10226
|
function removedWorktreeCoversRepo(saved, repoPath) {
|
|
9842
10227
|
if (!saved || !repoPath) return false;
|
|
@@ -10019,12 +10404,12 @@ async function archiveRemovedWorkspaceChats(threads, archive) {
|
|
|
10019
10404
|
}
|
|
10020
10405
|
if (failures.length > 0) throw new Error(failures.join("\n"));
|
|
10021
10406
|
}
|
|
10022
|
-
var import_node_fs20,
|
|
10407
|
+
var import_node_fs20, import_node_os7, import_node_path23;
|
|
10023
10408
|
var init_workspaces = __esm({
|
|
10024
10409
|
"src/store/workspaces.ts"() {
|
|
10025
10410
|
"use strict";
|
|
10026
10411
|
import_node_fs20 = require("fs");
|
|
10027
|
-
|
|
10412
|
+
import_node_os7 = require("os");
|
|
10028
10413
|
import_node_path23 = require("path");
|
|
10029
10414
|
init_settings();
|
|
10030
10415
|
init_paths();
|
|
@@ -10048,7 +10433,7 @@ __export(coordinator_prompt_exports, {
|
|
|
10048
10433
|
function formatWorkspaceInventory(workspaces) {
|
|
10049
10434
|
if (workspaces.length === 0) return "(no registered workspaces)";
|
|
10050
10435
|
return workspaces.map((w) => {
|
|
10051
|
-
const slug = w.githubSlug?.trim() ? ` github:${w.githubSlug.trim()}` : "";
|
|
10436
|
+
const slug = w.originRemote ? ` ${formatRemoteTag(w.originRemote)}` : w.githubSlug?.trim() ? ` github:${w.githubSlug.trim()}` : "";
|
|
10052
10437
|
const profile = formatWorkspaceProfileSuffix(safeViewerProfile(w.path));
|
|
10053
10438
|
return `- ${w.name}: ${w.path}${slug}${profile}`;
|
|
10054
10439
|
}).join("\n");
|
|
@@ -10056,8 +10441,9 @@ function formatWorkspaceInventory(workspaces) {
|
|
|
10056
10441
|
async function enrichWorkspacesWithGithub(workspaces) {
|
|
10057
10442
|
return Promise.all(
|
|
10058
10443
|
workspaces.map(async (w) => {
|
|
10059
|
-
const
|
|
10060
|
-
|
|
10444
|
+
const originRemote = await resolveOriginRemote(w.path).catch(() => null);
|
|
10445
|
+
const githubSlug = originRemote ? originRemote.forge === "github" ? originRemote.slug : null : await resolveGithubRepoSlug(w.path).catch(() => null);
|
|
10446
|
+
return { ...w, githubSlug, originRemote };
|
|
10061
10447
|
})
|
|
10062
10448
|
);
|
|
10063
10449
|
}
|
|
@@ -10068,8 +10454,8 @@ function coordinatorGreenfieldPlaybook(reposDir) {
|
|
|
10068
10454
|
"- Examples:",
|
|
10069
10455
|
` - Clone: \`git clone <url> ${reposDir}/<name>\``,
|
|
10070
10456
|
` - New GitHub repo: \`gh repo create <owner>/<name> --private --clone -- ${reposDir}/<name>\` (or mkdir + git init + gh repo create + remote add + push)`,
|
|
10071
|
-
"- 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 (
|
|
10072
|
-
"- Always target the child worktree's **origin** (`github:`
|
|
10457
|
+
"- 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`).",
|
|
10458
|
+
"- 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`.",
|
|
10073
10459
|
"- Do coding work in the child worktree thread, not by editing files in this home cwd."
|
|
10074
10460
|
].join("\n");
|
|
10075
10461
|
}
|
|
@@ -10230,6 +10616,7 @@ var init_coordinator_prompt = __esm({
|
|
|
10230
10616
|
"use strict";
|
|
10231
10617
|
import_node_fs21 = require("fs");
|
|
10232
10618
|
import_node_path24 = require("path");
|
|
10619
|
+
init_remote_forge();
|
|
10233
10620
|
init_worktree();
|
|
10234
10621
|
init_app_settings();
|
|
10235
10622
|
init_paths();
|
|
@@ -10238,9 +10625,9 @@ var init_coordinator_prompt = __esm({
|
|
|
10238
10625
|
"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.",
|
|
10239
10626
|
"Sideboard MCP (fleet control \u2014 prefer these for status and orchestration):",
|
|
10240
10627
|
"Discover:",
|
|
10241
|
-
"- list_projects \u2014 registered repos (path + github
|
|
10628
|
+
"- 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.",
|
|
10242
10629
|
"- 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.",
|
|
10243
|
-
|
|
10630
|
+
'- 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).',
|
|
10244
10631
|
"- 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.",
|
|
10245
10632
|
"- 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.",
|
|
10246
10633
|
"- 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.",
|
|
@@ -10277,11 +10664,11 @@ var init_coordinator_prompt = __esm({
|
|
|
10277
10664
|
"- 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.",
|
|
10278
10665
|
"Inspect / review / PRs:",
|
|
10279
10666
|
"- get_diff \u2014 compact diff summary",
|
|
10280
|
-
"- 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.",
|
|
10667
|
+
"- 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.",
|
|
10281
10668
|
'- 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.',
|
|
10282
10669
|
"- 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.",
|
|
10283
10670
|
'- 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.',
|
|
10284
|
-
'- 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.
|
|
10671
|
+
'- 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.',
|
|
10285
10672
|
"Process guides:",
|
|
10286
10673
|
"- 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.",
|
|
10287
10674
|
"- 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.",
|
|
@@ -10624,7 +11011,7 @@ function resolveBrightsyConfigFile(path) {
|
|
|
10624
11011
|
}
|
|
10625
11012
|
function brightsyConfigPath() {
|
|
10626
11013
|
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
10627
|
-
const raw = override || (0, import_node_path26.join)((0,
|
|
11014
|
+
const raw = override || (0, import_node_path26.join)((0, import_node_os8.homedir)(), ".brightsy", "config.json");
|
|
10628
11015
|
return resolveBrightsyConfigFile(raw);
|
|
10629
11016
|
}
|
|
10630
11017
|
function loadBrightsyConfig() {
|
|
@@ -10658,12 +11045,12 @@ function saveBrightsyConfig(cfg) {
|
|
|
10658
11045
|
mode: 384
|
|
10659
11046
|
});
|
|
10660
11047
|
}
|
|
10661
|
-
var import_node_fs23,
|
|
11048
|
+
var import_node_fs23, import_node_os8, import_node_path26;
|
|
10662
11049
|
var init_config = __esm({
|
|
10663
11050
|
"src/brightsy/config.ts"() {
|
|
10664
11051
|
"use strict";
|
|
10665
11052
|
import_node_fs23 = require("fs");
|
|
10666
|
-
|
|
11053
|
+
import_node_os8 = require("os");
|
|
10667
11054
|
import_node_path26 = require("path");
|
|
10668
11055
|
}
|
|
10669
11056
|
});
|
|
@@ -11772,7 +12159,7 @@ function claudePluginServerId(pluginName, serverName) {
|
|
|
11772
12159
|
return `plugin_${pluginName}_${serverName}`.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
11773
12160
|
}
|
|
11774
12161
|
function listEnabledClaudePluginMcpServers(opts) {
|
|
11775
|
-
const home = opts?.home ?? (0,
|
|
12162
|
+
const home = opts?.home ?? (0, import_node_os9.homedir)();
|
|
11776
12163
|
const pluginsRoot = claudePluginsRoot(home);
|
|
11777
12164
|
const enabled = enabledPluginIds(home, opts?.projectDirs ?? []);
|
|
11778
12165
|
const installed = readInstalledPlugins((0, import_node_path28.join)(pluginsRoot, "installed_plugins.json"));
|
|
@@ -11954,12 +12341,12 @@ function readJson(path) {
|
|
|
11954
12341
|
return {};
|
|
11955
12342
|
}
|
|
11956
12343
|
}
|
|
11957
|
-
var import_node_fs26,
|
|
12344
|
+
var import_node_fs26, import_node_os9, import_node_path28;
|
|
11958
12345
|
var init_claude_plugins = __esm({
|
|
11959
12346
|
"src/agents/claude-plugins.ts"() {
|
|
11960
12347
|
"use strict";
|
|
11961
12348
|
import_node_fs26 = require("fs");
|
|
11962
|
-
|
|
12349
|
+
import_node_os9 = require("os");
|
|
11963
12350
|
import_node_path28 = require("path");
|
|
11964
12351
|
init_meta();
|
|
11965
12352
|
}
|
|
@@ -12176,7 +12563,7 @@ function versionDirNodeBins(root, toBin) {
|
|
|
12176
12563
|
return [];
|
|
12177
12564
|
}
|
|
12178
12565
|
}
|
|
12179
|
-
function defaultNodeBinCandidates(home = (0,
|
|
12566
|
+
function defaultNodeBinCandidates(home = (0, import_node_os10.homedir)()) {
|
|
12180
12567
|
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
12181
12568
|
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path30.join)(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
12182
12569
|
);
|
|
@@ -12291,12 +12678,12 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
12291
12678
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
12292
12679
|
};
|
|
12293
12680
|
}
|
|
12294
|
-
var import_node_fs28,
|
|
12681
|
+
var import_node_fs28, import_node_os10, import_node_path30, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
|
|
12295
12682
|
var init_node_launch = __esm({
|
|
12296
12683
|
"src/agents/node-launch.ts"() {
|
|
12297
12684
|
"use strict";
|
|
12298
12685
|
import_node_fs28 = require("fs");
|
|
12299
|
-
|
|
12686
|
+
import_node_os10 = require("os");
|
|
12300
12687
|
import_node_path30 = require("path");
|
|
12301
12688
|
init_nested_electron_env();
|
|
12302
12689
|
init_system_ca();
|
|
@@ -12593,18 +12980,18 @@ function mcpServersRecord(servers, extraServers) {
|
|
|
12593
12980
|
function writeMcpServersConfig(servers, extraServers) {
|
|
12594
12981
|
const mcpServers = mcpServersRecord(servers, extraServers);
|
|
12595
12982
|
if (Object.keys(mcpServers).length === 0) return null;
|
|
12596
|
-
const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path31.join)((0,
|
|
12983
|
+
const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path31.join)((0, import_node_os11.tmpdir)(), "sideboard-mcp-"));
|
|
12597
12984
|
const cfgPath = (0, import_node_path31.join)(dir, "mcp.json");
|
|
12598
12985
|
(0, import_node_fs29.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
12599
12986
|
return cfgPath;
|
|
12600
12987
|
}
|
|
12601
|
-
var import_node_fs29, import_node_module,
|
|
12988
|
+
var import_node_fs29, import_node_module, import_node_os11, import_node_path31, 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, brightsyMcpCommandCache, BRIGHTSY_WORD;
|
|
12602
12989
|
var init_injected_mcp = __esm({
|
|
12603
12990
|
"src/agents/injected-mcp.ts"() {
|
|
12604
12991
|
"use strict";
|
|
12605
12992
|
import_node_fs29 = require("fs");
|
|
12606
12993
|
import_node_module = require("module");
|
|
12607
|
-
|
|
12994
|
+
import_node_os11 = require("os");
|
|
12608
12995
|
import_node_path31 = require("path");
|
|
12609
12996
|
import_node_url = require("url");
|
|
12610
12997
|
init_run();
|
|
@@ -12659,14 +13046,14 @@ var init_injected_mcp = __esm({
|
|
|
12659
13046
|
|
|
12660
13047
|
// src/agents/user-mcp-config.ts
|
|
12661
13048
|
function userClaudeMcpConfigPath() {
|
|
12662
|
-
return (0, import_node_path32.join)((0,
|
|
13049
|
+
return (0, import_node_path32.join)((0, import_node_os12.homedir)(), ".claude.json");
|
|
12663
13050
|
}
|
|
12664
|
-
var import_node_fs30,
|
|
13051
|
+
var import_node_fs30, import_node_os12, import_node_path32;
|
|
12665
13052
|
var init_user_mcp_config = __esm({
|
|
12666
13053
|
"src/agents/user-mcp-config.ts"() {
|
|
12667
13054
|
"use strict";
|
|
12668
13055
|
import_node_fs30 = require("fs");
|
|
12669
|
-
|
|
13056
|
+
import_node_os12 = require("os");
|
|
12670
13057
|
import_node_path32 = require("path");
|
|
12671
13058
|
init_paths();
|
|
12672
13059
|
init_injected_mcp();
|
|
@@ -12707,10 +13094,10 @@ function readText(path) {
|
|
|
12707
13094
|
return "";
|
|
12708
13095
|
}
|
|
12709
13096
|
}
|
|
12710
|
-
function userCodexConfigPaths(home = (0,
|
|
13097
|
+
function userCodexConfigPaths(home = (0, import_node_os13.homedir)()) {
|
|
12711
13098
|
return [(0, import_node_path33.join)(home, ".codex", "config.toml"), (0, import_node_path33.join)(home, ".config", "codex", "config.toml")];
|
|
12712
13099
|
}
|
|
12713
|
-
function userOpencodeConfigPaths(home = (0,
|
|
13100
|
+
function userOpencodeConfigPaths(home = (0, import_node_os13.homedir)()) {
|
|
12714
13101
|
return [
|
|
12715
13102
|
(0, import_node_path33.join)(home, ".config", "opencode", "opencode.json"),
|
|
12716
13103
|
(0, import_node_path33.join)(home, ".config", "opencode", "opencode.jsonc")
|
|
@@ -12732,7 +13119,7 @@ function userMcpNamesToDisable(opts) {
|
|
|
12732
13119
|
}
|
|
12733
13120
|
return out;
|
|
12734
13121
|
}
|
|
12735
|
-
function listUserCodexMcpNames(home = (0,
|
|
13122
|
+
function listUserCodexMcpNames(home = (0, import_node_os13.homedir)()) {
|
|
12736
13123
|
const names = [];
|
|
12737
13124
|
for (const path of userCodexConfigPaths(home)) {
|
|
12738
13125
|
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
@@ -12740,7 +13127,7 @@ function listUserCodexMcpNames(home = (0, import_node_os14.homedir)()) {
|
|
|
12740
13127
|
}
|
|
12741
13128
|
return names;
|
|
12742
13129
|
}
|
|
12743
|
-
function listUserOpencodeMcpNames(home = (0,
|
|
13130
|
+
function listUserOpencodeMcpNames(home = (0, import_node_os13.homedir)()) {
|
|
12744
13131
|
const names = [];
|
|
12745
13132
|
for (const path of userOpencodeConfigPaths(home)) {
|
|
12746
13133
|
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
@@ -12748,12 +13135,12 @@ function listUserOpencodeMcpNames(home = (0, import_node_os14.homedir)()) {
|
|
|
12748
13135
|
}
|
|
12749
13136
|
return names;
|
|
12750
13137
|
}
|
|
12751
|
-
function userClaudeMcpConfigObject(home = (0,
|
|
12752
|
-
const claudePath = home === (0,
|
|
13138
|
+
function userClaudeMcpConfigObject(home = (0, import_node_os13.homedir)()) {
|
|
13139
|
+
const claudePath = home === (0, import_node_os13.homedir)() ? userClaudeMcpConfigPath() : (0, import_node_path33.join)(home, ".claude.json");
|
|
12753
13140
|
if (!(0, import_node_fs31.existsSync)(claudePath)) return {};
|
|
12754
13141
|
return asObject(asObject(readJsonObject2(claudePath)).mcpServers);
|
|
12755
13142
|
}
|
|
12756
|
-
function listUserClaudeMcpServerEntries(home = (0,
|
|
13143
|
+
function listUserClaudeMcpServerEntries(home = (0, import_node_os13.homedir)(), projectDirs) {
|
|
12757
13144
|
const out = {};
|
|
12758
13145
|
for (const [name, entry] of Object.entries(
|
|
12759
13146
|
listEnabledClaudePluginMcpServers({ home, projectDirs })
|
|
@@ -12789,13 +13176,13 @@ function toCodexUnattendedAppsArgs() {
|
|
|
12789
13176
|
"features.plugins=false"
|
|
12790
13177
|
];
|
|
12791
13178
|
}
|
|
12792
|
-
var import_node_fs31,
|
|
13179
|
+
var import_node_fs31, import_node_os13, import_node_path33, import_smol_toml2;
|
|
12793
13180
|
var init_orch_mcp_isolation = __esm({
|
|
12794
13181
|
"src/agents/orch-mcp-isolation.ts"() {
|
|
12795
13182
|
"use strict";
|
|
12796
13183
|
import_node_fs31 = require("fs");
|
|
12797
13184
|
init_claude_plugins();
|
|
12798
|
-
|
|
13185
|
+
import_node_os13 = require("os");
|
|
12799
13186
|
import_node_path33 = require("path");
|
|
12800
13187
|
import_smol_toml2 = require("smol-toml");
|
|
12801
13188
|
init_user_mcp_config();
|
|
@@ -12896,7 +13283,7 @@ var init_proxy_server = __esm({
|
|
|
12896
13283
|
|
|
12897
13284
|
// src/mcp-ui/proxy-http.ts
|
|
12898
13285
|
async function listenMcpUiProxy(opts) {
|
|
12899
|
-
const token = (0,
|
|
13286
|
+
const token = (0, import_node_crypto5.randomBytes)(24).toString("hex");
|
|
12900
13287
|
const transports = /* @__PURE__ */ new Map();
|
|
12901
13288
|
const httpServer = (0, import_node_http.createServer)((req, res) => {
|
|
12902
13289
|
void handle(req, res);
|
|
@@ -12934,7 +13321,7 @@ async function listenMcpUiProxy(opts) {
|
|
|
12934
13321
|
return;
|
|
12935
13322
|
}
|
|
12936
13323
|
const created = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
12937
|
-
sessionIdGenerator: () => (0,
|
|
13324
|
+
sessionIdGenerator: () => (0, import_node_crypto5.randomUUID)(),
|
|
12938
13325
|
allowedHosts: ["127.0.0.1", "localhost"],
|
|
12939
13326
|
onsessioninitialized: (id) => {
|
|
12940
13327
|
transports.set(`${sessionKey}:${id}`, created);
|
|
@@ -12987,11 +13374,11 @@ function parseMcpUiProxyPath(url) {
|
|
|
12987
13374
|
return null;
|
|
12988
13375
|
}
|
|
12989
13376
|
}
|
|
12990
|
-
var
|
|
13377
|
+
var import_node_crypto5, import_node_http, import_server2, import_streamableHttp;
|
|
12991
13378
|
var init_proxy_http = __esm({
|
|
12992
13379
|
"src/mcp-ui/proxy-http.ts"() {
|
|
12993
13380
|
"use strict";
|
|
12994
|
-
|
|
13381
|
+
import_node_crypto5 = require("crypto");
|
|
12995
13382
|
import_node_http = require("http");
|
|
12996
13383
|
import_server2 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
12997
13384
|
import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
@@ -13128,7 +13515,7 @@ var init_session = __esm({
|
|
|
13128
13515
|
function getMcpUiHost() {
|
|
13129
13516
|
if (!singleton) {
|
|
13130
13517
|
singleton = new McpUiHost({
|
|
13131
|
-
entries: (projectDirs) => listUserClaudeMcpServerEntries((0,
|
|
13518
|
+
entries: (projectDirs) => listUserClaudeMcpServerEntries((0, import_node_os14.homedir)(), projectDirs)
|
|
13132
13519
|
});
|
|
13133
13520
|
}
|
|
13134
13521
|
return singleton;
|
|
@@ -13136,18 +13523,18 @@ function getMcpUiHost() {
|
|
|
13136
13523
|
async function proxyClaudeUserMcp(orchestrator, projectDirs) {
|
|
13137
13524
|
if (orchestrator) return {};
|
|
13138
13525
|
const dirs = projectDirs.filter((d) => typeof d === "string" && d.length > 0);
|
|
13139
|
-
return getMcpUiHost().proxyEntries(listUserClaudeMcpServerEntries((0,
|
|
13526
|
+
return getMcpUiHost().proxyEntries(listUserClaudeMcpServerEntries((0, import_node_os14.homedir)(), dirs), dirs);
|
|
13140
13527
|
}
|
|
13141
13528
|
function dirsKeyFor(projectDirs) {
|
|
13142
13529
|
if (!projectDirs?.length) return "";
|
|
13143
|
-
return (0,
|
|
13530
|
+
return (0, import_node_crypto6.createHash)("sha256").update(projectDirs.join("\0")).digest("hex").slice(0, 16);
|
|
13144
13531
|
}
|
|
13145
|
-
var
|
|
13532
|
+
var import_node_crypto6, import_node_os14, TOOL_TTL_MS, McpUiHost, singleton;
|
|
13146
13533
|
var init_host = __esm({
|
|
13147
13534
|
"src/mcp-ui/host.ts"() {
|
|
13148
13535
|
"use strict";
|
|
13149
|
-
|
|
13150
|
-
|
|
13536
|
+
import_node_crypto6 = require("crypto");
|
|
13537
|
+
import_node_os14 = require("os");
|
|
13151
13538
|
init_orch_mcp_isolation();
|
|
13152
13539
|
init_meta();
|
|
13153
13540
|
init_proxy_http();
|
|
@@ -14268,8 +14655,8 @@ function usageFromCodex(usage) {
|
|
|
14268
14655
|
}
|
|
14269
14656
|
function codexConfigHasNetworkAccess() {
|
|
14270
14657
|
const candidates = [
|
|
14271
|
-
(0, import_node_path36.join)((0,
|
|
14272
|
-
(0, import_node_path36.join)((0,
|
|
14658
|
+
(0, import_node_path36.join)((0, import_node_os15.homedir)(), ".codex", "config.toml"),
|
|
14659
|
+
(0, import_node_path36.join)((0, import_node_os15.homedir)(), ".config", "codex", "config.toml")
|
|
14273
14660
|
];
|
|
14274
14661
|
for (const path of candidates) {
|
|
14275
14662
|
if (!(0, import_node_fs35.existsSync)(path)) continue;
|
|
@@ -14305,7 +14692,7 @@ function asRecord5(value) {
|
|
|
14305
14692
|
return void 0;
|
|
14306
14693
|
}
|
|
14307
14694
|
function codexLooksAuthenticated() {
|
|
14308
|
-
const authPath = (0, import_node_path36.join)((0,
|
|
14695
|
+
const authPath = (0, import_node_path36.join)((0, import_node_os15.homedir)(), ".codex", "auth.json");
|
|
14309
14696
|
if (!(0, import_node_fs35.existsSync)(authPath)) return false;
|
|
14310
14697
|
try {
|
|
14311
14698
|
return (0, import_node_fs35.statSync)(authPath).size > 2;
|
|
@@ -14313,12 +14700,12 @@ function codexLooksAuthenticated() {
|
|
|
14313
14700
|
return false;
|
|
14314
14701
|
}
|
|
14315
14702
|
}
|
|
14316
|
-
var import_node_fs35,
|
|
14703
|
+
var import_node_fs35, import_node_os15, import_node_path36, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
14317
14704
|
var init_codex = __esm({
|
|
14318
14705
|
"src/agents/codex.ts"() {
|
|
14319
14706
|
"use strict";
|
|
14320
14707
|
import_node_fs35 = require("fs");
|
|
14321
|
-
|
|
14708
|
+
import_node_os15 = require("os");
|
|
14322
14709
|
import_node_path36 = require("path");
|
|
14323
14710
|
init_run();
|
|
14324
14711
|
init_app_settings();
|
|
@@ -15771,12 +16158,12 @@ var init_claude_usage = __esm({
|
|
|
15771
16158
|
});
|
|
15772
16159
|
|
|
15773
16160
|
// src/agents/claude-usage-client.ts
|
|
15774
|
-
var import_node_fs41,
|
|
16161
|
+
var import_node_fs41, import_node_os16, import_node_path41, CLAUDE_USAGE_ERROR_TTL_MS, CLAUDE_USAGE_STALE_OK_MS;
|
|
15775
16162
|
var init_claude_usage_client = __esm({
|
|
15776
16163
|
"src/agents/claude-usage-client.ts"() {
|
|
15777
16164
|
"use strict";
|
|
15778
16165
|
import_node_fs41 = require("fs");
|
|
15779
|
-
|
|
16166
|
+
import_node_os16 = require("os");
|
|
15780
16167
|
import_node_path41 = require("path");
|
|
15781
16168
|
init_run();
|
|
15782
16169
|
init_fetch();
|
|
@@ -16426,7 +16813,9 @@ function resolveSidebarGitPrompt(action, opts) {
|
|
|
16426
16813
|
}
|
|
16427
16814
|
return agentGitPrompt(action, opts);
|
|
16428
16815
|
}
|
|
16429
|
-
function gitActionExpansion(action, base) {
|
|
16816
|
+
function gitActionExpansion(action, base, forge) {
|
|
16817
|
+
if (forge === "cursor") return cursorGitActionExpansion(action, base);
|
|
16818
|
+
if (forge === "entire") return entireGitActionExpansion(action, base);
|
|
16430
16819
|
switch (action) {
|
|
16431
16820
|
case "commit-push":
|
|
16432
16821
|
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.";
|
|
@@ -16451,7 +16840,57 @@ function gitActionExpansion(action, base) {
|
|
|
16451
16840
|
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.";
|
|
16452
16841
|
}
|
|
16453
16842
|
}
|
|
16454
|
-
function
|
|
16843
|
+
function cursorGitActionExpansion(action, base) {
|
|
16844
|
+
switch (action) {
|
|
16845
|
+
case "commit-push":
|
|
16846
|
+
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.";
|
|
16847
|
+
case "create-draft":
|
|
16848
|
+
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`.";
|
|
16849
|
+
case "create-web":
|
|
16850
|
+
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`.";
|
|
16851
|
+
case "resolve-conflicts":
|
|
16852
|
+
if (base && !isMainishPrBase(base)) {
|
|
16853
|
+
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.`;
|
|
16854
|
+
}
|
|
16855
|
+
if (base) {
|
|
16856
|
+
return `Fetch the PR base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
|
|
16857
|
+
}
|
|
16858
|
+
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`.";
|
|
16859
|
+
case "ready-for-review":
|
|
16860
|
+
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`.";
|
|
16861
|
+
case "merge":
|
|
16862
|
+
if (base && !isMainishPrBase(base)) {
|
|
16863
|
+
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\`.`;
|
|
16864
|
+
}
|
|
16865
|
+
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`.";
|
|
16866
|
+
}
|
|
16867
|
+
}
|
|
16868
|
+
function entireGitActionExpansion(action, base) {
|
|
16869
|
+
switch (action) {
|
|
16870
|
+
case "commit-push":
|
|
16871
|
+
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.";
|
|
16872
|
+
case "create-draft":
|
|
16873
|
+
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`.';
|
|
16874
|
+
case "create-web":
|
|
16875
|
+
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`.';
|
|
16876
|
+
case "resolve-conflicts":
|
|
16877
|
+
if (base && !isMainishPrBase(base)) {
|
|
16878
|
+
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.`;
|
|
16879
|
+
}
|
|
16880
|
+
if (base) {
|
|
16881
|
+
return `Fetch the Trail base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push.`;
|
|
16882
|
+
}
|
|
16883
|
+
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`.";
|
|
16884
|
+
case "ready-for-review":
|
|
16885
|
+
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`.";
|
|
16886
|
+
case "merge":
|
|
16887
|
+
if (base && !isMainishPrBase(base)) {
|
|
16888
|
+
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\`.`;
|
|
16889
|
+
}
|
|
16890
|
+
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`.";
|
|
16891
|
+
}
|
|
16892
|
+
}
|
|
16893
|
+
function expandCanonicalGitRequest(prompt, opts) {
|
|
16455
16894
|
const trimmed = prompt.trim();
|
|
16456
16895
|
let action = null;
|
|
16457
16896
|
let base = null;
|
|
@@ -16476,11 +16915,12 @@ function expandCanonicalGitRequest(prompt) {
|
|
|
16476
16915
|
base = m[1]?.trim() || null;
|
|
16477
16916
|
}
|
|
16478
16917
|
}
|
|
16479
|
-
|
|
16918
|
+
const forge = opts?.forge ?? null;
|
|
16919
|
+
let expansion = action ? gitActionExpansion(action, base, forge) : null;
|
|
16480
16920
|
if (!expansion && trimmed === "Address review comments.") {
|
|
16481
|
-
expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
|
|
16921
|
+
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.";
|
|
16482
16922
|
} else if (!expansion && FIX_CI_RE.test(trimmed)) {
|
|
16483
|
-
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.";
|
|
16923
|
+
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.";
|
|
16484
16924
|
}
|
|
16485
16925
|
if (!expansion) return prompt;
|
|
16486
16926
|
return `${trimmed}
|
|
@@ -17211,7 +17651,7 @@ function forkMessageSlice(from, throughIndex) {
|
|
|
17211
17651
|
function buildForkTranscriptAttachment(baseTitle, messages) {
|
|
17212
17652
|
const title = baseTitle || "Chat";
|
|
17213
17653
|
return {
|
|
17214
|
-
id: (0,
|
|
17654
|
+
id: (0, import_node_crypto7.randomUUID)(),
|
|
17215
17655
|
name: `Transcript of ${title}.md`,
|
|
17216
17656
|
kind: "transcript",
|
|
17217
17657
|
content: formatTranscriptMarkdown(title, messages)
|
|
@@ -17270,11 +17710,11 @@ function forkChatTab(input) {
|
|
|
17270
17710
|
}
|
|
17271
17711
|
return tab;
|
|
17272
17712
|
}
|
|
17273
|
-
var
|
|
17713
|
+
var import_node_crypto7;
|
|
17274
17714
|
var init_chat_tabs = __esm({
|
|
17275
17715
|
"src/threads/chat-tabs.ts"() {
|
|
17276
17716
|
"use strict";
|
|
17277
|
-
|
|
17717
|
+
import_node_crypto7 = require("crypto");
|
|
17278
17718
|
init_context_compact();
|
|
17279
17719
|
init_teams();
|
|
17280
17720
|
init_worktree_labels();
|
|
@@ -17516,7 +17956,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
17516
17956
|
const path = opts?.path ?? REVIEW_SKILL_PATH;
|
|
17517
17957
|
const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH || path === CONTEXT_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
17518
17958
|
return {
|
|
17519
|
-
id: (0,
|
|
17959
|
+
id: (0, import_node_crypto8.randomUUID)(),
|
|
17520
17960
|
name,
|
|
17521
17961
|
kind: "file",
|
|
17522
17962
|
path,
|
|
@@ -17569,11 +18009,11 @@ async function requestReview(threadRef, send) {
|
|
|
17569
18009
|
const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
|
|
17570
18010
|
return { tab: started, from };
|
|
17571
18011
|
}
|
|
17572
|
-
var
|
|
18012
|
+
var import_node_crypto8, import_node_fs44, import_node_path44, 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;
|
|
17573
18013
|
var init_request_review = __esm({
|
|
17574
18014
|
"src/review/request-review.ts"() {
|
|
17575
18015
|
"use strict";
|
|
17576
|
-
|
|
18016
|
+
import_node_crypto8 = require("crypto");
|
|
17577
18017
|
import_node_fs44 = require("fs");
|
|
17578
18018
|
import_node_path44 = require("path");
|
|
17579
18019
|
init_global_workspace();
|
|
@@ -18831,7 +19271,7 @@ function setupLogPath(threadId) {
|
|
|
18831
19271
|
}
|
|
18832
19272
|
function setupLogKeyForWorktree(worktreePath) {
|
|
18833
19273
|
const norm = normalizeWorktreePath(worktreePath);
|
|
18834
|
-
return `wt-${(0,
|
|
19274
|
+
return `wt-${(0, import_node_crypto9.createHash)("sha1").update(norm).digest("hex").slice(0, 16)}`;
|
|
18835
19275
|
}
|
|
18836
19276
|
function emptySetupLog() {
|
|
18837
19277
|
return { ...EMPTY };
|
|
@@ -18924,11 +19364,11 @@ function finishSetupLog(threadId, exitCode, source) {
|
|
|
18924
19364
|
persistNow(threadId);
|
|
18925
19365
|
return materialize(mem);
|
|
18926
19366
|
}
|
|
18927
|
-
var
|
|
19367
|
+
var import_node_crypto9, import_node_fs48, import_node_path48, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
|
|
18928
19368
|
var init_setup_log = __esm({
|
|
18929
19369
|
"src/store/setup-log.ts"() {
|
|
18930
19370
|
"use strict";
|
|
18931
|
-
|
|
19371
|
+
import_node_crypto9 = require("crypto");
|
|
18932
19372
|
import_node_fs48 = require("fs");
|
|
18933
19373
|
import_node_path48 = require("path");
|
|
18934
19374
|
init_worktree_labels();
|
|
@@ -18979,7 +19419,7 @@ function runLogPath(key) {
|
|
|
18979
19419
|
}
|
|
18980
19420
|
function runLogKeyForWorktree(worktreePath, scriptName) {
|
|
18981
19421
|
const norm = normalizeWorktreePath(worktreePath);
|
|
18982
|
-
const hash = (0,
|
|
19422
|
+
const hash = (0, import_node_crypto10.createHash)("sha1").update(norm).digest("hex").slice(0, 16);
|
|
18983
19423
|
return `wt-${hash}-run-${safeScriptToken(scriptName)}`;
|
|
18984
19424
|
}
|
|
18985
19425
|
function emptyRunLog() {
|
|
@@ -19080,11 +19520,11 @@ function finishRunLog(key, exitCode) {
|
|
|
19080
19520
|
function flushRunLog(key) {
|
|
19081
19521
|
persistNow2(key);
|
|
19082
19522
|
}
|
|
19083
|
-
var
|
|
19523
|
+
var import_node_crypto10, import_node_fs49, import_node_path49, EMPTY2, MAX_RUN_LOG_CHARS, DEFAULT_RUN_LOG_TAIL_CHARS, memory2, persistTimers2, PERSIST_DEBOUNCE_MS2;
|
|
19084
19524
|
var init_run_log = __esm({
|
|
19085
19525
|
"src/store/run-log.ts"() {
|
|
19086
19526
|
"use strict";
|
|
19087
|
-
|
|
19527
|
+
import_node_crypto10 = require("crypto");
|
|
19088
19528
|
import_node_fs49 = require("fs");
|
|
19089
19529
|
import_node_path49 = require("path");
|
|
19090
19530
|
init_worktree_labels();
|
|
@@ -19510,11 +19950,11 @@ function denyPendingToolPermissions(threadId) {
|
|
|
19510
19950
|
const last = pending[pending.length - 1];
|
|
19511
19951
|
if (last) clearPrompt(threadId, last.id);
|
|
19512
19952
|
}
|
|
19513
|
-
var
|
|
19953
|
+
var import_node_crypto11, import_node_path53, queues, publisher;
|
|
19514
19954
|
var init_tool_permission = __esm({
|
|
19515
19955
|
"src/agents/tool-permission.ts"() {
|
|
19516
19956
|
"use strict";
|
|
19517
|
-
|
|
19957
|
+
import_node_crypto11 = require("crypto");
|
|
19518
19958
|
import_node_path53 = require("path");
|
|
19519
19959
|
init_claude_mcp();
|
|
19520
19960
|
queues = /* @__PURE__ */ new Map();
|
|
@@ -20046,7 +20486,7 @@ function isUnclaimedSteerRequest(req) {
|
|
|
20046
20486
|
}
|
|
20047
20487
|
function nextSteerRequest(existing) {
|
|
20048
20488
|
if (existing?.requestId && !existing.claimedAt) return existing;
|
|
20049
|
-
return { requestId: (0,
|
|
20489
|
+
return { requestId: (0, import_node_crypto12.randomUUID)(), requestedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
20050
20490
|
}
|
|
20051
20491
|
function claimSteerRequest(threadId) {
|
|
20052
20492
|
const pending = readThread(threadId)?.steerRequest;
|
|
@@ -20055,11 +20495,11 @@ function claimSteerRequest(threadId) {
|
|
|
20055
20495
|
steerRequest: { ...pending, claimedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
20056
20496
|
});
|
|
20057
20497
|
}
|
|
20058
|
-
var
|
|
20498
|
+
var import_node_crypto12;
|
|
20059
20499
|
var init_steer_request = __esm({
|
|
20060
20500
|
"src/orchestrator/steer-request.ts"() {
|
|
20061
20501
|
"use strict";
|
|
20062
|
-
|
|
20502
|
+
import_node_crypto12 = require("crypto");
|
|
20063
20503
|
init_thread_store();
|
|
20064
20504
|
}
|
|
20065
20505
|
});
|
|
@@ -20927,8 +21367,8 @@ function resolveAbleTimeOAuthHost(requested, saved) {
|
|
|
20927
21367
|
return fromSaved || void 0;
|
|
20928
21368
|
}
|
|
20929
21369
|
function createAbleTimePkce() {
|
|
20930
|
-
const verifier = (0,
|
|
20931
|
-
const challenge = (0,
|
|
21370
|
+
const verifier = (0, import_node_crypto13.randomBytes)(32).toString("base64url");
|
|
21371
|
+
const challenge = (0, import_node_crypto13.createHash)("sha256").update(verifier).digest("base64url");
|
|
20932
21372
|
return { verifier, challenge };
|
|
20933
21373
|
}
|
|
20934
21374
|
function ableTimeOAuthAuthorizeUrl(clientId, state, codeChallenge, host) {
|
|
@@ -21033,7 +21473,7 @@ async function startAbleTimeOAuth(opts) {
|
|
|
21033
21473
|
opts?.host,
|
|
21034
21474
|
loadAppSettings().integrations.abletimeHost
|
|
21035
21475
|
);
|
|
21036
|
-
const state = (0,
|
|
21476
|
+
const state = (0, import_node_crypto13.randomBytes)(16).toString("hex");
|
|
21037
21477
|
const pkce = createAbleTimePkce();
|
|
21038
21478
|
const authorizeUrl = ableTimeOAuthAuthorizeUrl(clientId, state, pkce.challenge, host);
|
|
21039
21479
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
@@ -21133,11 +21573,11 @@ async function startAbleTimeOAuth(opts) {
|
|
|
21133
21573
|
return loadAppSettings();
|
|
21134
21574
|
}
|
|
21135
21575
|
}
|
|
21136
|
-
var
|
|
21576
|
+
var import_node_crypto13, 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;
|
|
21137
21577
|
var init_abletime_oauth = __esm({
|
|
21138
21578
|
"src/integrations/abletime-oauth.ts"() {
|
|
21139
21579
|
"use strict";
|
|
21140
|
-
|
|
21580
|
+
import_node_crypto13 = require("crypto");
|
|
21141
21581
|
import_node_http2 = require("http");
|
|
21142
21582
|
init_fetch();
|
|
21143
21583
|
init_app_settings();
|
|
@@ -21898,7 +22338,7 @@ function uniqueAttachmentFileName(dir, originalName) {
|
|
|
21898
22338
|
const candidate = `${stem}-${i}${ext}`;
|
|
21899
22339
|
if (!(0, import_node_fs53.existsSync)((0, import_node_path54.join)(dir, candidate))) return candidate;
|
|
21900
22340
|
}
|
|
21901
|
-
return `${stem}-${(0,
|
|
22341
|
+
return `${stem}-${(0, import_node_crypto14.randomUUID)()}${ext}`;
|
|
21902
22342
|
}
|
|
21903
22343
|
function extractHttpUrls(markdown) {
|
|
21904
22344
|
const text7 = markdown ?? "";
|
|
@@ -22004,13 +22444,13 @@ async function downloadAuthenticatedFile(opts) {
|
|
|
22004
22444
|
...contentType ? { contentType } : {}
|
|
22005
22445
|
};
|
|
22006
22446
|
}
|
|
22007
|
-
var import_node_fs53, import_node_path54,
|
|
22447
|
+
var import_node_fs53, import_node_path54, import_node_crypto14, ISSUE_ATTACHMENT_MAX_BYTES, MARKDOWN_IMAGE_RE, MARKDOWN_LINK_RE, HTML_SRC_RE, BARE_URL_RE, EXT_BY_MIME;
|
|
22008
22448
|
var init_issue_attachments = __esm({
|
|
22009
22449
|
"src/integrations/issue-attachments.ts"() {
|
|
22010
22450
|
"use strict";
|
|
22011
22451
|
import_node_fs53 = require("fs");
|
|
22012
22452
|
import_node_path54 = require("path");
|
|
22013
|
-
|
|
22453
|
+
import_node_crypto14 = require("crypto");
|
|
22014
22454
|
init_fetch();
|
|
22015
22455
|
init_workspace_scratch();
|
|
22016
22456
|
ISSUE_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;
|
|
@@ -23629,7 +24069,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
23629
24069
|
...instructions
|
|
23630
24070
|
].join("\n");
|
|
23631
24071
|
return {
|
|
23632
|
-
id: (0,
|
|
24072
|
+
id: (0, import_node_crypto15.randomUUID)(),
|
|
23633
24073
|
name: orch ? "Orchestration quota handoff.md" : "Quota handoff.md",
|
|
23634
24074
|
kind: "transcript",
|
|
23635
24075
|
content: body
|
|
@@ -23667,11 +24107,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
|
|
|
23667
24107
|
}
|
|
23668
24108
|
return updateThread(tab.id, patch);
|
|
23669
24109
|
}
|
|
23670
|
-
var
|
|
24110
|
+
var import_node_crypto15, QUOTA_CONTINUE_PROMPT, QUOTA_CONTINUE_ACCOUNT_PROMPT, QUOTA_RESUME_PROMPT;
|
|
23671
24111
|
var init_quota_failover = __esm({
|
|
23672
24112
|
"src/orchestrator/quota-failover.ts"() {
|
|
23673
24113
|
"use strict";
|
|
23674
|
-
|
|
24114
|
+
import_node_crypto15 = require("crypto");
|
|
23675
24115
|
init_session_quota();
|
|
23676
24116
|
init_app_settings();
|
|
23677
24117
|
init_managed_accounts();
|
|
@@ -23778,7 +24218,7 @@ function listConductorWorkspaces() {
|
|
|
23778
24218
|
if (!(0, import_node_fs56.existsSync)(CONDUCTOR_DB)) {
|
|
23779
24219
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
23780
24220
|
}
|
|
23781
|
-
const tmp = (0, import_node_fs56.mkdtempSync)((0, import_node_path56.join)((0,
|
|
24221
|
+
const tmp = (0, import_node_fs56.mkdtempSync)((0, import_node_path56.join)((0, import_node_os17.tmpdir)(), "sideboard-conductor-"));
|
|
23782
24222
|
const snapshot = (0, import_node_path56.join)(tmp, "conductor.db");
|
|
23783
24223
|
try {
|
|
23784
24224
|
(0, import_node_fs56.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
@@ -23869,7 +24309,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
23869
24309
|
if (!(0, import_node_fs56.existsSync)(CONDUCTOR_DB)) {
|
|
23870
24310
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
23871
24311
|
}
|
|
23872
|
-
const tmp = (0, import_node_fs56.mkdtempSync)((0, import_node_path56.join)((0,
|
|
24312
|
+
const tmp = (0, import_node_fs56.mkdtempSync)((0, import_node_path56.join)((0, import_node_os17.tmpdir)(), "sideboard-conductor-"));
|
|
23873
24313
|
const snapshot = (0, import_node_path56.join)(tmp, "conductor.db");
|
|
23874
24314
|
try {
|
|
23875
24315
|
(0, import_node_fs56.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
@@ -23964,13 +24404,13 @@ function importConductorWorkspace(workspaceId) {
|
|
|
23964
24404
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
23965
24405
|
return importConductorWorkspace(workspaceId);
|
|
23966
24406
|
}
|
|
23967
|
-
var import_node_child_process5, import_node_fs56,
|
|
24407
|
+
var import_node_child_process5, import_node_fs56, import_node_os17, import_node_path56, import_node_module6, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
|
|
23968
24408
|
var init_adopt = __esm({
|
|
23969
24409
|
"src/threads/adopt.ts"() {
|
|
23970
24410
|
"use strict";
|
|
23971
24411
|
import_node_child_process5 = require("child_process");
|
|
23972
24412
|
import_node_fs56 = require("fs");
|
|
23973
|
-
|
|
24413
|
+
import_node_os17 = require("os");
|
|
23974
24414
|
import_node_path56 = require("path");
|
|
23975
24415
|
import_node_module6 = require("module");
|
|
23976
24416
|
init_worktree();
|
|
@@ -24284,9 +24724,187 @@ var init_stack_layers = __esm({
|
|
|
24284
24724
|
}
|
|
24285
24725
|
});
|
|
24286
24726
|
|
|
24727
|
+
// src/git/pr-write.ts
|
|
24728
|
+
async function lookupGithubGraphqlReset(cwd) {
|
|
24729
|
+
const result = await gh(["api", "rate_limit"], cwd, { reject: false });
|
|
24730
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) return void 0;
|
|
24731
|
+
try {
|
|
24732
|
+
const data = JSON.parse(result.stdout);
|
|
24733
|
+
const reset = data.resources?.graphql?.reset;
|
|
24734
|
+
return typeof reset === "number" ? reset : void 0;
|
|
24735
|
+
} catch {
|
|
24736
|
+
return void 0;
|
|
24737
|
+
}
|
|
24738
|
+
}
|
|
24739
|
+
async function formatPrCreateFailure(raw, cwd, ctx) {
|
|
24740
|
+
if (!isGhRateLimitError(raw)) {
|
|
24741
|
+
return formatGhLandError(raw, {
|
|
24742
|
+
targetedRepo: ctx?.slug,
|
|
24743
|
+
headRef: ctx?.head
|
|
24744
|
+
});
|
|
24745
|
+
}
|
|
24746
|
+
const resetAt = await lookupGithubGraphqlReset(cwd);
|
|
24747
|
+
return formatGhLandError(raw, {
|
|
24748
|
+
resetAt,
|
|
24749
|
+
targetedRepo: ctx?.slug,
|
|
24750
|
+
headRef: ctx?.head
|
|
24751
|
+
});
|
|
24752
|
+
}
|
|
24753
|
+
async function createCursorPullRequest(worktreePath, slug, opts) {
|
|
24754
|
+
const bodyText = (opts.body ?? opts.title).trim() || opts.title;
|
|
24755
|
+
const bodyFile = (0, import_node_path57.join)(
|
|
24756
|
+
(0, import_node_os18.tmpdir)(),
|
|
24757
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto16.randomBytes)(6).toString("hex")}.md`
|
|
24758
|
+
);
|
|
24759
|
+
(0, import_node_fs58.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
24760
|
+
`, "utf8");
|
|
24761
|
+
try {
|
|
24762
|
+
return await createOrUpdateCursorPr(worktreePath, slug, {
|
|
24763
|
+
title: opts.title,
|
|
24764
|
+
bodyFile,
|
|
24765
|
+
base: opts.base,
|
|
24766
|
+
head: opts.head,
|
|
24767
|
+
draft: opts.draft
|
|
24768
|
+
});
|
|
24769
|
+
} finally {
|
|
24770
|
+
try {
|
|
24771
|
+
(0, import_node_fs58.unlinkSync)(bodyFile);
|
|
24772
|
+
} catch {
|
|
24773
|
+
}
|
|
24774
|
+
}
|
|
24775
|
+
}
|
|
24776
|
+
function ghPrCreateAssigneeArgs(assignee) {
|
|
24777
|
+
const raw = assignee?.trim();
|
|
24778
|
+
if (raw && /^(none|unassigned)$/i.test(raw)) return [];
|
|
24779
|
+
return ["--assignee", raw || "@me"];
|
|
24780
|
+
}
|
|
24781
|
+
async function createOrUpdatePr(worktreePath, opts) {
|
|
24782
|
+
const origin = await resolveOriginRemote(worktreePath);
|
|
24783
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
24784
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
24785
|
+
if (cursorSlug) return createCursorPullRequest(worktreePath, cursorSlug, opts);
|
|
24786
|
+
await ensureGhPreferOrigin(worktreePath);
|
|
24787
|
+
const slug = await resolveGithubRepoSlug(worktreePath);
|
|
24788
|
+
if (!slug) {
|
|
24789
|
+
throw new Error(
|
|
24790
|
+
"Could not resolve the origin GitHub repo (owner/name) for this worktree. Check that `git remote get-url origin` points at github.com."
|
|
24791
|
+
);
|
|
24792
|
+
}
|
|
24793
|
+
const repoArgs2 = ghRepoSelectArgs(slug);
|
|
24794
|
+
const headRef = ghHeadRef(slug, opts.head);
|
|
24795
|
+
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
24796
|
+
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
24797
|
+
const bodyFile = (0, import_node_path57.join)(
|
|
24798
|
+
(0, import_node_os18.tmpdir)(),
|
|
24799
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto16.randomBytes)(6).toString("hex")}.md`
|
|
24800
|
+
);
|
|
24801
|
+
(0, import_node_fs58.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
24802
|
+
`, "utf8");
|
|
24803
|
+
const bodyArgs = ["--body-file", bodyFile];
|
|
24804
|
+
try {
|
|
24805
|
+
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
24806
|
+
...opts,
|
|
24807
|
+
slug,
|
|
24808
|
+
repoArgs: repoArgs2,
|
|
24809
|
+
headRef,
|
|
24810
|
+
branchOnly,
|
|
24811
|
+
bodyArgs
|
|
24812
|
+
});
|
|
24813
|
+
} finally {
|
|
24814
|
+
try {
|
|
24815
|
+
(0, import_node_fs58.unlinkSync)(bodyFile);
|
|
24816
|
+
} catch {
|
|
24817
|
+
}
|
|
24818
|
+
}
|
|
24819
|
+
}
|
|
24820
|
+
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
24821
|
+
const { slug, repoArgs: repoArgs2, headRef, branchOnly, bodyArgs } = opts;
|
|
24822
|
+
const existing = await gh(
|
|
24823
|
+
[...repoArgs2, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
24824
|
+
worktreePath,
|
|
24825
|
+
{ reject: false }
|
|
24826
|
+
);
|
|
24827
|
+
if (existing.exitCode === 0 && existing.stdout.trim() && !opts.web) {
|
|
24828
|
+
const url2 = existing.stdout.trim();
|
|
24829
|
+
await gh(
|
|
24830
|
+
[
|
|
24831
|
+
...repoArgs2,
|
|
24832
|
+
"pr",
|
|
24833
|
+
"edit",
|
|
24834
|
+
branchOnly,
|
|
24835
|
+
"--title",
|
|
24836
|
+
opts.title,
|
|
24837
|
+
...bodyArgs
|
|
24838
|
+
],
|
|
24839
|
+
worktreePath,
|
|
24840
|
+
{ reject: false }
|
|
24841
|
+
);
|
|
24842
|
+
return url2;
|
|
24843
|
+
}
|
|
24844
|
+
if (opts.web) {
|
|
24845
|
+
const args2 = [
|
|
24846
|
+
...repoArgs2,
|
|
24847
|
+
"pr",
|
|
24848
|
+
"create",
|
|
24849
|
+
"--web",
|
|
24850
|
+
"--title",
|
|
24851
|
+
opts.title,
|
|
24852
|
+
...bodyArgs,
|
|
24853
|
+
"--base",
|
|
24854
|
+
opts.base,
|
|
24855
|
+
"--head",
|
|
24856
|
+
headRef
|
|
24857
|
+
];
|
|
24858
|
+
if (opts.draft) args2.push("--draft");
|
|
24859
|
+
args2.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
24860
|
+
await gh(args2, worktreePath, { reject: false });
|
|
24861
|
+
const again = await gh(
|
|
24862
|
+
[...repoArgs2, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
24863
|
+
worktreePath,
|
|
24864
|
+
{ reject: false }
|
|
24865
|
+
);
|
|
24866
|
+
return again.stdout.trim() || "";
|
|
24867
|
+
}
|
|
24868
|
+
const args = [
|
|
24869
|
+
...repoArgs2,
|
|
24870
|
+
"pr",
|
|
24871
|
+
"create",
|
|
24872
|
+
"--title",
|
|
24873
|
+
opts.title,
|
|
24874
|
+
...bodyArgs,
|
|
24875
|
+
"--base",
|
|
24876
|
+
opts.base,
|
|
24877
|
+
"--head",
|
|
24878
|
+
headRef
|
|
24879
|
+
];
|
|
24880
|
+
if (opts.draft) args.push("--draft");
|
|
24881
|
+
args.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
24882
|
+
const created = await gh(args, worktreePath, { reject: false });
|
|
24883
|
+
if (created.exitCode !== 0) {
|
|
24884
|
+
const raw = created.stderr.trim() || created.stdout.trim() || "gh pr create failed";
|
|
24885
|
+
throw new Error(await formatPrCreateFailure(raw, worktreePath, { slug, head: headRef }));
|
|
24886
|
+
}
|
|
24887
|
+
const url = created.stdout.trim().split("\n").find((l) => l.startsWith("http")) ?? created.stdout.trim();
|
|
24888
|
+
return url;
|
|
24889
|
+
}
|
|
24890
|
+
var import_node_crypto16, import_node_fs58, import_node_os18, import_node_path57;
|
|
24891
|
+
var init_pr_write = __esm({
|
|
24892
|
+
"src/git/pr-write.ts"() {
|
|
24893
|
+
"use strict";
|
|
24894
|
+
import_node_crypto16 = require("crypto");
|
|
24895
|
+
import_node_fs58 = require("fs");
|
|
24896
|
+
import_node_os18 = require("os");
|
|
24897
|
+
import_node_path57 = require("path");
|
|
24898
|
+
init_gh_errors();
|
|
24899
|
+
init_run();
|
|
24900
|
+
init_cursor_pr();
|
|
24901
|
+
init_worktree();
|
|
24902
|
+
}
|
|
24903
|
+
});
|
|
24904
|
+
|
|
24287
24905
|
// src/diff/diff.ts
|
|
24288
24906
|
async function inspectGitWorktree(worktreePath) {
|
|
24289
|
-
if (!worktreePath || !(0,
|
|
24907
|
+
if (!worktreePath || !(0, import_node_fs59.existsSync)(worktreePath)) return "missing_worktree";
|
|
24290
24908
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
24291
24909
|
reject: false
|
|
24292
24910
|
});
|
|
@@ -24294,7 +24912,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
24294
24912
|
return "ok";
|
|
24295
24913
|
}
|
|
24296
24914
|
async function initializeGitRepository(worktreePath) {
|
|
24297
|
-
if (!worktreePath || !(0,
|
|
24915
|
+
if (!worktreePath || !(0, import_node_fs59.existsSync)(worktreePath)) {
|
|
24298
24916
|
throw new Error("Worktree not found");
|
|
24299
24917
|
}
|
|
24300
24918
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -24428,11 +25046,11 @@ new file mode 100644
|
|
|
24428
25046
|
};
|
|
24429
25047
|
}
|
|
24430
25048
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
24431
|
-
const abs = (0,
|
|
25049
|
+
const abs = (0, import_node_path58.join)(worktreePath, path);
|
|
24432
25050
|
try {
|
|
24433
|
-
const st = (0,
|
|
25051
|
+
const st = (0, import_node_fs59.statSync)(abs);
|
|
24434
25052
|
if (st.isFile() && st.size > maxHunk) {
|
|
24435
|
-
const buf = (0,
|
|
25053
|
+
const buf = (0, import_node_fs59.readFileSync)(abs).subarray(0, maxHunk);
|
|
24436
25054
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
24437
25055
|
}
|
|
24438
25056
|
} catch {
|
|
@@ -24899,9 +25517,9 @@ async function getDiff(worktreePath, repoPath, opts) {
|
|
|
24899
25517
|
}
|
|
24900
25518
|
function statWorktreePath(worktreePath, relativePath) {
|
|
24901
25519
|
assertSafeRelativePath(relativePath);
|
|
24902
|
-
const abs = (0,
|
|
24903
|
-
if (!(0,
|
|
24904
|
-
const st = (0,
|
|
25520
|
+
const abs = (0, import_node_path58.join)(worktreePath, relativePath);
|
|
25521
|
+
if (!(0, import_node_fs59.existsSync)(abs)) return "missing";
|
|
25522
|
+
const st = (0, import_node_fs59.statSync)(abs);
|
|
24905
25523
|
if (st.isDirectory()) return "dir";
|
|
24906
25524
|
if (st.isFile()) return "file";
|
|
24907
25525
|
return "missing";
|
|
@@ -24930,8 +25548,8 @@ function isImageRelativePath(relativePath) {
|
|
|
24930
25548
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
24931
25549
|
assertSafeRelativePath(relativePath);
|
|
24932
25550
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
24933
|
-
const abs = (0,
|
|
24934
|
-
const st = (0,
|
|
25551
|
+
const abs = (0, import_node_path58.join)(worktreePath, relativePath);
|
|
25552
|
+
const st = (0, import_node_fs59.statSync)(abs);
|
|
24935
25553
|
if (!st.isFile()) {
|
|
24936
25554
|
throw new Error(`Not a file: ${relativePath}`);
|
|
24937
25555
|
}
|
|
@@ -24940,7 +25558,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
24940
25558
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
24941
25559
|
);
|
|
24942
25560
|
}
|
|
24943
|
-
const buf = (0,
|
|
25561
|
+
const buf = (0, import_node_fs59.readFileSync)(abs);
|
|
24944
25562
|
return {
|
|
24945
25563
|
path: relativePath,
|
|
24946
25564
|
contentBase64: buf.toString("base64"),
|
|
@@ -24950,12 +25568,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
24950
25568
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
24951
25569
|
assertSafeRelativePath(relativePath);
|
|
24952
25570
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
24953
|
-
const abs = (0,
|
|
24954
|
-
const st = (0,
|
|
25571
|
+
const abs = (0, import_node_path58.join)(worktreePath, relativePath);
|
|
25572
|
+
const st = (0, import_node_fs59.statSync)(abs);
|
|
24955
25573
|
if (!st.isFile()) {
|
|
24956
25574
|
throw new Error(`Not a file: ${relativePath}`);
|
|
24957
25575
|
}
|
|
24958
|
-
const buf = (0,
|
|
25576
|
+
const buf = (0, import_node_fs59.readFileSync)(abs);
|
|
24959
25577
|
if (isImageRelativePath(relativePath)) {
|
|
24960
25578
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
24961
25579
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -24998,9 +25616,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
24998
25616
|
}
|
|
24999
25617
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
25000
25618
|
assertSafeRelativePath(relativePath);
|
|
25001
|
-
const abs = (0,
|
|
25002
|
-
(0,
|
|
25003
|
-
(0,
|
|
25619
|
+
const abs = (0, import_node_path58.join)(worktreePath, relativePath);
|
|
25620
|
+
(0, import_node_fs59.mkdirSync)((0, import_node_path58.dirname)(abs), { recursive: true });
|
|
25621
|
+
(0, import_node_fs59.writeFileSync)(abs, content, "utf8");
|
|
25004
25622
|
return { path: relativePath };
|
|
25005
25623
|
}
|
|
25006
25624
|
async function getWorktreeDirtyStat(worktreePath) {
|
|
@@ -25040,12 +25658,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
25040
25658
|
truncated: full.files.length > maxFiles
|
|
25041
25659
|
};
|
|
25042
25660
|
}
|
|
25043
|
-
var
|
|
25661
|
+
var import_node_fs59, import_node_path58, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
|
|
25044
25662
|
var init_diff = __esm({
|
|
25045
25663
|
"src/diff/diff.ts"() {
|
|
25046
25664
|
"use strict";
|
|
25047
|
-
|
|
25048
|
-
|
|
25665
|
+
import_node_fs59 = require("fs");
|
|
25666
|
+
import_node_path58 = require("path");
|
|
25049
25667
|
init_run();
|
|
25050
25668
|
init_worktree();
|
|
25051
25669
|
mergeBaseCache = /* @__PURE__ */ new Map();
|
|
@@ -25254,6 +25872,7 @@ async function confirmLand(thread, opts) {
|
|
|
25254
25872
|
var init_land = __esm({
|
|
25255
25873
|
"src/land/land.ts"() {
|
|
25256
25874
|
"use strict";
|
|
25875
|
+
init_pr_write();
|
|
25257
25876
|
init_worktree();
|
|
25258
25877
|
init_diff();
|
|
25259
25878
|
init_pr_metadata();
|
|
@@ -25267,16 +25886,16 @@ function readWorktreeFileTail(worktreePath, relativePath, maxBytes = WORKTREE_TA
|
|
|
25267
25886
|
if (!relativePath || relativePath.includes("..") || relativePath.startsWith("/")) {
|
|
25268
25887
|
throw new Error("Invalid path");
|
|
25269
25888
|
}
|
|
25270
|
-
const abs = (0,
|
|
25271
|
-
const fd = (0,
|
|
25889
|
+
const abs = (0, import_node_path59.join)(worktreePath, relativePath);
|
|
25890
|
+
const fd = (0, import_node_fs60.openSync)(abs, "r");
|
|
25272
25891
|
try {
|
|
25273
|
-
const st = (0,
|
|
25892
|
+
const st = (0, import_node_fs60.fstatSync)(fd);
|
|
25274
25893
|
if (!st.isFile()) throw new Error(`Not a file: ${relativePath}`);
|
|
25275
25894
|
const size = st.size;
|
|
25276
25895
|
const start = Math.max(0, size - maxBytes);
|
|
25277
25896
|
const length = size - start;
|
|
25278
25897
|
const buf = Buffer.alloc(length);
|
|
25279
|
-
if (length > 0) (0,
|
|
25898
|
+
if (length > 0) (0, import_node_fs60.readSync)(fd, buf, 0, length, start);
|
|
25280
25899
|
if (buf.subarray(0, Math.min(buf.length, 8e3)).includes(0)) {
|
|
25281
25900
|
return {
|
|
25282
25901
|
path: relativePath,
|
|
@@ -25294,15 +25913,15 @@ function readWorktreeFileTail(worktreePath, relativePath, maxBytes = WORKTREE_TA
|
|
|
25294
25913
|
}
|
|
25295
25914
|
return { path: relativePath, content, truncated, binary: false, encoding: "utf8" };
|
|
25296
25915
|
} finally {
|
|
25297
|
-
(0,
|
|
25916
|
+
(0, import_node_fs60.closeSync)(fd);
|
|
25298
25917
|
}
|
|
25299
25918
|
}
|
|
25300
|
-
var
|
|
25919
|
+
var import_node_fs60, import_node_path59, WORKTREE_TAIL_BYTES;
|
|
25301
25920
|
var init_read_worktree_tail = __esm({
|
|
25302
25921
|
"src/diff/read-worktree-tail.ts"() {
|
|
25303
25922
|
"use strict";
|
|
25304
|
-
|
|
25305
|
-
|
|
25923
|
+
import_node_fs60 = require("fs");
|
|
25924
|
+
import_node_path59 = require("path");
|
|
25306
25925
|
WORKTREE_TAIL_BYTES = 2e5;
|
|
25307
25926
|
}
|
|
25308
25927
|
});
|
|
@@ -25451,7 +26070,7 @@ function parseFrontmatter(content) {
|
|
|
25451
26070
|
}
|
|
25452
26071
|
function readSkill(skillMd, source) {
|
|
25453
26072
|
try {
|
|
25454
|
-
const content = (0,
|
|
26073
|
+
const content = (0, import_node_fs61.readFileSync)(skillMd, "utf8");
|
|
25455
26074
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
25456
26075
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
25457
26076
|
const name = fmName || dirName;
|
|
@@ -25470,19 +26089,19 @@ function readSkill(skillMd, source) {
|
|
|
25470
26089
|
}
|
|
25471
26090
|
}
|
|
25472
26091
|
function scanSkillsDir(dir, source, out) {
|
|
25473
|
-
if (!(0,
|
|
26092
|
+
if (!(0, import_node_fs61.existsSync)(dir)) return;
|
|
25474
26093
|
let entries;
|
|
25475
26094
|
try {
|
|
25476
|
-
entries = (0,
|
|
26095
|
+
entries = (0, import_node_fs61.readdirSync)(dir);
|
|
25477
26096
|
} catch {
|
|
25478
26097
|
return;
|
|
25479
26098
|
}
|
|
25480
26099
|
for (const entry of entries) {
|
|
25481
26100
|
if (entry.startsWith(".")) continue;
|
|
25482
|
-
const skillMd = (0,
|
|
25483
|
-
if (!(0,
|
|
26101
|
+
const skillMd = (0, import_node_path60.join)(dir, entry, "SKILL.md");
|
|
26102
|
+
if (!(0, import_node_fs61.existsSync)(skillMd)) continue;
|
|
25484
26103
|
try {
|
|
25485
|
-
if (!(0,
|
|
26104
|
+
if (!(0, import_node_fs61.statSync)(skillMd).isFile()) continue;
|
|
25486
26105
|
} catch {
|
|
25487
26106
|
continue;
|
|
25488
26107
|
}
|
|
@@ -25491,24 +26110,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
25491
26110
|
}
|
|
25492
26111
|
}
|
|
25493
26112
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
25494
|
-
if (!(0,
|
|
26113
|
+
if (!(0, import_node_fs61.existsSync)(pluginsRoot)) return;
|
|
25495
26114
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
25496
26115
|
if (depth > 7) return;
|
|
25497
26116
|
let entries;
|
|
25498
26117
|
try {
|
|
25499
|
-
entries = (0,
|
|
26118
|
+
entries = (0, import_node_fs61.readdirSync)(dir);
|
|
25500
26119
|
} catch {
|
|
25501
26120
|
return;
|
|
25502
26121
|
}
|
|
25503
26122
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
25504
|
-
const skill = readSkill((0,
|
|
26123
|
+
const skill = readSkill((0, import_node_path60.join)(dir, "SKILL.md"), "cli");
|
|
25505
26124
|
if (skill) out.push(skill);
|
|
25506
26125
|
}
|
|
25507
26126
|
for (const entry of entries) {
|
|
25508
26127
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
25509
|
-
const full = (0,
|
|
26128
|
+
const full = (0, import_node_path60.join)(dir, entry);
|
|
25510
26129
|
try {
|
|
25511
|
-
if (!(0,
|
|
26130
|
+
if (!(0, import_node_fs61.statSync)(full).isDirectory()) continue;
|
|
25512
26131
|
} catch {
|
|
25513
26132
|
continue;
|
|
25514
26133
|
}
|
|
@@ -25526,17 +26145,17 @@ function discoverSkills(worktreePath) {
|
|
|
25526
26145
|
const home = (0, import_node_os19.homedir)();
|
|
25527
26146
|
const collected = [];
|
|
25528
26147
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
25529
|
-
scanSkillsDir((0,
|
|
26148
|
+
scanSkillsDir((0, import_node_path60.join)(worktreePath, rel), "workspace", collected);
|
|
25530
26149
|
}
|
|
25531
26150
|
for (const abs of [
|
|
25532
|
-
(0,
|
|
25533
|
-
(0,
|
|
25534
|
-
(0,
|
|
25535
|
-
(0,
|
|
26151
|
+
(0, import_node_path60.join)(home, ".claude/skills"),
|
|
26152
|
+
(0, import_node_path60.join)(home, ".cursor/skills"),
|
|
26153
|
+
(0, import_node_path60.join)(home, ".sideboard/skills"),
|
|
26154
|
+
(0, import_node_path60.join)(home, ".brightsy/skills")
|
|
25536
26155
|
]) {
|
|
25537
26156
|
scanSkillsDir(abs, "user", collected);
|
|
25538
26157
|
}
|
|
25539
|
-
scanClaudePluginSkills((0,
|
|
26158
|
+
scanClaudePluginSkills((0, import_node_path60.join)(home, ".claude/plugins"), collected);
|
|
25540
26159
|
collected.push(...bundledSkills());
|
|
25541
26160
|
const rank = {
|
|
25542
26161
|
workspace: 0,
|
|
@@ -25562,7 +26181,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
25562
26181
|
\u2026(truncated)` : body;
|
|
25563
26182
|
}
|
|
25564
26183
|
}
|
|
25565
|
-
const raw = (0,
|
|
26184
|
+
const raw = (0, import_node_fs61.readFileSync)(skillPath, "utf8");
|
|
25566
26185
|
if (raw.startsWith("---")) {
|
|
25567
26186
|
const end = raw.indexOf("\n---", 3);
|
|
25568
26187
|
if (end >= 0) {
|
|
@@ -25576,13 +26195,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
25576
26195
|
|
|
25577
26196
|
\u2026(truncated)` : raw;
|
|
25578
26197
|
}
|
|
25579
|
-
var
|
|
26198
|
+
var import_node_fs61, import_node_os19, import_node_path60, BUNDLED_SKILL_PREFIX;
|
|
25580
26199
|
var init_discover = __esm({
|
|
25581
26200
|
"src/skills/discover.ts"() {
|
|
25582
26201
|
"use strict";
|
|
25583
|
-
|
|
26202
|
+
import_node_fs61 = require("fs");
|
|
25584
26203
|
import_node_os19 = require("os");
|
|
25585
|
-
|
|
26204
|
+
import_node_path60 = require("path");
|
|
25586
26205
|
init_long_running();
|
|
25587
26206
|
BUNDLED_SKILL_PREFIX = "bundled:";
|
|
25588
26207
|
}
|
|
@@ -25793,7 +26412,7 @@ function promptForJoinedSteer(input) {
|
|
|
25793
26412
|
rewriteTrailingUserPrompt(input.threadId, input.promptText, input.latestPrompt);
|
|
25794
26413
|
const { agentPrompt: expandedLatest } = expandComposerPrompt(
|
|
25795
26414
|
input.worktreePath,
|
|
25796
|
-
expandCanonicalGitRequest(input.latestPrompt),
|
|
26415
|
+
expandCanonicalGitRequest(input.latestPrompt, { forge: input.gitForge }),
|
|
25797
26416
|
{ attachments: input.attachments }
|
|
25798
26417
|
);
|
|
25799
26418
|
return input.expandedPrompt && input.agentPrompt.endsWith(input.expandedPrompt) ? input.agentPrompt.slice(0, -input.expandedPrompt.length) + expandedLatest : `${input.agentPrompt}
|
|
@@ -25901,6 +26520,33 @@ var init_enqueue_thread_send = __esm({
|
|
|
25901
26520
|
}
|
|
25902
26521
|
});
|
|
25903
26522
|
|
|
26523
|
+
// src/agents/forge-git-directives.ts
|
|
26524
|
+
function formatCursorGitDirective(slug) {
|
|
26525
|
+
const repo = slug?.trim() || "<origin-owner/name>";
|
|
26526
|
+
return [
|
|
26527
|
+
`Git host (Settings \u2192 Git \u2192 Cursor): this checkout is on Cursor (\`origin.cursor.com\`, \`${repo}\`).`,
|
|
26528
|
+
"- Use the `origin` CLI, not `gh`. Where commands overlap, flags follow `gh` (`origin <command> --help`).",
|
|
26529
|
+
"- `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.",
|
|
26530
|
+
"- 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.",
|
|
26531
|
+
"- Origin has no issue tracker. Tickets for this repo come from Linear or AbleTime via `list_issues`. Do not use `gh issue`."
|
|
26532
|
+
].join("\n");
|
|
26533
|
+
}
|
|
26534
|
+
function formatEntireGitDirective(slug) {
|
|
26535
|
+
const repo = slug?.trim() || "<origin-owner/name>";
|
|
26536
|
+
return [
|
|
26537
|
+
`Git host (Settings \u2192 Git \u2192 Entire): this checkout is on Entire (\`${repo}\`).`,
|
|
26538
|
+
"- Use the `entire` CLI, not `gh` or `origin`. Trails replace pull requests and GitHub issues.",
|
|
26539
|
+
"- `entire` uses the login from Settings \u2192 Git \u2192 Entire. Do not read tokens, set `ENTIRE_TOKEN`, or run `entire login` from this turn.",
|
|
26540
|
+
"- 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.",
|
|
26541
|
+
"- Tickets for this repo are Trails (`entire trail list` / `entire trail show`). Do not use `gh issue`."
|
|
26542
|
+
].join("\n");
|
|
26543
|
+
}
|
|
26544
|
+
var init_forge_git_directives = __esm({
|
|
26545
|
+
"src/agents/forge-git-directives.ts"() {
|
|
26546
|
+
"use strict";
|
|
26547
|
+
}
|
|
26548
|
+
});
|
|
26549
|
+
|
|
25904
26550
|
// src/skills/detached-job-path.ts
|
|
25905
26551
|
function compiledModuleDir() {
|
|
25906
26552
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
@@ -25908,7 +26554,7 @@ function compiledModuleDir() {
|
|
|
25908
26554
|
try {
|
|
25909
26555
|
const url = import_meta8.url;
|
|
25910
26556
|
if (typeof url === "string" && url.length > 0) {
|
|
25911
|
-
return (0,
|
|
26557
|
+
return (0, import_node_path61.dirname)((0, import_node_url5.fileURLToPath)(url));
|
|
25912
26558
|
}
|
|
25913
26559
|
} catch {
|
|
25914
26560
|
}
|
|
@@ -25916,8 +26562,8 @@ function compiledModuleDir() {
|
|
|
25916
26562
|
}
|
|
25917
26563
|
function detachedJobScriptIn(dir) {
|
|
25918
26564
|
for (const name of DETACHED_JOB_FILENAMES) {
|
|
25919
|
-
const script = (0,
|
|
25920
|
-
if ((0,
|
|
26565
|
+
const script = (0, import_node_path61.join)(dir, "scripts", name);
|
|
26566
|
+
if ((0, import_node_fs62.existsSync)(script)) return script;
|
|
25921
26567
|
}
|
|
25922
26568
|
return null;
|
|
25923
26569
|
}
|
|
@@ -25934,7 +26580,7 @@ function resolveDetachedJobScript() {
|
|
|
25934
26580
|
for (let i = 0; i < 8; i++) {
|
|
25935
26581
|
const candidate = detachedJobScriptIn(dir);
|
|
25936
26582
|
if (candidate) return candidate;
|
|
25937
|
-
const parent = (0,
|
|
26583
|
+
const parent = (0, import_node_path61.dirname)(dir);
|
|
25938
26584
|
if (parent === dir) break;
|
|
25939
26585
|
dir = parent;
|
|
25940
26586
|
}
|
|
@@ -25945,12 +26591,12 @@ function formatDetachedJobInvoke(scriptPath) {
|
|
|
25945
26591
|
if (resolved) return `node ${JSON.stringify(resolved)}`;
|
|
25946
26592
|
return "node scripts/detached-job.cjs";
|
|
25947
26593
|
}
|
|
25948
|
-
var
|
|
26594
|
+
var import_node_fs62, import_node_path61, import_node_url5, import_meta8, DETACHED_JOB_FILENAMES;
|
|
25949
26595
|
var init_detached_job_path = __esm({
|
|
25950
26596
|
"src/skills/detached-job-path.ts"() {
|
|
25951
26597
|
"use strict";
|
|
25952
|
-
|
|
25953
|
-
|
|
26598
|
+
import_node_fs62 = require("fs");
|
|
26599
|
+
import_node_path61 = require("path");
|
|
25954
26600
|
import_node_url5 = require("url");
|
|
25955
26601
|
init_packaged_runtime();
|
|
25956
26602
|
import_meta8 = {};
|
|
@@ -26038,17 +26684,35 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
26038
26684
|
lines.push(
|
|
26039
26685
|
"- 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)."
|
|
26040
26686
|
);
|
|
26041
|
-
|
|
26687
|
+
const cursorRepo = opts?.originForge === "cursor";
|
|
26688
|
+
const entireRepo = opts?.originForge === "entire";
|
|
26689
|
+
if (cursorRepo) {
|
|
26690
|
+
lines.push(formatCursorGitDirective(opts?.originSlug));
|
|
26691
|
+
} else if (entireRepo) {
|
|
26692
|
+
lines.push(formatEntireGitDirective(opts?.originSlug));
|
|
26693
|
+
} else {
|
|
26694
|
+
lines.push(formatGitAuthModeDirective(opts?.gitAuthMode ?? "auto"));
|
|
26695
|
+
}
|
|
26042
26696
|
lines.push(
|
|
26043
26697
|
"- 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."
|
|
26044
26698
|
);
|
|
26045
26699
|
lines.push(
|
|
26046
|
-
"- 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`)."
|
|
26700
|
+
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`)."
|
|
26047
26701
|
);
|
|
26048
26702
|
if (thread.prUrl) {
|
|
26049
26703
|
lines.push(
|
|
26050
26704
|
`- A PR already exists (${thread.prUrl}). Update it (push + edit title/body if the purpose drifted) instead of opening a duplicate.`
|
|
26051
26705
|
);
|
|
26706
|
+
} else if (entireRepo) {
|
|
26707
|
+
lines.push(
|
|
26708
|
+
'- 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`.'
|
|
26709
|
+
);
|
|
26710
|
+
} else if (cursorRepo) {
|
|
26711
|
+
const slug = opts?.originSlug?.trim() || "<origin-owner/name>";
|
|
26712
|
+
const resolve3 = opts?.originSlug?.trim() ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
|
|
26713
|
+
lines.push(
|
|
26714
|
+
`- 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\`.`
|
|
26715
|
+
);
|
|
26052
26716
|
} else {
|
|
26053
26717
|
const slug = opts?.githubSlug ?? "<origin-owner/name>";
|
|
26054
26718
|
const resolve3 = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
|
|
@@ -26166,9 +26830,9 @@ function formatPrGateDirective() {
|
|
|
26166
26830
|
}
|
|
26167
26831
|
function formatProcessGuideDirective(opts) {
|
|
26168
26832
|
const worktree = opts?.worktreePath?.trim();
|
|
26169
|
-
const hasGraphSkill = !!worktree && (0,
|
|
26170
|
-
const hasReviewSkill = !!worktree && (0,
|
|
26171
|
-
const hasInstallSkill = !!worktree && (0,
|
|
26833
|
+
const hasGraphSkill = !!worktree && (0, import_node_fs63.existsSync)((0, import_node_path62.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
|
|
26834
|
+
const hasReviewSkill = !!worktree && (0, import_node_fs63.existsSync)((0, import_node_path62.join)(worktree, ".claude/skills/review/SKILL.md"));
|
|
26835
|
+
const hasInstallSkill = !!worktree && (0, import_node_fs63.existsSync)((0, import_node_path62.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
|
|
26172
26836
|
return [
|
|
26173
26837
|
"Process guides (recurring work only):",
|
|
26174
26838
|
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,
|
|
@@ -26208,13 +26872,14 @@ function formatArtifactDirective() {
|
|
|
26208
26872
|
function formatUiReminder() {
|
|
26209
26873
|
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.";
|
|
26210
26874
|
}
|
|
26211
|
-
var
|
|
26875
|
+
var import_node_fs63, import_node_path62, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
|
|
26212
26876
|
var init_instructions = __esm({
|
|
26213
26877
|
"src/agents/instructions.ts"() {
|
|
26214
26878
|
"use strict";
|
|
26215
|
-
|
|
26216
|
-
|
|
26879
|
+
import_node_fs63 = require("fs");
|
|
26880
|
+
import_node_path62 = require("path");
|
|
26217
26881
|
init_git_auth_mode();
|
|
26882
|
+
init_forge_git_directives();
|
|
26218
26883
|
init_branch_prefix();
|
|
26219
26884
|
init_worktree_labels();
|
|
26220
26885
|
init_detached_job_path();
|
|
@@ -26563,6 +27228,7 @@ function compactIssueRow(issue, opts) {
|
|
|
26563
27228
|
function formatMcpIssueList(input) {
|
|
26564
27229
|
const truncated = input.truncated || Boolean(input.commentsTruncated);
|
|
26565
27230
|
const comments = input.comments ?? [];
|
|
27231
|
+
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;
|
|
26566
27232
|
return {
|
|
26567
27233
|
...input.source ? { source: input.source } : {},
|
|
26568
27234
|
...input.viewer ? { viewer: input.viewer } : {},
|
|
@@ -26570,9 +27236,8 @@ function formatMcpIssueList(input) {
|
|
|
26570
27236
|
returned: input.issues.length,
|
|
26571
27237
|
truncated,
|
|
26572
27238
|
...input.since ? { since: input.since } : {},
|
|
26573
|
-
...
|
|
26574
|
-
|
|
26575
|
-
} : {},
|
|
27239
|
+
...input.unavailableReason ? { unavailableReason: input.unavailableReason } : {},
|
|
27240
|
+
...pageHint ? { hint: pageHint } : {},
|
|
26576
27241
|
issues: input.issues.map((issue) => compactIssueRow(issue, { since: input.since })),
|
|
26577
27242
|
...input.since || comments.length > 0 ? { comments } : {}
|
|
26578
27243
|
};
|
|
@@ -26589,7 +27254,8 @@ function formatListedIssuesForMcp(result, page) {
|
|
|
26589
27254
|
truncated: windowed.truncated,
|
|
26590
27255
|
since: result.since,
|
|
26591
27256
|
comments: commentWindow.items,
|
|
26592
|
-
commentsTruncated: commentWindow.truncated
|
|
27257
|
+
commentsTruncated: commentWindow.truncated,
|
|
27258
|
+
unavailableReason: result.unavailableReason
|
|
26593
27259
|
});
|
|
26594
27260
|
}
|
|
26595
27261
|
function mcpJson(payload, isError = false) {
|
|
@@ -26954,40 +27620,40 @@ __export(plan_file_exports, {
|
|
|
26954
27620
|
writePlanFile: () => writePlanFile
|
|
26955
27621
|
});
|
|
26956
27622
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
26957
|
-
const gitignoreAbs = (0,
|
|
26958
|
-
if ((0,
|
|
26959
|
-
(0,
|
|
26960
|
-
(0,
|
|
27623
|
+
const gitignoreAbs = (0, import_node_path63.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
27624
|
+
if ((0, import_node_fs64.existsSync)(gitignoreAbs)) return;
|
|
27625
|
+
(0, import_node_fs64.mkdirSync)((0, import_node_path63.dirname)(gitignoreAbs), { recursive: true });
|
|
27626
|
+
(0, import_node_fs64.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
26961
27627
|
}
|
|
26962
27628
|
function planFileAbs(worktreePath) {
|
|
26963
|
-
return (0,
|
|
27629
|
+
return (0, import_node_path63.join)(worktreePath, PLAN_FILE_REL);
|
|
26964
27630
|
}
|
|
26965
27631
|
function readTextIfPresent2(abs) {
|
|
26966
|
-
if (!(0,
|
|
27632
|
+
if (!(0, import_node_fs64.existsSync)(abs)) return null;
|
|
26967
27633
|
try {
|
|
26968
|
-
const content = (0,
|
|
27634
|
+
const content = (0, import_node_fs64.readFileSync)(abs, "utf8");
|
|
26969
27635
|
return content.trim() ? content : null;
|
|
26970
27636
|
} catch {
|
|
26971
27637
|
return null;
|
|
26972
27638
|
}
|
|
26973
27639
|
}
|
|
26974
27640
|
function readPlanFile(worktreePath) {
|
|
26975
|
-
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0,
|
|
27641
|
+
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path63.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path63.join)(worktreePath, LEGACY_PLAN_FILE_REL));
|
|
26976
27642
|
}
|
|
26977
27643
|
function writePlanFile(worktreePath, content) {
|
|
26978
27644
|
ensureAttachmentsGitignore(worktreePath);
|
|
26979
27645
|
const abs = planFileAbs(worktreePath);
|
|
26980
|
-
(0,
|
|
27646
|
+
(0, import_node_fs64.mkdirSync)((0, import_node_path63.dirname)(abs), { recursive: true });
|
|
26981
27647
|
const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
|
|
26982
|
-
(0,
|
|
27648
|
+
(0, import_node_fs64.writeFileSync)(abs, body, "utf8");
|
|
26983
27649
|
return PLAN_FILE_REL;
|
|
26984
27650
|
}
|
|
26985
|
-
var
|
|
27651
|
+
var import_node_fs64, import_node_path63;
|
|
26986
27652
|
var init_plan_file = __esm({
|
|
26987
27653
|
"src/plan/plan-file.ts"() {
|
|
26988
27654
|
"use strict";
|
|
26989
|
-
|
|
26990
|
-
|
|
27655
|
+
import_node_fs64 = require("fs");
|
|
27656
|
+
import_node_path63 = require("path");
|
|
26991
27657
|
init_workspace_scratch();
|
|
26992
27658
|
init_plan_present();
|
|
26993
27659
|
init_plan_present();
|
|
@@ -27036,7 +27702,7 @@ function setCaffeinateHoldHooks(next) {
|
|
|
27036
27702
|
hooks = next;
|
|
27037
27703
|
}
|
|
27038
27704
|
function caffeinateHoldPath() {
|
|
27039
|
-
return (0,
|
|
27705
|
+
return (0, import_node_path64.join)(appDataDir(), "caffeinate-hold.json");
|
|
27040
27706
|
}
|
|
27041
27707
|
function processAlive(pid) {
|
|
27042
27708
|
if (hooks.processAlive) return hooks.processAlive(pid);
|
|
@@ -27070,9 +27736,9 @@ function uniqueIds(ids) {
|
|
|
27070
27736
|
}
|
|
27071
27737
|
function readHold() {
|
|
27072
27738
|
const path = caffeinateHoldPath();
|
|
27073
|
-
if (!(0,
|
|
27739
|
+
if (!(0, import_node_fs65.existsSync)(path)) return null;
|
|
27074
27740
|
try {
|
|
27075
|
-
const parsed = JSON.parse((0,
|
|
27741
|
+
const parsed = JSON.parse((0, import_node_fs65.readFileSync)(path, "utf8"));
|
|
27076
27742
|
if (typeof parsed?.pid === "number" && parsed.pid > 0) {
|
|
27077
27743
|
return {
|
|
27078
27744
|
pid: parsed.pid,
|
|
@@ -27094,7 +27760,7 @@ function writeHold(pid, threadIds) {
|
|
|
27094
27760
|
}
|
|
27095
27761
|
function clearHold() {
|
|
27096
27762
|
try {
|
|
27097
|
-
(0,
|
|
27763
|
+
(0, import_node_fs65.unlinkSync)(caffeinateHoldPath());
|
|
27098
27764
|
} catch {
|
|
27099
27765
|
}
|
|
27100
27766
|
}
|
|
@@ -27179,13 +27845,13 @@ function releaseCaffeinateHoldForThread(threadId) {
|
|
|
27179
27845
|
}
|
|
27180
27846
|
return setCaffeinateHold(false, { threadId: id });
|
|
27181
27847
|
}
|
|
27182
|
-
var import_node_child_process6,
|
|
27848
|
+
var import_node_child_process6, import_node_fs65, import_node_path64, hooks;
|
|
27183
27849
|
var init_caffeinate_hold = __esm({
|
|
27184
27850
|
"src/store/caffeinate-hold.ts"() {
|
|
27185
27851
|
"use strict";
|
|
27186
27852
|
import_node_child_process6 = require("child_process");
|
|
27187
|
-
|
|
27188
|
-
|
|
27853
|
+
import_node_fs65 = require("fs");
|
|
27854
|
+
import_node_path64 = require("path");
|
|
27189
27855
|
init_paths();
|
|
27190
27856
|
init_private_file();
|
|
27191
27857
|
hooks = {};
|
|
@@ -27194,7 +27860,7 @@ var init_caffeinate_hold = __esm({
|
|
|
27194
27860
|
|
|
27195
27861
|
// src/store/schedules.ts
|
|
27196
27862
|
function schedulesPath() {
|
|
27197
|
-
return (0,
|
|
27863
|
+
return (0, import_node_path65.join)(appDataDir(), "schedules.json");
|
|
27198
27864
|
}
|
|
27199
27865
|
function parseDurationMs(every) {
|
|
27200
27866
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -27330,9 +27996,9 @@ function normalizeTask(raw) {
|
|
|
27330
27996
|
}
|
|
27331
27997
|
function readAll2() {
|
|
27332
27998
|
const path = schedulesPath();
|
|
27333
|
-
if (!(0,
|
|
27999
|
+
if (!(0, import_node_fs66.existsSync)(path)) return [];
|
|
27334
28000
|
try {
|
|
27335
|
-
const parsed = JSON.parse((0,
|
|
28001
|
+
const parsed = JSON.parse((0, import_node_fs66.readFileSync)(path, "utf8"));
|
|
27336
28002
|
if (!Array.isArray(parsed)) return [];
|
|
27337
28003
|
return parsed.map((row) => {
|
|
27338
28004
|
try {
|
|
@@ -27467,13 +28133,13 @@ function recordScheduleRun(id, result) {
|
|
|
27467
28133
|
writeAll2(rows);
|
|
27468
28134
|
return next;
|
|
27469
28135
|
}
|
|
27470
|
-
var import_node_crypto17,
|
|
28136
|
+
var import_node_crypto17, import_node_fs66, import_node_path65, import_croner, DURATION_RE, UNIT_MS, ATTACHMENT_KINDS;
|
|
27471
28137
|
var init_schedules = __esm({
|
|
27472
28138
|
"src/store/schedules.ts"() {
|
|
27473
28139
|
"use strict";
|
|
27474
28140
|
import_node_crypto17 = require("crypto");
|
|
27475
|
-
|
|
27476
|
-
|
|
28141
|
+
import_node_fs66 = require("fs");
|
|
28142
|
+
import_node_path65 = require("path");
|
|
27477
28143
|
import_croner = require("croner");
|
|
27478
28144
|
init_orchestrator_capable();
|
|
27479
28145
|
init_thinking_effort();
|
|
@@ -27677,9 +28343,9 @@ function recoverFinishedCursorRun(opts) {
|
|
|
27677
28343
|
return best;
|
|
27678
28344
|
}
|
|
27679
28345
|
function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
27680
|
-
if (!(0,
|
|
28346
|
+
if (!(0, import_node_fs67.existsSync)(runsPath)) return null;
|
|
27681
28347
|
try {
|
|
27682
|
-
const lines = (0,
|
|
28348
|
+
const lines = (0, import_node_fs67.readFileSync)(runsPath, "utf8").split("\n");
|
|
27683
28349
|
let best = null;
|
|
27684
28350
|
for (const line of lines) {
|
|
27685
28351
|
const trimmed = line.trim();
|
|
@@ -27705,11 +28371,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
|
27705
28371
|
return null;
|
|
27706
28372
|
}
|
|
27707
28373
|
}
|
|
27708
|
-
var
|
|
28374
|
+
var import_node_fs67;
|
|
27709
28375
|
var init_cursor_recover = __esm({
|
|
27710
28376
|
"src/agents/cursor-recover.ts"() {
|
|
27711
28377
|
"use strict";
|
|
27712
|
-
|
|
28378
|
+
import_node_fs67 = require("fs");
|
|
27713
28379
|
init_cursor_store();
|
|
27714
28380
|
}
|
|
27715
28381
|
});
|
|
@@ -27830,7 +28496,7 @@ async function startOrchestration(opts) {
|
|
|
27830
28496
|
}
|
|
27831
28497
|
return ready;
|
|
27832
28498
|
}
|
|
27833
|
-
var import_node_events, import_node_crypto18,
|
|
28499
|
+
var import_node_events, import_node_crypto18, import_node_fs68, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton2;
|
|
27834
28500
|
var init_orchestrator = __esm({
|
|
27835
28501
|
"src/orchestrator/orchestrator.ts"() {
|
|
27836
28502
|
"use strict";
|
|
@@ -27839,7 +28505,7 @@ var init_orchestrator = __esm({
|
|
|
27839
28505
|
init_task_state();
|
|
27840
28506
|
init_wait_for_turn();
|
|
27841
28507
|
import_node_crypto18 = require("crypto");
|
|
27842
|
-
|
|
28508
|
+
import_node_fs68 = require("fs");
|
|
27843
28509
|
init_error_detail();
|
|
27844
28510
|
init_run();
|
|
27845
28511
|
init_stale_lock();
|
|
@@ -28038,7 +28704,7 @@ var init_orchestrator = __esm({
|
|
|
28038
28704
|
this.lightReconcileAt.set(repoPath, Date.now());
|
|
28039
28705
|
for (const thread of listThreads()) {
|
|
28040
28706
|
if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
|
|
28041
|
-
if (!(0,
|
|
28707
|
+
if (!(0, import_node_fs68.existsSync)(thread.worktreePath)) {
|
|
28042
28708
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
28043
28709
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
28044
28710
|
}
|
|
@@ -28067,7 +28733,7 @@ var init_orchestrator = __esm({
|
|
|
28067
28733
|
}
|
|
28068
28734
|
continue;
|
|
28069
28735
|
}
|
|
28070
|
-
if (!(0,
|
|
28736
|
+
if (!(0, import_node_fs68.existsSync)(thread.worktreePath)) {
|
|
28071
28737
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
28072
28738
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
28073
28739
|
continue;
|
|
@@ -28791,7 +29457,8 @@ var init_orchestrator = __esm({
|
|
|
28791
29457
|
return;
|
|
28792
29458
|
}
|
|
28793
29459
|
thread = this.requireThread(threadId);
|
|
28794
|
-
const
|
|
29460
|
+
const turnOrigin = thread.worktreePath?.trim() ? await resolveOriginRemote(thread.worktreePath).catch(() => null) : null;
|
|
29461
|
+
const gitPrompt = expandCanonicalGitRequest(promptText, { forge: turnOrigin?.forge });
|
|
28795
29462
|
const { agentPrompt: expandedPrompt } = expandComposerPrompt(
|
|
28796
29463
|
thread.worktreePath,
|
|
28797
29464
|
gitPrompt,
|
|
@@ -28878,11 +29545,9 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
28878
29545
|
const { autoRenameBranchEnabled: autoRenameBranchEnabled2, getGithubGitAuthMode: getGithubGitAuthMode2, gitBranchPrefixSetting: gitBranchPrefixSetting2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
|
|
28879
29546
|
const gitAuthMode = getGithubGitAuthMode2();
|
|
28880
29547
|
const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
|
|
28881
|
-
githubSlug: await withTimeout(
|
|
28882
|
-
|
|
28883
|
-
|
|
28884
|
-
"resolveGithubRepoSlug"
|
|
28885
|
-
).catch(() => null),
|
|
29548
|
+
githubSlug: turnOrigin?.forge === "github" ? turnOrigin.slug : await withTimeout(resolveGithubRepoSlug(fresh.worktreePath), 8e3, "resolveGithubRepoSlug").catch(() => null),
|
|
29549
|
+
originForge: turnOrigin?.forge ?? null,
|
|
29550
|
+
originSlug: turnOrigin?.slug ?? null,
|
|
28886
29551
|
gitAuthMode,
|
|
28887
29552
|
activeRuns: annotateDevAccessRuns(
|
|
28888
29553
|
mergeWorktreeActiveRuns(
|
|
@@ -28975,7 +29640,8 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
28975
29640
|
agentPrompt,
|
|
28976
29641
|
expandedPrompt,
|
|
28977
29642
|
worktreePath: fresh.worktreePath,
|
|
28978
|
-
attachments: autoContinue ? [] : sentAttachments ?? []
|
|
29643
|
+
attachments: autoContinue ? [] : sentAttachments ?? [],
|
|
29644
|
+
gitForge: turnOrigin?.forge
|
|
28979
29645
|
});
|
|
28980
29646
|
const handle = await spawnAgentTurn(
|
|
28981
29647
|
fresh,
|
|
@@ -30549,7 +31215,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
30549
31215
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
30550
31216
|
return restored2;
|
|
30551
31217
|
}
|
|
30552
|
-
if (!(0,
|
|
31218
|
+
if (!(0, import_node_fs68.existsSync)(thread.worktreePath)) {
|
|
30553
31219
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
30554
31220
|
throw new Error(
|
|
30555
31221
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
@@ -30740,7 +31406,7 @@ function createClippedMcpServer() {
|
|
|
30740
31406
|
// src/mcp/server.ts
|
|
30741
31407
|
var import_zod11 = require("zod");
|
|
30742
31408
|
var import_node_crypto22 = require("crypto");
|
|
30743
|
-
var
|
|
31409
|
+
var import_node_path69 = require("path");
|
|
30744
31410
|
init_orchestrator();
|
|
30745
31411
|
init_task_state();
|
|
30746
31412
|
init_worktree();
|
|
@@ -30848,9 +31514,9 @@ function githubProjectsOnIssue(raw) {
|
|
|
30848
31514
|
}
|
|
30849
31515
|
return out;
|
|
30850
31516
|
}
|
|
30851
|
-
async function readGitHubIssueProjects(number, cwd,
|
|
31517
|
+
async function readGitHubIssueProjects(number, cwd, repoArgs2) {
|
|
30852
31518
|
const result = await gh(
|
|
30853
|
-
["issue", "view", String(number), ...
|
|
31519
|
+
["issue", "view", String(number), ...repoArgs2, "--json", "projectItems"],
|
|
30854
31520
|
cwd,
|
|
30855
31521
|
{ reject: false }
|
|
30856
31522
|
);
|
|
@@ -30868,8 +31534,8 @@ async function readGitHubIssueProjects(number, cwd, repoArgs) {
|
|
|
30868
31534
|
return { projects: [] };
|
|
30869
31535
|
}
|
|
30870
31536
|
}
|
|
30871
|
-
async function listGitHubIssueProjectNames(number, cwd,
|
|
30872
|
-
const read = await readGitHubIssueProjects(number, cwd,
|
|
31537
|
+
async function listGitHubIssueProjectNames(number, cwd, repoArgs2) {
|
|
31538
|
+
const read = await readGitHubIssueProjects(number, cwd, repoArgs2);
|
|
30873
31539
|
return read.projects.map((project) => project.name).filter(Boolean);
|
|
30874
31540
|
}
|
|
30875
31541
|
function parseGitHubProjectList(stdout) {
|
|
@@ -31074,14 +31740,14 @@ async function listGitHubIssueCommentsSince(opts) {
|
|
|
31074
31740
|
}
|
|
31075
31741
|
async function getGitHubIssue(id, opts) {
|
|
31076
31742
|
const number = parseGitHubIssueNumber(id);
|
|
31077
|
-
const { cwd, repoArgs } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
31743
|
+
const { cwd, repoArgs: repoArgs2 } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
31078
31744
|
const stdout = requireGhOk(
|
|
31079
31745
|
await gh(
|
|
31080
31746
|
[
|
|
31081
31747
|
"issue",
|
|
31082
31748
|
"view",
|
|
31083
31749
|
String(number),
|
|
31084
|
-
...
|
|
31750
|
+
...repoArgs2,
|
|
31085
31751
|
"--json",
|
|
31086
31752
|
"number,title,body,url,state,labels,assignees,comments,author"
|
|
31087
31753
|
],
|
|
@@ -31100,7 +31766,7 @@ async function getGitHubIssue(id, opts) {
|
|
|
31100
31766
|
throw new Error(`GitHub issue not found: #${number}`);
|
|
31101
31767
|
}
|
|
31102
31768
|
const issue = toGitHubIssue(parsed);
|
|
31103
|
-
const projects = await readGitHubIssueProjects(number, cwd,
|
|
31769
|
+
const projects = await readGitHubIssueProjects(number, cwd, repoArgs2);
|
|
31104
31770
|
issue.projects = projects.projects;
|
|
31105
31771
|
if (projects.error) issue.projectsError = projects.error;
|
|
31106
31772
|
return issue;
|
|
@@ -31109,10 +31775,10 @@ async function commentGitHubIssue(input, opts) {
|
|
|
31109
31775
|
const number = parseGitHubIssueNumber(input.id);
|
|
31110
31776
|
const body = input.body.trim();
|
|
31111
31777
|
if (!body) throw new Error("GitHub comment body is required");
|
|
31112
|
-
const { cwd, repoArgs } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
31778
|
+
const { cwd, repoArgs: repoArgs2 } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
31113
31779
|
const stdout = requireGhOk(
|
|
31114
31780
|
await gh(
|
|
31115
|
-
["issue", "comment", String(number), ...
|
|
31781
|
+
["issue", "comment", String(number), ...repoArgs2, "--body", body],
|
|
31116
31782
|
cwd,
|
|
31117
31783
|
{ reject: false }
|
|
31118
31784
|
),
|
|
@@ -31154,21 +31820,21 @@ async function updateGitHubIssue(input, opts) {
|
|
|
31154
31820
|
"github_update_issue needs at least one of title, body, state, labels, project, parent, relations, removeRelations"
|
|
31155
31821
|
);
|
|
31156
31822
|
}
|
|
31157
|
-
const { cwd, repoArgs } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
31823
|
+
const { cwd, repoArgs: repoArgs2 } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
31158
31824
|
if (state === "closed" || state === "close") {
|
|
31159
31825
|
requireGhOk(
|
|
31160
|
-
await gh(["issue", "close", String(number), ...
|
|
31826
|
+
await gh(["issue", "close", String(number), ...repoArgs2], cwd, { reject: false }),
|
|
31161
31827
|
`GitHub close #${number}`
|
|
31162
31828
|
);
|
|
31163
31829
|
} else if (state === "open" || state === "reopen") {
|
|
31164
31830
|
requireGhOk(
|
|
31165
|
-
await gh(["issue", "reopen", String(number), ...
|
|
31831
|
+
await gh(["issue", "reopen", String(number), ...repoArgs2], cwd, { reject: false }),
|
|
31166
31832
|
`GitHub reopen #${number}`
|
|
31167
31833
|
);
|
|
31168
31834
|
} else if (state) {
|
|
31169
31835
|
throw new Error(`GitHub issue state must be open or closed (got ${input.state})`);
|
|
31170
31836
|
}
|
|
31171
|
-
const args = ["issue", "edit", String(number), ...
|
|
31837
|
+
const args = ["issue", "edit", String(number), ...repoArgs2];
|
|
31172
31838
|
if (title) args.push("--title", title);
|
|
31173
31839
|
if (body !== void 0) args.push("--body", body);
|
|
31174
31840
|
if (input.labels !== void 0) {
|
|
@@ -31180,7 +31846,7 @@ async function updateGitHubIssue(input, opts) {
|
|
|
31180
31846
|
if (remove.length) args.push("--remove-label", remove.join(","));
|
|
31181
31847
|
}
|
|
31182
31848
|
if (input.project !== void 0) {
|
|
31183
|
-
const current = await listGitHubIssueProjectNames(number, cwd,
|
|
31849
|
+
const current = await listGitHubIssueProjectNames(number, cwd, repoArgs2);
|
|
31184
31850
|
if (isGitHubNoneToken(input.project)) {
|
|
31185
31851
|
for (const name of current) args.push("--remove-project", name);
|
|
31186
31852
|
} else {
|
|
@@ -31206,7 +31872,7 @@ async function updateGitHubIssue(input, opts) {
|
|
|
31206
31872
|
for (const rel of addRelations ?? []) {
|
|
31207
31873
|
args.push(githubRelationEditFlag(rel.type, false), String(parseGitHubIssueNumber(rel.issue)));
|
|
31208
31874
|
}
|
|
31209
|
-
const editChanged = args.length > 3 +
|
|
31875
|
+
const editChanged = args.length > 3 + repoArgs2.length;
|
|
31210
31876
|
if (editChanged) {
|
|
31211
31877
|
requireGhOk(await gh(args, cwd, { reject: false }), `GitHub edit #${number}`);
|
|
31212
31878
|
}
|
|
@@ -31221,8 +31887,8 @@ async function createGitHubIssue(input, opts) {
|
|
|
31221
31887
|
parentNumber ? `Spin-off of #${parentNumber}.` : null,
|
|
31222
31888
|
input.body?.trim() || null
|
|
31223
31889
|
].filter(Boolean);
|
|
31224
|
-
const { cwd, repoArgs } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
31225
|
-
const args = ["issue", "create", ...
|
|
31890
|
+
const { cwd, repoArgs: repoArgs2 } = await resolveGitHubIssueRepo(opts?.repoPath);
|
|
31891
|
+
const args = ["issue", "create", ...repoArgs2, "--title", title];
|
|
31226
31892
|
if (bodyParts.length) args.push("--body", bodyParts.join("\n\n"));
|
|
31227
31893
|
const created = await gh([...args, "--json", "number,url,title"], cwd, { reject: false });
|
|
31228
31894
|
if (created.exitCode === 0 && created.stdout.trim()) {
|
|
@@ -32446,6 +33112,18 @@ async function commentLinearIssue(input, opts) {
|
|
|
32446
33112
|
}
|
|
32447
33113
|
|
|
32448
33114
|
// src/integrations/issues.ts
|
|
33115
|
+
var CURSOR_ISSUES_UNAVAILABLE = "Cursor Origin has no issue tracker. Tickets for this repo come from Linear or AbleTime (Settings \u2192 Issues).";
|
|
33116
|
+
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.";
|
|
33117
|
+
async function cursorIssuesUnavailableReason(repoPath) {
|
|
33118
|
+
try {
|
|
33119
|
+
const remote = await resolveOriginRemote(repoPath);
|
|
33120
|
+
if (remote?.forge === "cursor") return CURSOR_ISSUES_UNAVAILABLE;
|
|
33121
|
+
if (remote?.forge === "entire") return ENTIRE_ISSUES_ARE_TRAILS;
|
|
33122
|
+
return null;
|
|
33123
|
+
} catch {
|
|
33124
|
+
return null;
|
|
33125
|
+
}
|
|
33126
|
+
}
|
|
32449
33127
|
function assigneeKey(assignee) {
|
|
32450
33128
|
return (assignee ?? "").trim().toLowerCase();
|
|
32451
33129
|
}
|
|
@@ -32607,6 +33285,17 @@ async function listIssues(repoPath, opts) {
|
|
|
32607
33285
|
...since ? { since, comments: commentsFromAbleTimeIssues(tasks, issues2, since) } : {}
|
|
32608
33286
|
};
|
|
32609
33287
|
}
|
|
33288
|
+
const unavailableReason = await cursorIssuesUnavailableReason(repoPath);
|
|
33289
|
+
if (unavailableReason) {
|
|
33290
|
+
return {
|
|
33291
|
+
source,
|
|
33292
|
+
preferredSource,
|
|
33293
|
+
linearConnected,
|
|
33294
|
+
abletimeConnected,
|
|
33295
|
+
issues: [],
|
|
33296
|
+
unavailableReason
|
|
33297
|
+
};
|
|
33298
|
+
}
|
|
32610
33299
|
const [issues, login] = await Promise.all([
|
|
32611
33300
|
listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit, updatedSince: since }),
|
|
32612
33301
|
githubViewerLogin(repoPath)
|
|
@@ -33416,11 +34105,15 @@ function fail2(err) {
|
|
|
33416
34105
|
true
|
|
33417
34106
|
);
|
|
33418
34107
|
}
|
|
34108
|
+
async function cursorIssueBlock(repoPath) {
|
|
34109
|
+
const cwd = await resolveRepoRoot((repoPath ?? "").trim() || process.cwd());
|
|
34110
|
+
return cursorIssuesUnavailableReason(cwd);
|
|
34111
|
+
}
|
|
33419
34112
|
var repoPathSchema = import_zod6.z.string().optional().describe("Workspace / worktree path. Omit on a worktree turn (uses cwd).");
|
|
33420
34113
|
function registerGithubIssueTools(server) {
|
|
33421
34114
|
server.tool(
|
|
33422
34115
|
"github_search_issues",
|
|
33423
|
-
"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).",
|
|
34116
|
+
"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).",
|
|
33424
34117
|
{
|
|
33425
34118
|
query: import_zod6.z.string().optional().describe("Search text (title, body, identifiers). Omit to list by assignee only."),
|
|
33426
34119
|
assignee: import_zod6.z.string().optional().describe("me, unassigned, all, or a GitHub login. Default: all when query is set, otherwise me."),
|
|
@@ -33432,6 +34125,15 @@ function registerGithubIssueTools(server) {
|
|
|
33432
34125
|
try {
|
|
33433
34126
|
const cwd = await resolveRepoRoot((repoPath ?? "").trim() || process.cwd());
|
|
33434
34127
|
const page = clampMcpIssueLimit(limit);
|
|
34128
|
+
const blocked = await cursorIssuesUnavailableReason(cwd);
|
|
34129
|
+
if (blocked) {
|
|
34130
|
+
return mcpJson(
|
|
34131
|
+
formatListedIssuesForMcp(
|
|
34132
|
+
{ source: "github", issues: [], unavailableReason: blocked },
|
|
34133
|
+
page
|
|
34134
|
+
)
|
|
34135
|
+
);
|
|
34136
|
+
}
|
|
33435
34137
|
const since = updatedSince ? parseIssueSince(updatedSince) : void 0;
|
|
33436
34138
|
const issues = await listGitHubIssues(cwd, {
|
|
33437
34139
|
query,
|
|
@@ -33467,6 +34169,8 @@ function registerGithubIssueTools(server) {
|
|
|
33467
34169
|
{ repoPath: repoPathSchema },
|
|
33468
34170
|
async ({ repoPath }) => {
|
|
33469
34171
|
try {
|
|
34172
|
+
const blocked = await cursorIssueBlock(repoPath);
|
|
34173
|
+
if (blocked) throw new Error(blocked);
|
|
33470
34174
|
return text4({ projects: await listGitHubProjects({ repoPath }) });
|
|
33471
34175
|
} catch (err) {
|
|
33472
34176
|
return fail2(err);
|
|
@@ -33479,6 +34183,8 @@ function registerGithubIssueTools(server) {
|
|
|
33479
34183
|
{ id: import_zod6.z.string(), include: mcpIssueIncludeSchema, repoPath: repoPathSchema },
|
|
33480
34184
|
async ({ id, include, repoPath }) => {
|
|
33481
34185
|
try {
|
|
34186
|
+
const blocked = await cursorIssueBlock(repoPath);
|
|
34187
|
+
if (blocked) throw new Error(blocked);
|
|
33482
34188
|
return text4(formatGitHubIssuePayload(await getGitHubIssue(id, { repoPath }), include));
|
|
33483
34189
|
} catch (err) {
|
|
33484
34190
|
return fail2(err);
|
|
@@ -33507,6 +34213,8 @@ function registerGithubIssueTools(server) {
|
|
|
33507
34213
|
{ id: import_zod6.z.string(), body: import_zod6.z.string(), repoPath: repoPathSchema },
|
|
33508
34214
|
async ({ id, body, repoPath }) => {
|
|
33509
34215
|
try {
|
|
34216
|
+
const blocked = await cursorIssueBlock(repoPath);
|
|
34217
|
+
if (blocked) throw new Error(blocked);
|
|
33510
34218
|
return text4(await commentGitHubIssue({ id, body }, { repoPath }));
|
|
33511
34219
|
} catch (err) {
|
|
33512
34220
|
return fail2(err);
|
|
@@ -33534,6 +34242,8 @@ function registerGithubIssueTools(server) {
|
|
|
33534
34242
|
},
|
|
33535
34243
|
async (args) => {
|
|
33536
34244
|
try {
|
|
34245
|
+
const blocked = await cursorIssueBlock(args.repoPath);
|
|
34246
|
+
if (blocked) throw new Error(blocked);
|
|
33537
34247
|
return text4(await updateGitHubIssue(args, { repoPath: args.repoPath }));
|
|
33538
34248
|
} catch (err) {
|
|
33539
34249
|
return fail2(err);
|
|
@@ -33551,6 +34261,8 @@ function registerGithubIssueTools(server) {
|
|
|
33551
34261
|
},
|
|
33552
34262
|
async (args) => {
|
|
33553
34263
|
try {
|
|
34264
|
+
const blocked = await cursorIssueBlock(args.repoPath);
|
|
34265
|
+
if (blocked) throw new Error(blocked);
|
|
33554
34266
|
return text4(await createGitHubIssue(args, { repoPath: args.repoPath }));
|
|
33555
34267
|
} catch (err) {
|
|
33556
34268
|
return fail2(err);
|
|
@@ -34239,7 +34951,7 @@ function registerScheduleTools(server) {
|
|
|
34239
34951
|
|
|
34240
34952
|
// src/agent-rpc/handlers.ts
|
|
34241
34953
|
var import_node_crypto20 = require("crypto");
|
|
34242
|
-
var
|
|
34954
|
+
var import_node_path66 = require("path");
|
|
34243
34955
|
init_wait_for_job();
|
|
34244
34956
|
init_wait_for_turn();
|
|
34245
34957
|
|
|
@@ -34304,27 +35016,27 @@ init_gh_errors();
|
|
|
34304
35016
|
init_git_auth_mode();
|
|
34305
35017
|
|
|
34306
35018
|
// src/board/load-home-board.ts
|
|
34307
|
-
var
|
|
34308
|
-
var
|
|
35019
|
+
var import_node_fs70 = require("fs");
|
|
35020
|
+
var import_node_path68 = require("path");
|
|
34309
35021
|
init_worktree();
|
|
34310
35022
|
init_paths();
|
|
34311
35023
|
|
|
34312
35024
|
// src/board/board-pins.ts
|
|
34313
35025
|
var import_node_crypto21 = require("crypto");
|
|
34314
|
-
var
|
|
34315
|
-
var
|
|
35026
|
+
var import_node_fs69 = require("fs");
|
|
35027
|
+
var import_node_path67 = require("path");
|
|
34316
35028
|
init_paths();
|
|
34317
35029
|
init_home_board();
|
|
34318
35030
|
var FILE = "home-board-pins.json";
|
|
34319
35031
|
var VERSION = 1;
|
|
34320
35032
|
function pinsFile() {
|
|
34321
|
-
return (0,
|
|
35033
|
+
return (0, import_node_path67.join)(appDataDir(), FILE);
|
|
34322
35034
|
}
|
|
34323
35035
|
function readDisk() {
|
|
34324
35036
|
const path = pinsFile();
|
|
34325
|
-
if (!(0,
|
|
35037
|
+
if (!(0, import_node_fs69.existsSync)(path)) return [];
|
|
34326
35038
|
try {
|
|
34327
|
-
const raw = JSON.parse((0,
|
|
35039
|
+
const raw = JSON.parse((0, import_node_fs69.readFileSync)(path, "utf8"));
|
|
34328
35040
|
if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
|
|
34329
35041
|
return raw.items.filter((item) => item?.id && item.kind && item.ref);
|
|
34330
35042
|
} catch {
|
|
@@ -34332,8 +35044,8 @@ function readDisk() {
|
|
|
34332
35044
|
}
|
|
34333
35045
|
}
|
|
34334
35046
|
function writeDisk(items) {
|
|
34335
|
-
(0,
|
|
34336
|
-
(0,
|
|
35047
|
+
(0, import_node_fs69.mkdirSync)(appDataDir(), { recursive: true });
|
|
35048
|
+
(0, import_node_fs69.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
|
|
34337
35049
|
}
|
|
34338
35050
|
function listBoardPins() {
|
|
34339
35051
|
return readDisk();
|
|
@@ -34354,7 +35066,7 @@ function homeBoardWorkspaceKey(workspaces) {
|
|
|
34354
35066
|
return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
|
|
34355
35067
|
}
|
|
34356
35068
|
function cacheFile() {
|
|
34357
|
-
return (0,
|
|
35069
|
+
return (0, import_node_path68.join)(appDataDir(), "home-board-cache.json");
|
|
34358
35070
|
}
|
|
34359
35071
|
function emptyInputs() {
|
|
34360
35072
|
return {
|
|
@@ -34380,9 +35092,9 @@ function shouldCacheHomeBoardInputs(inputs) {
|
|
|
34380
35092
|
}
|
|
34381
35093
|
function readDiskCache() {
|
|
34382
35094
|
const path = cacheFile();
|
|
34383
|
-
if (!(0,
|
|
35095
|
+
if (!(0, import_node_fs70.existsSync)(path)) return null;
|
|
34384
35096
|
try {
|
|
34385
|
-
const raw = JSON.parse((0,
|
|
35097
|
+
const raw = JSON.parse((0, import_node_fs70.readFileSync)(path, "utf8"));
|
|
34386
35098
|
if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
|
|
34387
35099
|
return null;
|
|
34388
35100
|
}
|
|
@@ -34396,8 +35108,8 @@ function readDiskCache() {
|
|
|
34396
35108
|
}
|
|
34397
35109
|
function writeDiskCache(entry) {
|
|
34398
35110
|
try {
|
|
34399
|
-
(0,
|
|
34400
|
-
(0,
|
|
35111
|
+
(0, import_node_fs70.mkdirSync)(appDataDir(), { recursive: true });
|
|
35112
|
+
(0, import_node_fs70.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
|
|
34401
35113
|
} catch {
|
|
34402
35114
|
}
|
|
34403
35115
|
}
|
|
@@ -34621,13 +35333,13 @@ async function startMcpServer() {
|
|
|
34621
35333
|
if (!worktreeProfile) {
|
|
34622
35334
|
server.tool(
|
|
34623
35335
|
"list_projects",
|
|
34624
|
-
"List registered projects (git repos). Each line is name, path,
|
|
35336
|
+
"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.",
|
|
34625
35337
|
{},
|
|
34626
35338
|
async () => {
|
|
34627
35339
|
const workspaces = orch.listWorkspaces();
|
|
34628
35340
|
const lines = await Promise.all(
|
|
34629
35341
|
workspaces.map(async (w) => {
|
|
34630
|
-
const
|
|
35342
|
+
const tag = await resolveProjectRemoteTag(w.path).catch(() => null);
|
|
34631
35343
|
let profile;
|
|
34632
35344
|
try {
|
|
34633
35345
|
profile = resolveViewerProfileForRepo(w.path);
|
|
@@ -34635,7 +35347,7 @@ async function startMcpServer() {
|
|
|
34635
35347
|
profile = resolveViewerProfile();
|
|
34636
35348
|
}
|
|
34637
35349
|
const suffix = formatWorkspaceProfileSuffix(profile);
|
|
34638
|
-
return
|
|
35350
|
+
return tag ? `${w.name} ${w.path} ${tag}${suffix}` : `${w.name} ${w.path}${suffix}`;
|
|
34639
35351
|
})
|
|
34640
35352
|
);
|
|
34641
35353
|
return {
|
|
@@ -34652,7 +35364,7 @@ async function startMcpServer() {
|
|
|
34652
35364
|
async () => {
|
|
34653
35365
|
const threads = orch.getThreads();
|
|
34654
35366
|
const lines = threads.map((t) => {
|
|
34655
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
35367
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path69.basename)(t.repoPath) || t.repoPath;
|
|
34656
35368
|
const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
|
|
34657
35369
|
const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
|
|
34658
35370
|
const preview = lastMessagePreview(t.messages, 80);
|
|
@@ -35482,7 +36194,7 @@ async function startMcpServer() {
|
|
|
35482
36194
|
error: true,
|
|
35483
36195
|
action,
|
|
35484
36196
|
lastError: message,
|
|
35485
|
-
hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_chat so the worktree agent
|
|
36197
|
+
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
|
|
35486
36198
|
},
|
|
35487
36199
|
true
|
|
35488
36200
|
);
|
|
@@ -35792,7 +36504,7 @@ async function startMcpServer() {
|
|
|
35792
36504
|
);
|
|
35793
36505
|
server.tool(
|
|
35794
36506
|
"list_issues",
|
|
35795
|
-
"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.",
|
|
36507
|
+
"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.",
|
|
35796
36508
|
{
|
|
35797
36509
|
repoPath: import_zod11.z.string(),
|
|
35798
36510
|
query: import_zod11.z.string().optional().describe("Search title, identifier, or description"),
|