@sideboard-ai/core 0.1.148 → 0.1.150
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/{abletime-QEVAE67D.js → abletime-223A3LY6.js} +2 -2
- package/dist/{abletime-DI55AJX3.js → abletime-CLC5UJC2.js} +2 -2
- package/dist/agents/cursor-runner.cjs +85 -45
- package/dist/agents/cursor-runner.js +47 -12
- package/dist/{agents-DUF4Q2ZI.js → agents-KKXGTEV6.js} +10 -9
- package/dist/{agents-INCTFWKA.js → agents-YWBQXOA2.js} +10 -9
- package/dist/{app-settings-WJDCJFSY.js → app-settings-3CHCNIMD.js} +5 -1
- package/dist/{app-settings-ZCN632OJ.js → app-settings-J3JBCUOT.js} +5 -1
- package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
- package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
- package/dist/{chunk-R4JP32P5.js → chunk-AF6O55PJ.js} +4 -4
- package/dist/{chunk-BOD5V52W.js → chunk-B7XK37WZ.js} +1 -1
- package/dist/{chunk-BGQBELGJ.js → chunk-CZD4NRDZ.js} +12 -0
- package/dist/{chunk-ZVYLEF72.js → chunk-DMRIZR6M.js} +6 -6
- package/dist/{chunk-5MS2XTNV.js → chunk-DXCNW2JF.js} +113 -52
- package/dist/{chunk-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
- package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
- package/dist/{chunk-3QRGCKYL.js → chunk-HAS5EPBS.js} +2 -2
- package/dist/{chunk-WT5HSFOU.js → chunk-HEII7W3Q.js} +5 -2
- package/dist/{chunk-EGDRPA4B.js → chunk-NOTANBYC.js} +6 -6
- package/dist/{chunk-CTXQHSTY.js → chunk-NUPITVRF.js} +134 -73
- package/dist/{chunk-QTUESPAW.js → chunk-PTOSP4AH.js} +1 -1
- package/dist/{chunk-Q62SDB53.js → chunk-QGJHIJHV.js} +2 -2
- package/dist/{chunk-YQRBNOIW.js → chunk-SDN4ZYQH.js} +24 -13
- package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
- package/dist/{chunk-N3VNOFXQ.js → chunk-VO4SPEBS.js} +4 -4
- package/dist/chunk-VSFGPWCQ.js +62 -0
- package/dist/{chunk-N5PM7HGQ.js → chunk-W6N6GQME.js} +1 -1
- package/dist/{chunk-FKOIHGKV.js → chunk-WHU7YGWP.js} +1 -1
- package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
- package/dist/chunk-Y4NAPW5I.js +60 -0
- package/dist/{chunk-B3SJXYIJ.js → chunk-Y7YBWWIG.js} +1 -1
- package/dist/{chunk-XOKHXFFX.js → chunk-YGGBJY5A.js} +22 -8
- package/dist/{chunk-JTPDWTWJ.js → chunk-Z2PVJKMN.js} +137 -114
- package/dist/{chunk-YP3CSOZ6.js → chunk-ZGFYFVJF.js} +142 -114
- package/dist/{connected-teams-IJUJQ7R6.js → connected-teams-I2WZZZFA.js} +2 -2
- package/dist/{connected-teams-4A2AXDNN.js → connected-teams-XO766HB4.js} +2 -2
- package/dist/{coordinator-prompt-ZWBMAIWA.js → coordinator-prompt-NYR5TPBD.js} +6 -5
- package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-UCQJTFA7.js} +6 -5
- package/dist/{global-workspace-2SIPM4PW.js → global-workspace-4QHDAD2D.js} +7 -6
- package/dist/{global-workspace-OJRXWXEA.js → global-workspace-4SENNWBU.js} +7 -6
- package/dist/index.cjs +1002 -575
- package/dist/index.d.cts +91 -10
- package/dist/index.d.ts +91 -10
- package/dist/index.js +268 -93
- package/dist/mcp/run-stdio.cjs +980 -580
- package/dist/mcp/run-stdio.js +196 -43
- package/dist/{orchestrator-OVYITCO6.js → orchestrator-GZE4X3XV.js} +14 -11
- package/dist/{orchestrator-NWIU5TJP.js → orchestrator-QSBRWME5.js} +16 -13
- package/dist/{plan-file-6O7G4VPQ.js → plan-file-5S5TUNAW.js} +2 -2
- package/dist/{plan-file-PHVKUAEE.js → plan-file-IBSU2PVW.js} +2 -2
- package/dist/{run-XQKGHQZ2.js → run-CAGKZLHA.js} +1 -1
- package/dist/{run-USF6FRKV.js → run-EBWL2Q4N.js} +1 -1
- package/dist/{workspaces-UUJNOO4T.js → workspaces-7S7QKCUE.js} +8 -7
- package/dist/{workspaces-3NUUZTQK.js → workspaces-RDUSB6FD.js} +8 -7
- package/dist/{worktree-RZRJNHYL.js → worktree-63AGPPLO.js} +5 -4
- package/dist/{worktree-UCWWTVLS.js → worktree-JIZ3QMZX.js} +5 -4
- package/dist/worktree-exclude-6MQWGWV5.js +11 -0
- package/dist/worktree-exclude-TV6EV6BS.js +9 -0
- package/package.json +1 -1
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -1527,7 +1527,7 @@ function looksLikeRetryableRunnerCrash(text5) {
|
|
|
1527
1527
|
const lower = text5.trim().toLowerCase();
|
|
1528
1528
|
if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
|
|
1529
1529
|
if (!lower) return true;
|
|
1530
|
-
return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
|
|
1530
|
+
return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|network request failed|cursor startup failed:.+\(retryable\)|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
|
|
1531
1531
|
lower
|
|
1532
1532
|
);
|
|
1533
1533
|
}
|
|
@@ -1595,6 +1595,9 @@ function humanizeAgentFailDetail(detail) {
|
|
|
1595
1595
|
if (/connection stalled/.test(lower)) {
|
|
1596
1596
|
return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
|
|
1597
1597
|
}
|
|
1598
|
+
if (/network request failed|cursor startup failed:.+\(retryable\)/.test(lower)) {
|
|
1599
|
+
return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (a transient Cursor SDK network error).`;
|
|
1600
|
+
}
|
|
1598
1601
|
return raw;
|
|
1599
1602
|
}
|
|
1600
1603
|
function turnFailChatText(opts) {
|
|
@@ -1761,16 +1764,98 @@ var init_path = __esm({
|
|
|
1761
1764
|
}
|
|
1762
1765
|
});
|
|
1763
1766
|
|
|
1767
|
+
// src/git/github-agent-auth.ts
|
|
1768
|
+
function githubAgentAuthDir() {
|
|
1769
|
+
const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
|
|
1770
|
+
if (override) return override;
|
|
1771
|
+
return (0, import_node_path12.join)((0, import_node_os4.homedir)(), ".sideboard-git-auth");
|
|
1772
|
+
}
|
|
1773
|
+
function githubCredentialStorePath() {
|
|
1774
|
+
return (0, import_node_path12.join)(githubAgentAuthDir(), "git-credentials");
|
|
1775
|
+
}
|
|
1776
|
+
function githubGhConfigDir() {
|
|
1777
|
+
return (0, import_node_path12.join)(githubAgentAuthDir(), "gh");
|
|
1778
|
+
}
|
|
1779
|
+
function writePrivateFile2(file, body) {
|
|
1780
|
+
(0, import_node_fs11.mkdirSync)((0, import_node_path12.dirname)(file), { recursive: true, mode: 448 });
|
|
1781
|
+
try {
|
|
1782
|
+
(0, import_node_fs11.chmodSync)((0, import_node_path12.dirname)(file), 448);
|
|
1783
|
+
} catch {
|
|
1784
|
+
}
|
|
1785
|
+
(0, import_node_fs11.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
1786
|
+
try {
|
|
1787
|
+
(0, import_node_fs11.chmodSync)(file, 384);
|
|
1788
|
+
} catch {
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
function gitCredentialStoreContents(token) {
|
|
1792
|
+
return `https://x-access-token:${encodeURIComponent(token)}@github.com
|
|
1793
|
+
`;
|
|
1794
|
+
}
|
|
1795
|
+
function ghHostsYml(token, user = "x-access-token") {
|
|
1796
|
+
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
1797
|
+
return [
|
|
1798
|
+
"github.com:",
|
|
1799
|
+
" git_protocol: https",
|
|
1800
|
+
` user: ${u}`,
|
|
1801
|
+
` oauth_token: ${token}`,
|
|
1802
|
+
" users:",
|
|
1803
|
+
` ${u}:`,
|
|
1804
|
+
` oauth_token: ${token}`,
|
|
1805
|
+
""
|
|
1806
|
+
].join("\n");
|
|
1807
|
+
}
|
|
1808
|
+
function materializeGithubAgentAuth(token, user) {
|
|
1809
|
+
const trimmed = token.trim();
|
|
1810
|
+
if (!trimmed) return;
|
|
1811
|
+
const root = githubAgentAuthDir();
|
|
1812
|
+
(0, import_node_fs11.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
1813
|
+
try {
|
|
1814
|
+
(0, import_node_fs11.chmodSync)(root, 448);
|
|
1815
|
+
} catch {
|
|
1816
|
+
}
|
|
1817
|
+
writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
|
|
1818
|
+
const ghDir = githubGhConfigDir();
|
|
1819
|
+
(0, import_node_fs11.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
1820
|
+
writePrivateFile2((0, import_node_path12.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
1821
|
+
writePrivateFile2((0, import_node_path12.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
1822
|
+
}
|
|
1823
|
+
function githubAgentAuthReady() {
|
|
1824
|
+
return (0, import_node_fs11.existsSync)(githubCredentialStorePath()) && (0, import_node_fs11.existsSync)((0, import_node_path12.join)(githubGhConfigDir(), "hosts.yml"));
|
|
1825
|
+
}
|
|
1826
|
+
function githubCredentialHelperGitConfig() {
|
|
1827
|
+
const file = githubCredentialStorePath();
|
|
1828
|
+
return [
|
|
1829
|
+
{ key: "credential.helper", value: "" },
|
|
1830
|
+
{ key: "credential.helper", value: `store --file=${file}` }
|
|
1831
|
+
];
|
|
1832
|
+
}
|
|
1833
|
+
function githubGhConfigEnv() {
|
|
1834
|
+
return {
|
|
1835
|
+
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
1836
|
+
GH_PROMPT_DISABLED: "1"
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
var import_node_fs11, import_node_os4, import_node_path12;
|
|
1840
|
+
var init_github_agent_auth = __esm({
|
|
1841
|
+
"src/git/github-agent-auth.ts"() {
|
|
1842
|
+
"use strict";
|
|
1843
|
+
import_node_fs11 = require("fs");
|
|
1844
|
+
import_node_os4 = require("os");
|
|
1845
|
+
import_node_path12 = require("path");
|
|
1846
|
+
}
|
|
1847
|
+
});
|
|
1848
|
+
|
|
1764
1849
|
// src/git/stale-lock.ts
|
|
1765
1850
|
function isIndexLockError(text5) {
|
|
1766
1851
|
return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text5);
|
|
1767
1852
|
}
|
|
1768
1853
|
function clearStaleIndexLock(gitDir, maxAgeMs = STALE_INDEX_LOCK_MS, now = Date.now()) {
|
|
1769
|
-
const lockPath = (0,
|
|
1854
|
+
const lockPath = (0, import_node_path13.join)(gitDir, "index.lock");
|
|
1770
1855
|
try {
|
|
1771
|
-
if (!(0,
|
|
1772
|
-
if (now - (0,
|
|
1773
|
-
(0,
|
|
1856
|
+
if (!(0, import_node_fs12.existsSync)(lockPath)) return null;
|
|
1857
|
+
if (now - (0, import_node_fs12.statSync)(lockPath).mtimeMs < maxAgeMs) return null;
|
|
1858
|
+
(0, import_node_fs12.unlinkSync)(lockPath);
|
|
1774
1859
|
return lockPath;
|
|
1775
1860
|
} catch {
|
|
1776
1861
|
return null;
|
|
@@ -1785,12 +1870,12 @@ function clearStaleIndexLocks(gitDirs, maxAgeMs = STALE_INDEX_LOCK_MS) {
|
|
|
1785
1870
|
}
|
|
1786
1871
|
return removed;
|
|
1787
1872
|
}
|
|
1788
|
-
var
|
|
1873
|
+
var import_node_fs12, import_node_path13, STALE_INDEX_LOCK_MS;
|
|
1789
1874
|
var init_stale_lock = __esm({
|
|
1790
1875
|
"src/git/stale-lock.ts"() {
|
|
1791
1876
|
"use strict";
|
|
1792
|
-
|
|
1793
|
-
|
|
1877
|
+
import_node_fs12 = require("fs");
|
|
1878
|
+
import_node_path13 = require("path");
|
|
1794
1879
|
STALE_INDEX_LOCK_MS = 2e4;
|
|
1795
1880
|
}
|
|
1796
1881
|
});
|
|
@@ -1887,7 +1972,10 @@ async function gh(args, cwd, opts) {
|
|
|
1887
1972
|
timeoutMs: opts?.timeoutMs,
|
|
1888
1973
|
env: {
|
|
1889
1974
|
GH_PROMPT_DISABLED: "1",
|
|
1890
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
1975
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
1976
|
+
// Isolated hosts.yml uses git_protocol: https so `gh pr create` does not
|
|
1977
|
+
// shell out over SSH when Settings → Git is SSH (ask_git in Electron).
|
|
1978
|
+
...githubAgentAuthReady() ? githubGhConfigEnv() : {}
|
|
1891
1979
|
}
|
|
1892
1980
|
});
|
|
1893
1981
|
}
|
|
@@ -1903,6 +1991,7 @@ var init_run = __esm({
|
|
|
1903
1991
|
"use strict";
|
|
1904
1992
|
import_execa2 = require("execa");
|
|
1905
1993
|
init_path();
|
|
1994
|
+
init_github_agent_auth();
|
|
1906
1995
|
init_stale_lock();
|
|
1907
1996
|
}
|
|
1908
1997
|
});
|
|
@@ -2741,6 +2830,18 @@ var init_worktree_labels = __esm({
|
|
|
2741
2830
|
function isGhRateLimitError(text5) {
|
|
2742
2831
|
return /API rate limit (already )?exceeded/i.test(text5) || /rate limit exceeded/i.test(text5);
|
|
2743
2832
|
}
|
|
2833
|
+
function isGhPrBodyTooLongError(text5) {
|
|
2834
|
+
return /body is too long|body.{0,20}too long|maximum is 65536|exceeds the maximum allowed size|request (entity |is )?too large|payload too large|413 Request Entity Too Large/i.test(
|
|
2835
|
+
text5
|
|
2836
|
+
);
|
|
2837
|
+
}
|
|
2838
|
+
function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
|
|
2839
|
+
const t = body.replace(/\s+$/u, "");
|
|
2840
|
+
if (t.length <= max) return t;
|
|
2841
|
+
const note = "\n\n_(truncated to fit GitHub\u2019s PR body limit)_";
|
|
2842
|
+
const keep = Math.max(0, max - note.length);
|
|
2843
|
+
return `${t.slice(0, keep).replace(/\s+$/u, "")}${note}`;
|
|
2844
|
+
}
|
|
2744
2845
|
function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
2745
2846
|
const ms = resetEpochSec * 1e3 - nowMs;
|
|
2746
2847
|
if (ms <= 0) return "soon";
|
|
@@ -2751,18 +2852,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
|
2751
2852
|
const hours = Math.ceil(mins / 60);
|
|
2752
2853
|
return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
|
|
2753
2854
|
}
|
|
2855
|
+
function omitGhBodyArg(text5) {
|
|
2856
|
+
return text5.replace(
|
|
2857
|
+
/--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
|
|
2858
|
+
"--body <omitted>"
|
|
2859
|
+
);
|
|
2860
|
+
}
|
|
2861
|
+
function capGhErrorText(text5, max = 400) {
|
|
2862
|
+
const t = text5.trim();
|
|
2863
|
+
if (t.length <= max) return t;
|
|
2864
|
+
return `${t.slice(0, max - 1).trimEnd()}\u2026`;
|
|
2865
|
+
}
|
|
2754
2866
|
function extractGhErrorDetail(text5) {
|
|
2755
|
-
const trimmed = text5.trim();
|
|
2867
|
+
const trimmed = omitGhBodyArg(text5.trim());
|
|
2756
2868
|
if (!trimmed) return "";
|
|
2869
|
+
if (isGhPrBodyTooLongError(text5) || isGhPrBodyTooLongError(trimmed)) {
|
|
2870
|
+
return "GraphQL: body is too long (GitHub PR body / request size limit).";
|
|
2871
|
+
}
|
|
2757
2872
|
const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
|
|
2758
|
-
if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}
|
|
2873
|
+
if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
|
|
2759
2874
|
const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
|
|
2760
|
-
if (http?.[1]) return `HTTP: ${http[1].trim()}
|
|
2875
|
+
if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
|
|
2761
2876
|
const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
2762
2877
|
if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
|
|
2763
|
-
return lines.slice(1).join(" ").trim() || lines[0];
|
|
2878
|
+
return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
|
|
2764
2879
|
}
|
|
2765
|
-
return trimmed;
|
|
2880
|
+
return capGhErrorText(trimmed);
|
|
2766
2881
|
}
|
|
2767
2882
|
function formatGhLandError(raw, opts) {
|
|
2768
2883
|
const trimmed = raw.trim();
|
|
@@ -2780,6 +2895,10 @@ function formatGhLandError(raw, opts) {
|
|
|
2780
2895
|
const hint = opts?.targetedRepo ? ` Branch was pushed to origin \u2014 confirm it exists on GitHub and differs from the base branch.${target}${head}.` : " Often `gh` targeted upstream instead of origin. Branch was pushed \u2014 retry in the latest Sideboard, or run: gh pr create -R <owner/name> --base main --head <branch>.";
|
|
2781
2896
|
return `Could not create the pull request.${hint}`;
|
|
2782
2897
|
}
|
|
2898
|
+
if (isGhPrBodyTooLongError(raw) || isGhPrBodyTooLongError(detail)) {
|
|
2899
|
+
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
2900
|
+
return `GitHub rejected the pull request: the GraphQL body is too long (PR description / request size, limit ${GITHUB_PR_BODY_MAX_CHARS} characters).${pushNote} Retry with a short title and body via \`gh pr create --body-file\` (or send_to_thread so the worktree agent writes a brief description). Do not paste a changelog or diff into --body.`;
|
|
2901
|
+
}
|
|
2783
2902
|
if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
|
|
2784
2903
|
const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
|
|
2785
2904
|
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
@@ -2800,15 +2919,82 @@ function formatMergePrError(raw) {
|
|
|
2800
2919
|
}
|
|
2801
2920
|
return extractGhErrorDetail(trimmed) || trimmed;
|
|
2802
2921
|
}
|
|
2922
|
+
var GITHUB_PR_BODY_MAX_CHARS, GITHUB_PR_BODY_SAFE_CHARS;
|
|
2803
2923
|
var init_gh_errors = __esm({
|
|
2804
2924
|
"src/git/gh-errors.ts"() {
|
|
2805
2925
|
"use strict";
|
|
2926
|
+
GITHUB_PR_BODY_MAX_CHARS = 65536;
|
|
2927
|
+
GITHUB_PR_BODY_SAFE_CHARS = 6e4;
|
|
2928
|
+
}
|
|
2929
|
+
});
|
|
2930
|
+
|
|
2931
|
+
// src/git/worktree-exclude.ts
|
|
2932
|
+
var worktree_exclude_exports = {};
|
|
2933
|
+
__export(worktree_exclude_exports, {
|
|
2934
|
+
WORKTREE_SIDEBOARD_EXCLUDE: () => WORKTREE_SIDEBOARD_EXCLUDE,
|
|
2935
|
+
ensureWorktreeSideboardIgnored: () => ensureWorktreeSideboardIgnored
|
|
2936
|
+
});
|
|
2937
|
+
function excludeHasSideboard(body) {
|
|
2938
|
+
return body.split(/\r?\n/).some((line) => {
|
|
2939
|
+
const t = line.trim();
|
|
2940
|
+
return t === ".sideboard/" || t === ".sideboard" || t === "/.sideboard/";
|
|
2941
|
+
});
|
|
2942
|
+
}
|
|
2943
|
+
async function ensureWorktreeSideboardIgnored(worktreePath) {
|
|
2944
|
+
if (!worktreePath.trim()) return;
|
|
2945
|
+
const gitDir = await git(["rev-parse", "--absolute-git-dir"], worktreePath, {
|
|
2946
|
+
reject: false,
|
|
2947
|
+
timeoutMs: 5e3
|
|
2948
|
+
});
|
|
2949
|
+
if (gitDir.exitCode !== 0) return;
|
|
2950
|
+
const dir = gitDir.stdout.trim();
|
|
2951
|
+
if (!dir) return;
|
|
2952
|
+
const excludePath = (0, import_node_path14.join)(dir, "info", "exclude");
|
|
2953
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path14.dirname)(excludePath), { recursive: true });
|
|
2954
|
+
let body = "";
|
|
2955
|
+
try {
|
|
2956
|
+
body = (0, import_node_fs13.readFileSync)(excludePath, "utf8");
|
|
2957
|
+
} catch {
|
|
2958
|
+
body = "";
|
|
2959
|
+
}
|
|
2960
|
+
if (!excludeHasSideboard(body)) {
|
|
2961
|
+
const prefix = body && !body.endsWith("\n") ? `${body}
|
|
2962
|
+
` : body;
|
|
2963
|
+
(0, import_node_fs13.writeFileSync)(
|
|
2964
|
+
excludePath,
|
|
2965
|
+
`${prefix}${EXCLUDE_COMMENT}
|
|
2966
|
+
${WORKTREE_SIDEBOARD_EXCLUDE}
|
|
2967
|
+
`,
|
|
2968
|
+
"utf8"
|
|
2969
|
+
);
|
|
2970
|
+
}
|
|
2971
|
+
const listed = await git(["ls-files", "-z", "--", ".sideboard"], worktreePath, {
|
|
2972
|
+
reject: false,
|
|
2973
|
+
timeoutMs: 5e3
|
|
2974
|
+
});
|
|
2975
|
+
if (listed.exitCode !== 0 || !listed.stdout) return;
|
|
2976
|
+
const files = listed.stdout.split("\0").filter(Boolean);
|
|
2977
|
+
if (files.length === 0) return;
|
|
2978
|
+
await git(["update-index", "--skip-worktree", "--", ...files], worktreePath, {
|
|
2979
|
+
reject: false,
|
|
2980
|
+
timeoutMs: 8e3
|
|
2981
|
+
});
|
|
2982
|
+
}
|
|
2983
|
+
var import_node_fs13, import_node_path14, WORKTREE_SIDEBOARD_EXCLUDE, EXCLUDE_COMMENT;
|
|
2984
|
+
var init_worktree_exclude = __esm({
|
|
2985
|
+
"src/git/worktree-exclude.ts"() {
|
|
2986
|
+
"use strict";
|
|
2987
|
+
import_node_fs13 = require("fs");
|
|
2988
|
+
import_node_path14 = require("path");
|
|
2989
|
+
init_run();
|
|
2990
|
+
WORKTREE_SIDEBOARD_EXCLUDE = ".sideboard/";
|
|
2991
|
+
EXCLUDE_COMMENT = "# Sideboard worktree scratch \u2014 do not commit";
|
|
2806
2992
|
}
|
|
2807
2993
|
});
|
|
2808
2994
|
|
|
2809
2995
|
// src/store/secret-vault.ts
|
|
2810
2996
|
function secretVaultPath() {
|
|
2811
|
-
return (0,
|
|
2997
|
+
return (0, import_node_path15.join)(appDataDir(), "secrets.json");
|
|
2812
2998
|
}
|
|
2813
2999
|
function loadSecretVault() {
|
|
2814
3000
|
const parsed = readSecureJson(secretVaultPath());
|
|
@@ -2867,11 +3053,11 @@ function normalizeVault(raw) {
|
|
|
2867
3053
|
}
|
|
2868
3054
|
return out;
|
|
2869
3055
|
}
|
|
2870
|
-
var
|
|
3056
|
+
var import_node_path15;
|
|
2871
3057
|
var init_secret_vault = __esm({
|
|
2872
3058
|
"src/store/secret-vault.ts"() {
|
|
2873
3059
|
"use strict";
|
|
2874
|
-
|
|
3060
|
+
import_node_path15 = require("path");
|
|
2875
3061
|
init_paths();
|
|
2876
3062
|
init_secure_file();
|
|
2877
3063
|
}
|
|
@@ -2900,6 +3086,7 @@ var init_issue_source_labels = __esm({
|
|
|
2900
3086
|
// src/store/app-settings.ts
|
|
2901
3087
|
var app_settings_exports = {};
|
|
2902
3088
|
__export(app_settings_exports, {
|
|
3089
|
+
FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
|
|
2903
3090
|
GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
|
|
2904
3091
|
HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
|
|
2905
3092
|
ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
|
|
@@ -2925,6 +3112,7 @@ __export(app_settings_exports, {
|
|
|
2925
3112
|
disconnectLinearConnection: () => disconnectLinearConnection,
|
|
2926
3113
|
emptyPublicIntegrations: () => emptyPublicIntegrations,
|
|
2927
3114
|
ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
|
|
3115
|
+
followUpBehavior: () => followUpBehavior,
|
|
2928
3116
|
getAbleTimeAccessToken: () => getAbleTimeAccessToken,
|
|
2929
3117
|
getAbleTimeHost: () => getAbleTimeHost,
|
|
2930
3118
|
getDefaultAgent: () => getDefaultAgent,
|
|
@@ -3033,10 +3221,10 @@ function toPublicAppSettings(settings) {
|
|
|
3033
3221
|
};
|
|
3034
3222
|
}
|
|
3035
3223
|
function appSettingsPath() {
|
|
3036
|
-
return (0,
|
|
3224
|
+
return (0, import_node_path16.join)(appDataDir(), "settings.json");
|
|
3037
3225
|
}
|
|
3038
3226
|
function claudeUserSettingsPath() {
|
|
3039
|
-
return (0,
|
|
3227
|
+
return (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".claude", "settings.json");
|
|
3040
3228
|
}
|
|
3041
3229
|
function normalizeClaude(raw) {
|
|
3042
3230
|
if (!raw || typeof raw !== "object") return {};
|
|
@@ -3281,6 +3469,9 @@ function normalizeAdvanced(raw) {
|
|
|
3281
3469
|
if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent) && source.orchestrationQuotaFallbackAgent !== "brightsy") {
|
|
3282
3470
|
out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
|
|
3283
3471
|
}
|
|
3472
|
+
if (source.followUpBehavior === "queue" || source.followUpBehavior === "steer") {
|
|
3473
|
+
out.followUpBehavior = source.followUpBehavior;
|
|
3474
|
+
}
|
|
3284
3475
|
return out;
|
|
3285
3476
|
}
|
|
3286
3477
|
function normalizeSettings(raw) {
|
|
@@ -3340,10 +3531,10 @@ function normalizeSettings(raw) {
|
|
|
3340
3531
|
}
|
|
3341
3532
|
function readSettingsFile() {
|
|
3342
3533
|
const path = appSettingsPath();
|
|
3343
|
-
if (!(0,
|
|
3534
|
+
if (!(0, import_node_fs14.existsSync)(path)) return { ...EMPTY_SETTINGS };
|
|
3344
3535
|
try {
|
|
3345
3536
|
chmodOwnerOnly(path);
|
|
3346
|
-
const parsed = JSON.parse((0,
|
|
3537
|
+
const parsed = JSON.parse((0, import_node_fs14.readFileSync)(path, "utf8"));
|
|
3347
3538
|
return normalizeSettings(parsed);
|
|
3348
3539
|
} catch {
|
|
3349
3540
|
return { ...EMPTY_SETTINGS };
|
|
@@ -3889,7 +4080,7 @@ function ensureSlackDeviceIdentity(settings = loadAppSettings()) {
|
|
|
3889
4080
|
}
|
|
3890
4081
|
if (!deviceLabel) {
|
|
3891
4082
|
try {
|
|
3892
|
-
deviceLabel = (0,
|
|
4083
|
+
deviceLabel = (0, import_node_os5.hostname)().split(".")[0]?.trim() || "This Mac";
|
|
3893
4084
|
} catch {
|
|
3894
4085
|
deviceLabel = "This Mac";
|
|
3895
4086
|
}
|
|
@@ -3972,6 +4163,9 @@ function updateAdvancedSettings(patch) {
|
|
|
3972
4163
|
if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent) && patch.orchestrationQuotaFallbackAgent !== "brightsy") {
|
|
3973
4164
|
advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
|
|
3974
4165
|
}
|
|
4166
|
+
if (patch.followUpBehavior === "queue" || patch.followUpBehavior === "steer") {
|
|
4167
|
+
advanced.followUpBehavior = patch.followUpBehavior;
|
|
4168
|
+
}
|
|
3975
4169
|
return saveAppSettings({ ...current, advanced });
|
|
3976
4170
|
}
|
|
3977
4171
|
function autoRenameBranchEnabled(settings = loadAppSettings()) {
|
|
@@ -4017,6 +4211,9 @@ function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
|
|
|
4017
4211
|
}
|
|
4018
4212
|
return "cursor";
|
|
4019
4213
|
}
|
|
4214
|
+
function followUpBehavior(settings = loadAppSettings()) {
|
|
4215
|
+
return settings.advanced.followUpBehavior === "queue" ? "queue" : "steer";
|
|
4216
|
+
}
|
|
4020
4217
|
function maxConcurrentAgents(settings = loadAppSettings()) {
|
|
4021
4218
|
const n = settings.advanced.maxConcurrent;
|
|
4022
4219
|
if (typeof n === "number" && Number.isFinite(n)) {
|
|
@@ -4104,14 +4301,14 @@ function childEnvWithAppSettings(extra) {
|
|
|
4104
4301
|
function harnessEnvKey(harness) {
|
|
4105
4302
|
return HARNESS_ENV_KEYS[harness];
|
|
4106
4303
|
}
|
|
4107
|
-
var import_node_crypto3,
|
|
4304
|
+
var import_node_crypto3, import_node_fs14, import_node_os5, import_node_path16, HARNESS_ENV_KEYS, DEFAULT_AGENTS, GITHUB_GIT_AUTH_MODES, FOLLOW_UP_BEHAVIORS, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, GIT_AUTH_MODES, EMPTY_SETTINGS, DEFAULT_CLI_BIN;
|
|
4108
4305
|
var init_app_settings = __esm({
|
|
4109
4306
|
"src/store/app-settings.ts"() {
|
|
4110
4307
|
"use strict";
|
|
4111
4308
|
import_node_crypto3 = require("crypto");
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4309
|
+
import_node_fs14 = require("fs");
|
|
4310
|
+
import_node_os5 = require("os");
|
|
4311
|
+
import_node_path16 = require("path");
|
|
4115
4312
|
init_thinking_effort();
|
|
4116
4313
|
init_nested_electron_env();
|
|
4117
4314
|
init_paths();
|
|
@@ -4133,6 +4330,7 @@ var init_app_settings = __esm({
|
|
|
4133
4330
|
"cursor"
|
|
4134
4331
|
]);
|
|
4135
4332
|
GITHUB_GIT_AUTH_MODES = ["auto", "gh", "ssh", "token"];
|
|
4333
|
+
FOLLOW_UP_BEHAVIORS = ["steer", "queue"];
|
|
4136
4334
|
CLOUD_CONNECT_AGENTS = /* @__PURE__ */ new Set([
|
|
4137
4335
|
"claude",
|
|
4138
4336
|
"codex",
|
|
@@ -4160,89 +4358,26 @@ var init_app_settings = __esm({
|
|
|
4160
4358
|
}
|
|
4161
4359
|
});
|
|
4162
4360
|
|
|
4163
|
-
// src/git/
|
|
4164
|
-
function
|
|
4165
|
-
const
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
}
|
|
4172
|
-
|
|
4173
|
-
return (0, import_node_path15.join)(githubAgentAuthDir(), "gh");
|
|
4174
|
-
}
|
|
4175
|
-
function writePrivateFile2(file, body) {
|
|
4176
|
-
(0, import_node_fs13.mkdirSync)((0, import_node_path15.dirname)(file), { recursive: true, mode: 448 });
|
|
4177
|
-
try {
|
|
4178
|
-
(0, import_node_fs13.chmodSync)((0, import_node_path15.dirname)(file), 448);
|
|
4179
|
-
} catch {
|
|
4180
|
-
}
|
|
4181
|
-
(0, import_node_fs13.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
4182
|
-
try {
|
|
4183
|
-
(0, import_node_fs13.chmodSync)(file, 384);
|
|
4184
|
-
} catch {
|
|
4361
|
+
// src/git/git-auth-mode.ts
|
|
4362
|
+
function githubHttpsInsteadOfEntries(remoteUrl) {
|
|
4363
|
+
const entries = [...HTTPS_REWRITE];
|
|
4364
|
+
const url = remoteUrl?.trim() ?? "";
|
|
4365
|
+
const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
|
|
4366
|
+
if (scpAlias?.[1]) {
|
|
4367
|
+
entries.push({
|
|
4368
|
+
key: "url.https://github.com/.insteadOf",
|
|
4369
|
+
value: `${scpAlias[1]}:`
|
|
4370
|
+
});
|
|
4185
4371
|
}
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
}
|
|
4191
|
-
|
|
4192
|
-
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
4193
|
-
return [
|
|
4194
|
-
"github.com:",
|
|
4195
|
-
" git_protocol: https",
|
|
4196
|
-
` user: ${u}`,
|
|
4197
|
-
` oauth_token: ${token}`,
|
|
4198
|
-
" users:",
|
|
4199
|
-
` ${u}:`,
|
|
4200
|
-
` oauth_token: ${token}`,
|
|
4201
|
-
""
|
|
4202
|
-
].join("\n");
|
|
4203
|
-
}
|
|
4204
|
-
function materializeGithubAgentAuth(token, user) {
|
|
4205
|
-
const trimmed = token.trim();
|
|
4206
|
-
if (!trimmed) return;
|
|
4207
|
-
const root = githubAgentAuthDir();
|
|
4208
|
-
(0, import_node_fs13.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
4209
|
-
try {
|
|
4210
|
-
(0, import_node_fs13.chmodSync)(root, 448);
|
|
4211
|
-
} catch {
|
|
4372
|
+
const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
|
|
4373
|
+
if (sshAlias?.[1]) {
|
|
4374
|
+
entries.push({
|
|
4375
|
+
key: "url.https://github.com/.insteadOf",
|
|
4376
|
+
value: `ssh://git@${sshAlias[1]}/`
|
|
4377
|
+
});
|
|
4212
4378
|
}
|
|
4213
|
-
|
|
4214
|
-
const ghDir = githubGhConfigDir();
|
|
4215
|
-
(0, import_node_fs13.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
4216
|
-
writePrivateFile2((0, import_node_path15.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
4217
|
-
writePrivateFile2((0, import_node_path15.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
4218
|
-
}
|
|
4219
|
-
function githubAgentAuthReady() {
|
|
4220
|
-
return (0, import_node_fs13.existsSync)(githubCredentialStorePath()) && (0, import_node_fs13.existsSync)((0, import_node_path15.join)(githubGhConfigDir(), "hosts.yml"));
|
|
4221
|
-
}
|
|
4222
|
-
function githubCredentialHelperGitConfig() {
|
|
4223
|
-
const file = githubCredentialStorePath();
|
|
4224
|
-
return [
|
|
4225
|
-
{ key: "credential.helper", value: "" },
|
|
4226
|
-
{ key: "credential.helper", value: `store --file=${file}` }
|
|
4227
|
-
];
|
|
4228
|
-
}
|
|
4229
|
-
function githubGhConfigEnv() {
|
|
4230
|
-
return {
|
|
4231
|
-
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
4232
|
-
GH_PROMPT_DISABLED: "1"
|
|
4233
|
-
};
|
|
4379
|
+
return entries;
|
|
4234
4380
|
}
|
|
4235
|
-
var import_node_fs13, import_node_os5, import_node_path15;
|
|
4236
|
-
var init_github_agent_auth = __esm({
|
|
4237
|
-
"src/git/github-agent-auth.ts"() {
|
|
4238
|
-
"use strict";
|
|
4239
|
-
import_node_fs13 = require("fs");
|
|
4240
|
-
import_node_os5 = require("os");
|
|
4241
|
-
import_node_path15 = require("path");
|
|
4242
|
-
}
|
|
4243
|
-
});
|
|
4244
|
-
|
|
4245
|
-
// src/git/git-auth-mode.ts
|
|
4246
4381
|
function nonInteractiveGitProcessEnv() {
|
|
4247
4382
|
return {
|
|
4248
4383
|
GIT_TERMINAL_PROMPT: "0",
|
|
@@ -4265,16 +4400,19 @@ function appendIndexedGitConfig(existing, entries) {
|
|
|
4265
4400
|
out.GIT_CONFIG_COUNT = String(count + entries.length);
|
|
4266
4401
|
return out;
|
|
4267
4402
|
}
|
|
4268
|
-
function githubAgentGitEnv(existing) {
|
|
4403
|
+
function githubAgentGitEnv(existing, opts) {
|
|
4269
4404
|
const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
|
|
4270
|
-
return appendIndexedGitConfig(existing, [
|
|
4405
|
+
return appendIndexedGitConfig(existing, [
|
|
4406
|
+
...githubHttpsInsteadOfEntries(opts?.remoteUrl),
|
|
4407
|
+
...helpers
|
|
4408
|
+
]);
|
|
4271
4409
|
}
|
|
4272
4410
|
function applyGithubGitAuthEnv(existing, opts) {
|
|
4273
4411
|
const out = { ...nonInteractiveGitProcessEnv() };
|
|
4274
4412
|
const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
|
|
4275
4413
|
if (token) materializeGithubAgentAuth(token);
|
|
4276
4414
|
Object.assign(out, githubGhConfigEnv());
|
|
4277
|
-
if (opts.mode === "ssh") return out;
|
|
4415
|
+
if (opts.mode === "ssh" && !token) return out;
|
|
4278
4416
|
Object.assign(out, githubAgentGitEnv(existing));
|
|
4279
4417
|
return out;
|
|
4280
4418
|
}
|
|
@@ -4330,7 +4468,7 @@ async function warmGithubAgentAuth(opts) {
|
|
|
4330
4468
|
}
|
|
4331
4469
|
function normalizeWritableRoot(raw) {
|
|
4332
4470
|
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
4333
|
-
return trimmed && (0,
|
|
4471
|
+
return trimmed && (0, import_node_path17.isAbsolute)(trimmed) ? trimmed : null;
|
|
4334
4472
|
}
|
|
4335
4473
|
async function resolveCodexGitWritableRoots(cwd) {
|
|
4336
4474
|
const roots = /* @__PURE__ */ new Set();
|
|
@@ -4387,8 +4525,9 @@ function formatGitAuthModeDirective(mode) {
|
|
|
4387
4525
|
case "ssh":
|
|
4388
4526
|
return [
|
|
4389
4527
|
"Git authentication (Settings \u2192 Git mode: SSH):",
|
|
4390
|
-
"-
|
|
4391
|
-
"-
|
|
4528
|
+
"- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
|
|
4529
|
+
"- This process may push over HTTPS via `gh` (process-only `insteadOf`) so ask_git / unattended turns work when ssh-agent is missing \u2014 that does not change the stored remote.",
|
|
4530
|
+
"- SSH is batch-mode: it will not prompt for a Keychain password. If both SSH and HTTPS fail, tell the user to unlock ssh-agent or run `gh auth login` (or switch Settings \u2192 Git to Auto).",
|
|
4392
4531
|
"- `gh` already authenticates for PRs/API (no token in the environment). Do not set GitHub token environment variables or run `gh auth login` from this turn.",
|
|
4393
4532
|
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
4394
4533
|
].join("\n");
|
|
@@ -4407,11 +4546,11 @@ function formatGitAuthModeDirective(mode) {
|
|
|
4407
4546
|
].join("\n");
|
|
4408
4547
|
}
|
|
4409
4548
|
}
|
|
4410
|
-
var
|
|
4549
|
+
var import_node_path17, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
|
|
4411
4550
|
var init_git_auth_mode = __esm({
|
|
4412
4551
|
"src/git/git-auth-mode.ts"() {
|
|
4413
4552
|
"use strict";
|
|
4414
|
-
|
|
4553
|
+
import_node_path17 = require("path");
|
|
4415
4554
|
init_app_settings();
|
|
4416
4555
|
init_github_agent_auth();
|
|
4417
4556
|
init_run();
|
|
@@ -4759,7 +4898,7 @@ function attachmentsGitignoreBody() {
|
|
|
4759
4898
|
}
|
|
4760
4899
|
function isWorkspaceScratchPath(relativePath) {
|
|
4761
4900
|
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
4762
|
-
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".context" || p.startsWith(".context/");
|
|
4901
|
+
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
|
|
4763
4902
|
}
|
|
4764
4903
|
var ATTACHMENTS_DIR, LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_GITIGNORE;
|
|
4765
4904
|
var init_workspace_scratch = __esm({
|
|
@@ -4866,7 +5005,7 @@ async function resolveRepoRoot(cwd) {
|
|
|
4866
5005
|
}
|
|
4867
5006
|
function canonicalizeRepoPath(path) {
|
|
4868
5007
|
try {
|
|
4869
|
-
return (0,
|
|
5008
|
+
return (0, import_node_fs15.realpathSync)(path);
|
|
4870
5009
|
} catch {
|
|
4871
5010
|
return path.replace(/\/+$/, "");
|
|
4872
5011
|
}
|
|
@@ -5605,6 +5744,16 @@ function originFetchBranch(sourceRef) {
|
|
|
5605
5744
|
if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
|
|
5606
5745
|
return ref;
|
|
5607
5746
|
}
|
|
5747
|
+
async function originRemoteUrl(cwd) {
|
|
5748
|
+
const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
|
|
5749
|
+
return result.exitCode === 0 ? result.stdout.trim() : "";
|
|
5750
|
+
}
|
|
5751
|
+
function githubHttpsRetryEnv(remoteUrl) {
|
|
5752
|
+
return {
|
|
5753
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
5754
|
+
...githubAgentGitEnv(void 0, { remoteUrl })
|
|
5755
|
+
};
|
|
5756
|
+
}
|
|
5608
5757
|
async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
5609
5758
|
const first = await git(args, repoPath, { reject: false, timeoutMs });
|
|
5610
5759
|
if (first.exitCode === 0) return true;
|
|
@@ -5614,15 +5763,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
|
5614
5763
|
} catch {
|
|
5615
5764
|
return false;
|
|
5616
5765
|
}
|
|
5617
|
-
if (mode === "ssh") return false;
|
|
5618
5766
|
const token = await resolveGithubAgentToken(mode, repoPath);
|
|
5619
5767
|
if (!token) return false;
|
|
5768
|
+
const remoteUrl = await originRemoteUrl(repoPath);
|
|
5620
5769
|
const tryHttps = async (header) => git(args, repoPath, {
|
|
5621
5770
|
reject: false,
|
|
5622
5771
|
timeoutMs,
|
|
5623
|
-
env:
|
|
5772
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
5624
5773
|
config: {
|
|
5625
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
5626
5774
|
"http.extraHeader": header
|
|
5627
5775
|
}
|
|
5628
5776
|
});
|
|
@@ -5704,8 +5852,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
|
|
|
5704
5852
|
}
|
|
5705
5853
|
async function createThreadWorktree(opts) {
|
|
5706
5854
|
let branchName = `thread/${opts.slug}`;
|
|
5707
|
-
const worktreePath = (0,
|
|
5708
|
-
if ((0,
|
|
5855
|
+
const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
5856
|
+
if ((0, import_node_fs15.existsSync)(worktreePath)) {
|
|
5709
5857
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
5710
5858
|
}
|
|
5711
5859
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -5740,13 +5888,14 @@ ${add.stdout}`;
|
|
|
5740
5888
|
});
|
|
5741
5889
|
branchName = added;
|
|
5742
5890
|
await ensureGhPreferOrigin(worktreePath);
|
|
5891
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5743
5892
|
return { branchName, worktreePath };
|
|
5744
5893
|
}
|
|
5745
5894
|
async function createExistingBranchWorktree(opts) {
|
|
5746
5895
|
const branchName = opts.branchName.trim();
|
|
5747
5896
|
if (!branchName) throw new Error("branch name required");
|
|
5748
|
-
const worktreePath = (0,
|
|
5749
|
-
if ((0,
|
|
5897
|
+
const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
5898
|
+
if ((0, import_node_fs15.existsSync)(worktreePath)) {
|
|
5750
5899
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
5751
5900
|
}
|
|
5752
5901
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -5784,6 +5933,7 @@ async function createExistingBranchWorktree(opts) {
|
|
|
5784
5933
|
await git(["checkout", "-B", branchName], worktreePath, { reject: false });
|
|
5785
5934
|
}
|
|
5786
5935
|
await ensureGhPreferOrigin(worktreePath);
|
|
5936
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5787
5937
|
return { branchName, worktreePath };
|
|
5788
5938
|
}
|
|
5789
5939
|
async function removeWorktree(repoPath, worktreePath, opts) {
|
|
@@ -5872,7 +6022,9 @@ async function currentBranch(worktreePath) {
|
|
|
5872
6022
|
async function commitAll(worktreePath, message) {
|
|
5873
6023
|
const dirty = await isDirty(worktreePath);
|
|
5874
6024
|
if (!dirty) return false;
|
|
6025
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5875
6026
|
await git(["add", "-A"], worktreePath);
|
|
6027
|
+
await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
|
|
5876
6028
|
await git(["commit", "-m", message], worktreePath);
|
|
5877
6029
|
return true;
|
|
5878
6030
|
}
|
|
@@ -5886,14 +6038,14 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
5886
6038
|
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
|
|
5887
6039
|
if (!slug || !token) {
|
|
5888
6040
|
throw new Error(
|
|
5889
|
-
sshErr || `git push origin ${branchName} failed` + (!token ? " (
|
|
6041
|
+
sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
|
|
5890
6042
|
);
|
|
5891
6043
|
}
|
|
6044
|
+
const remoteUrl = await originRemoteUrl(worktreePath);
|
|
5892
6045
|
const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
|
|
5893
6046
|
reject: false,
|
|
5894
|
-
env:
|
|
6047
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
5895
6048
|
config: {
|
|
5896
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
5897
6049
|
"http.extraHeader": header
|
|
5898
6050
|
}
|
|
5899
6051
|
});
|
|
@@ -6023,6 +6175,32 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6023
6175
|
const repoArgs = ghRepoSelectArgs(slug);
|
|
6024
6176
|
const headRef = ghHeadRef(slug, opts.head);
|
|
6025
6177
|
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
6178
|
+
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
6179
|
+
const bodyFile = (0, import_node_path18.join)(
|
|
6180
|
+
(0, import_node_os6.tmpdir)(),
|
|
6181
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto4.randomBytes)(6).toString("hex")}.md`
|
|
6182
|
+
);
|
|
6183
|
+
(0, import_node_fs15.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
6184
|
+
`, "utf8");
|
|
6185
|
+
const bodyArgs = ["--body-file", bodyFile];
|
|
6186
|
+
try {
|
|
6187
|
+
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
6188
|
+
...opts,
|
|
6189
|
+
slug,
|
|
6190
|
+
repoArgs,
|
|
6191
|
+
headRef,
|
|
6192
|
+
branchOnly,
|
|
6193
|
+
bodyArgs
|
|
6194
|
+
});
|
|
6195
|
+
} finally {
|
|
6196
|
+
try {
|
|
6197
|
+
(0, import_node_fs15.unlinkSync)(bodyFile);
|
|
6198
|
+
} catch {
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
6201
|
+
}
|
|
6202
|
+
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
6203
|
+
const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
|
|
6026
6204
|
const existing = await gh(
|
|
6027
6205
|
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
6028
6206
|
worktreePath,
|
|
@@ -6038,8 +6216,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6038
6216
|
branchOnly,
|
|
6039
6217
|
"--title",
|
|
6040
6218
|
opts.title,
|
|
6041
|
-
|
|
6042
|
-
opts.body ?? opts.title
|
|
6219
|
+
...bodyArgs
|
|
6043
6220
|
],
|
|
6044
6221
|
worktreePath,
|
|
6045
6222
|
{ reject: false }
|
|
@@ -6054,8 +6231,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6054
6231
|
"--web",
|
|
6055
6232
|
"--title",
|
|
6056
6233
|
opts.title,
|
|
6057
|
-
|
|
6058
|
-
opts.body ?? opts.title,
|
|
6234
|
+
...bodyArgs,
|
|
6059
6235
|
"--base",
|
|
6060
6236
|
opts.base,
|
|
6061
6237
|
"--head",
|
|
@@ -6076,8 +6252,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6076
6252
|
"create",
|
|
6077
6253
|
"--title",
|
|
6078
6254
|
opts.title,
|
|
6079
|
-
|
|
6080
|
-
opts.body ?? opts.title,
|
|
6255
|
+
...bodyArgs,
|
|
6081
6256
|
"--base",
|
|
6082
6257
|
opts.base,
|
|
6083
6258
|
"--head",
|
|
@@ -6101,10 +6276,10 @@ function sameRepoPath(a, b) {
|
|
|
6101
6276
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
6102
6277
|
}
|
|
6103
6278
|
function listLocalThreadBranchSlugs(repoPath) {
|
|
6104
|
-
const refsDir = (0,
|
|
6105
|
-
if (!(0,
|
|
6279
|
+
const refsDir = (0, import_node_path18.join)(repoPath, ".git", "refs", "heads", "thread");
|
|
6280
|
+
if (!(0, import_node_fs15.existsSync)(refsDir)) return [];
|
|
6106
6281
|
try {
|
|
6107
|
-
return (0,
|
|
6282
|
+
return (0, import_node_fs15.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
|
|
6108
6283
|
} catch {
|
|
6109
6284
|
return [];
|
|
6110
6285
|
}
|
|
@@ -6112,8 +6287,8 @@ function listLocalThreadBranchSlugs(repoPath) {
|
|
|
6112
6287
|
function collectTakenTeamSlugs(repoPath) {
|
|
6113
6288
|
const taken = /* @__PURE__ */ new Set();
|
|
6114
6289
|
const root = worktreesRoot(repoPath);
|
|
6115
|
-
if ((0,
|
|
6116
|
-
for (const entry of (0,
|
|
6290
|
+
if ((0, import_node_fs15.existsSync)(root)) {
|
|
6291
|
+
for (const entry of (0, import_node_fs15.readdirSync)(root, { withFileTypes: true })) {
|
|
6117
6292
|
if (entry.isDirectory() && entry.name !== ".DS_Store") {
|
|
6118
6293
|
taken.add(normalizeTakenSlug(entry.name));
|
|
6119
6294
|
}
|
|
@@ -6134,23 +6309,26 @@ function allocateTeamSlug(repoPath) {
|
|
|
6134
6309
|
const taken = collectTakenTeamSlugs(repoPath);
|
|
6135
6310
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
6136
6311
|
const team = allocateTeamName(taken);
|
|
6137
|
-
const path = (0,
|
|
6138
|
-
if (!(0,
|
|
6312
|
+
const path = (0, import_node_path18.join)(worktreesRoot(repoPath), team.slug);
|
|
6313
|
+
if (!(0, import_node_fs15.existsSync)(path)) return team;
|
|
6139
6314
|
taken.add(team.slug);
|
|
6140
6315
|
}
|
|
6141
6316
|
throw new Error("No available soccer team worktree directories left");
|
|
6142
6317
|
}
|
|
6143
|
-
var
|
|
6318
|
+
var import_node_crypto4, import_node_fs15, import_node_os6, import_node_path18;
|
|
6144
6319
|
var init_worktree = __esm({
|
|
6145
6320
|
"src/git/worktree.ts"() {
|
|
6146
6321
|
"use strict";
|
|
6147
|
-
|
|
6148
|
-
|
|
6322
|
+
import_node_crypto4 = require("crypto");
|
|
6323
|
+
import_node_fs15 = require("fs");
|
|
6324
|
+
import_node_os6 = require("os");
|
|
6325
|
+
import_node_path18 = require("path");
|
|
6149
6326
|
init_paths();
|
|
6150
6327
|
init_thread_store();
|
|
6151
6328
|
init_teams();
|
|
6152
6329
|
init_worktree_labels();
|
|
6153
6330
|
init_gh_errors();
|
|
6331
|
+
init_worktree_exclude();
|
|
6154
6332
|
init_git_auth_mode();
|
|
6155
6333
|
init_run();
|
|
6156
6334
|
init_repo_git_lock();
|
|
@@ -6194,7 +6372,7 @@ var init_cloud_connect_constants = __esm({
|
|
|
6194
6372
|
|
|
6195
6373
|
// src/composer/stage-files.ts
|
|
6196
6374
|
function fileExtension(filePath) {
|
|
6197
|
-
const base = (0,
|
|
6375
|
+
const base = (0, import_node_path19.basename)(filePath).toLowerCase();
|
|
6198
6376
|
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
6199
6377
|
}
|
|
6200
6378
|
function isImageFilePath(filePath) {
|
|
@@ -6204,24 +6382,24 @@ function imageMimeType(filePath) {
|
|
|
6204
6382
|
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
6205
6383
|
}
|
|
6206
6384
|
function ensureAttachmentsDir(worktreePath) {
|
|
6207
|
-
const dir = (0,
|
|
6208
|
-
(0,
|
|
6209
|
-
const gi = (0,
|
|
6210
|
-
if (!(0,
|
|
6211
|
-
(0,
|
|
6385
|
+
const dir = (0, import_node_path19.join)(worktreePath, ATTACHMENTS_DIR);
|
|
6386
|
+
(0, import_node_fs16.mkdirSync)(dir, { recursive: true });
|
|
6387
|
+
const gi = (0, import_node_path19.join)(dir, ".gitignore");
|
|
6388
|
+
if (!(0, import_node_fs16.existsSync)(gi)) {
|
|
6389
|
+
(0, import_node_fs16.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
6212
6390
|
}
|
|
6213
6391
|
return dir;
|
|
6214
6392
|
}
|
|
6215
6393
|
function uniqueAttachmentName(dir, originalName) {
|
|
6216
6394
|
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
6217
|
-
if (!(0,
|
|
6218
|
-
const ext = (0,
|
|
6395
|
+
if (!(0, import_node_fs16.existsSync)((0, import_node_path19.join)(dir, safe))) return safe;
|
|
6396
|
+
const ext = (0, import_node_path19.extname)(safe);
|
|
6219
6397
|
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
6220
6398
|
for (let i = 1; i < 1e4; i++) {
|
|
6221
6399
|
const candidate = `${stem}-${i}${ext}`;
|
|
6222
|
-
if (!(0,
|
|
6400
|
+
if (!(0, import_node_fs16.existsSync)((0, import_node_path19.join)(dir, candidate))) return candidate;
|
|
6223
6401
|
}
|
|
6224
|
-
return `${stem}-${(0,
|
|
6402
|
+
return `${stem}-${(0, import_node_crypto5.randomUUID)()}${ext}`;
|
|
6225
6403
|
}
|
|
6226
6404
|
function previewDataUrlFromBuf(filePath, buf) {
|
|
6227
6405
|
if (!isImageFilePath(filePath)) return void 0;
|
|
@@ -6233,7 +6411,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
6233
6411
|
if (isImageFilePath(name)) {
|
|
6234
6412
|
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
6235
6413
|
return {
|
|
6236
|
-
id: (0,
|
|
6414
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6237
6415
|
name,
|
|
6238
6416
|
kind: "file",
|
|
6239
6417
|
path: opts.path,
|
|
@@ -6246,7 +6424,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
6246
6424
|
}
|
|
6247
6425
|
if (buf.length > MAX_INLINE_BYTES) {
|
|
6248
6426
|
return {
|
|
6249
|
-
id: (0,
|
|
6427
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6250
6428
|
name,
|
|
6251
6429
|
kind: "file",
|
|
6252
6430
|
path: opts.path,
|
|
@@ -6255,7 +6433,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
6255
6433
|
}
|
|
6256
6434
|
if (buf.includes(0)) {
|
|
6257
6435
|
return {
|
|
6258
|
-
id: (0,
|
|
6436
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6259
6437
|
name,
|
|
6260
6438
|
kind: "file",
|
|
6261
6439
|
path: opts.path,
|
|
@@ -6263,7 +6441,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
6263
6441
|
};
|
|
6264
6442
|
}
|
|
6265
6443
|
return {
|
|
6266
|
-
id: (0,
|
|
6444
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6267
6445
|
name,
|
|
6268
6446
|
kind: "file",
|
|
6269
6447
|
path: opts.path,
|
|
@@ -6275,19 +6453,19 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
|
6275
6453
|
const dir = ensureAttachmentsDir(worktreePath);
|
|
6276
6454
|
const out = [];
|
|
6277
6455
|
for (const abs of absolutePaths) {
|
|
6278
|
-
const originalName = (0,
|
|
6456
|
+
const originalName = (0, import_node_path19.basename)(abs);
|
|
6279
6457
|
try {
|
|
6280
|
-
const st = (0,
|
|
6458
|
+
const st = (0, import_node_fs16.statSync)(abs);
|
|
6281
6459
|
if (!st.isFile()) continue;
|
|
6282
6460
|
const name = uniqueAttachmentName(dir, originalName);
|
|
6283
|
-
const destAbs = (0,
|
|
6284
|
-
(0,
|
|
6461
|
+
const destAbs = (0, import_node_path19.join)(dir, name);
|
|
6462
|
+
(0, import_node_fs16.copyFileSync)(abs, destAbs);
|
|
6285
6463
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
6286
|
-
const buf = (0,
|
|
6464
|
+
const buf = (0, import_node_fs16.readFileSync)(destAbs);
|
|
6287
6465
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
6288
6466
|
} catch (err) {
|
|
6289
6467
|
out.push({
|
|
6290
|
-
id: (0,
|
|
6468
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6291
6469
|
name: originalName,
|
|
6292
6470
|
kind: "file",
|
|
6293
6471
|
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -6305,13 +6483,13 @@ function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
|
6305
6483
|
try {
|
|
6306
6484
|
const buf = Buffer.from(item.dataBase64, "base64");
|
|
6307
6485
|
const name = uniqueAttachmentName(dir, originalName);
|
|
6308
|
-
const destAbs = (0,
|
|
6309
|
-
(0,
|
|
6486
|
+
const destAbs = (0, import_node_path19.join)(dir, name);
|
|
6487
|
+
(0, import_node_fs16.writeFileSync)(destAbs, buf);
|
|
6310
6488
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
6311
6489
|
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
6312
6490
|
} catch (err) {
|
|
6313
6491
|
out.push({
|
|
6314
|
-
id: (0,
|
|
6492
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6315
6493
|
name: originalName,
|
|
6316
6494
|
kind: "file",
|
|
6317
6495
|
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -6366,23 +6544,23 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
6366
6544
|
for (const rel of relativePaths) {
|
|
6367
6545
|
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
6368
6546
|
out.push({
|
|
6369
|
-
id: (0,
|
|
6370
|
-
name: (0,
|
|
6547
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6548
|
+
name: (0, import_node_path19.basename)(rel) || "file",
|
|
6371
6549
|
kind: "file",
|
|
6372
6550
|
content: `(invalid path: ${rel})`
|
|
6373
6551
|
});
|
|
6374
6552
|
continue;
|
|
6375
6553
|
}
|
|
6376
|
-
const name = (0,
|
|
6554
|
+
const name = (0, import_node_path19.basename)(rel);
|
|
6377
6555
|
try {
|
|
6378
|
-
const abs = (0,
|
|
6379
|
-
const st = (0,
|
|
6556
|
+
const abs = (0, import_node_path19.join)(worktreePath, rel);
|
|
6557
|
+
const st = (0, import_node_fs16.statSync)(abs);
|
|
6380
6558
|
if (!st.isFile()) continue;
|
|
6381
|
-
const buf = (0,
|
|
6559
|
+
const buf = (0, import_node_fs16.readFileSync)(abs);
|
|
6382
6560
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
6383
6561
|
} catch (err) {
|
|
6384
6562
|
out.push({
|
|
6385
|
-
id: (0,
|
|
6563
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6386
6564
|
name,
|
|
6387
6565
|
kind: "file",
|
|
6388
6566
|
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -6391,13 +6569,13 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
6391
6569
|
}
|
|
6392
6570
|
return out;
|
|
6393
6571
|
}
|
|
6394
|
-
var
|
|
6572
|
+
var import_node_fs16, import_node_path19, import_node_crypto5, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
|
|
6395
6573
|
var init_stage_files = __esm({
|
|
6396
6574
|
"src/composer/stage-files.ts"() {
|
|
6397
6575
|
"use strict";
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6576
|
+
import_node_fs16 = require("fs");
|
|
6577
|
+
import_node_path19 = require("path");
|
|
6578
|
+
import_node_crypto5 = require("crypto");
|
|
6401
6579
|
init_workspace_scratch();
|
|
6402
6580
|
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6403
6581
|
"png",
|
|
@@ -6514,7 +6692,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
6514
6692
|
function ensureGlobalCoordinatorCwd(opts) {
|
|
6515
6693
|
const dir = globalAgentCwd();
|
|
6516
6694
|
try {
|
|
6517
|
-
(0,
|
|
6695
|
+
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
6518
6696
|
} catch {
|
|
6519
6697
|
return dir;
|
|
6520
6698
|
}
|
|
@@ -6522,7 +6700,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
6522
6700
|
let orchId = opts?.orchestratorThreadId?.trim() || "";
|
|
6523
6701
|
if (!orchId) {
|
|
6524
6702
|
try {
|
|
6525
|
-
const existing = (0,
|
|
6703
|
+
const existing = (0, import_node_fs17.readFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), "utf8");
|
|
6526
6704
|
const m = existing.match(
|
|
6527
6705
|
/YOUR orchestration thread id is `([0-9a-f-]{36})`/i
|
|
6528
6706
|
);
|
|
@@ -6565,9 +6743,9 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
6565
6743
|
"Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
|
|
6566
6744
|
].join("\n");
|
|
6567
6745
|
try {
|
|
6568
|
-
(0,
|
|
6746
|
+
(0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
|
|
6569
6747
|
`, "utf8");
|
|
6570
|
-
(0,
|
|
6748
|
+
(0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), `${body}
|
|
6571
6749
|
`, "utf8");
|
|
6572
6750
|
} catch {
|
|
6573
6751
|
}
|
|
@@ -6599,12 +6777,12 @@ function coordinatorSystemPrompt(opts) {
|
|
|
6599
6777
|
formatWorkspaceInventory(opts.workspaces)
|
|
6600
6778
|
].join("\n");
|
|
6601
6779
|
}
|
|
6602
|
-
var
|
|
6780
|
+
var import_node_fs17, import_node_path20, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
|
|
6603
6781
|
var init_coordinator_prompt = __esm({
|
|
6604
6782
|
"src/orchestrator/coordinator-prompt.ts"() {
|
|
6605
6783
|
"use strict";
|
|
6606
|
-
|
|
6607
|
-
|
|
6784
|
+
import_node_fs17 = require("fs");
|
|
6785
|
+
import_node_path20 = require("path");
|
|
6608
6786
|
init_worktree();
|
|
6609
6787
|
init_app_settings();
|
|
6610
6788
|
init_paths();
|
|
@@ -6614,8 +6792,8 @@ var init_coordinator_prompt = __esm({
|
|
|
6614
6792
|
"Discover:",
|
|
6615
6793
|
"- list_workspaces \u2014 registered repos (path + github slug when known)",
|
|
6616
6794
|
"- list_board \u2014 Home Kanban of worktrees (New / Draft / Review / Merged; one card per checkout). Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind, column, limit.",
|
|
6617
|
-
"- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues)",
|
|
6618
|
-
"- linear_list_teams / linear_get_issue / linear_create_issue / linear_update_issue / linear_comment \u2014 Linear Account connection; call linear_list_teams for team key and workflow states; pass ENG-123 or uuid. linear_get_issue returns comments, relations, parent/children, and the rest of the issue metadata. If mutations fail with a scope error, Disconnect and Connect Linear in Account settings.",
|
|
6795
|
+
"- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues). list_issues accepts query and assignee (me / unassigned / all / user id) so Linear is not limited to tickets assigned to you.",
|
|
6796
|
+
"- linear_list_teams / linear_search_issues / linear_get_issue / linear_create_issue / linear_update_issue / linear_comment \u2014 Linear Account connection; call linear_list_teams for team key and workflow states; pass ENG-123 or uuid. linear_search_issues finds unassigned and other people's open issues (assignee=unassigned|all|me|user). linear_get_issue returns comments, relations, parent/children, and the rest of the issue metadata. If mutations fail with a scope error, Disconnect and Connect Linear in Account settings.",
|
|
6619
6797
|
"- abletime_orientation / abletime_list_projects / abletime_list_tasks / abletime_search_tasks / abletime_get_task / abletime_create_task / abletime_ensure_task \u2014 AbleTime Account personal access token (hosted MCP). Call orientation first. If work has no task yet, abletime_ensure_task creates one to track against (or create_thread from the default branch does that automatically when AbleTime is the preferred issue source).",
|
|
6620
6798
|
"- list_teams / slack_list_channels / slack_list_users / slack_search / slack_read / slack_post / slack_replies \u2014 Slack workspaces from Settings \u2192 Remote; pass team_id from list_teams",
|
|
6621
6799
|
"- Optional connectors (Vercel, Supabase, PostHog, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`) with those env vars. PostHog has no first-class CLI \u2014 use the HTTP API (`POSTHOG_PERSONAL_API_KEY`). If a CLI is missing, the user can Install CLI on that row (not auto-installed on Connect). Do not add vendor MCPs or ask the user to paste tokens again. Git (`gh`) stays Settings \u2192 Git; issue tracking stays Settings \u2192 Issues; Slack stays Settings \u2192 Remote (Sideboard MCP).",
|
|
@@ -6634,7 +6812,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6634
6812
|
"- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
|
|
6635
6813
|
"- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
|
|
6636
6814
|
"- send_to_thread \u2014 queue a prompt (start/continue a chat turn). force_stop: true only to replace a wrong in-flight request \u2014 never to check in, resume after a halt notice, or because wait_for_turn returned stillRunning (that kills the child mid-thought)",
|
|
6637
|
-
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success. On status stopped or broken (or incomplete=true), the child was interrupted or died \u2014 resume with send_to_thread or tell the user; never treat stopped as a finished turn. Sideboard also injects a notice into this chat when a child stops unexpectedly.",
|
|
6815
|
+
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). stillRunning is the source of truth \u2014 if it is false, the child is not working; do not tell the user it is running or \u201Cwaiting for a gate,\u201D even if status still says running/queued. If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. If stillRunning stays true across many waits with the same lastActivityAt, the child is stuck \u2014 tell the user; do not invent a gate. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success. On status stopped or broken (or incomplete=true), the child was interrupted or died \u2014 resume with send_to_thread or tell the user; never treat stopped as a finished turn. Sideboard also injects a notice into this chat when a child stops unexpectedly.",
|
|
6638
6816
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
6639
6817
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
6640
6818
|
"Setup / run:",
|
|
@@ -6643,7 +6821,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6643
6821
|
"Inspect / review / PRs:",
|
|
6644
6822
|
"- get_diff \u2014 compact diff summary",
|
|
6645
6823
|
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else seeds that skill / local guidelines; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
|
|
6646
|
-
"- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing.",
|
|
6824
|
+
"- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error.",
|
|
6647
6825
|
'- Merge (`ask_git` action=merge / send_to_thread "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.',
|
|
6648
6826
|
'- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
|
|
6649
6827
|
"Process guides:",
|
|
@@ -6914,32 +7092,32 @@ var init_global_workspace = __esm({
|
|
|
6914
7092
|
function brightsyConfigPath() {
|
|
6915
7093
|
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
6916
7094
|
if (override) return override;
|
|
6917
|
-
return (0,
|
|
7095
|
+
return (0, import_node_path21.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
|
|
6918
7096
|
}
|
|
6919
7097
|
function loadBrightsyConfig() {
|
|
6920
7098
|
const path = brightsyConfigPath();
|
|
6921
|
-
if (!(0,
|
|
7099
|
+
if (!(0, import_node_fs18.existsSync)(path)) {
|
|
6922
7100
|
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
6923
7101
|
}
|
|
6924
|
-
const raw = JSON.parse((0,
|
|
7102
|
+
const raw = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
|
|
6925
7103
|
if (!raw.access_token || !raw.account_id) {
|
|
6926
7104
|
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
6927
7105
|
}
|
|
6928
7106
|
return raw;
|
|
6929
7107
|
}
|
|
6930
7108
|
function saveBrightsyConfig(cfg) {
|
|
6931
|
-
(0,
|
|
7109
|
+
(0, import_node_fs18.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
6932
7110
|
`, {
|
|
6933
7111
|
mode: 384
|
|
6934
7112
|
});
|
|
6935
7113
|
}
|
|
6936
|
-
var
|
|
7114
|
+
var import_node_fs18, import_node_os7, import_node_path21;
|
|
6937
7115
|
var init_config = __esm({
|
|
6938
7116
|
"src/brightsy/config.ts"() {
|
|
6939
7117
|
"use strict";
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
7118
|
+
import_node_fs18 = require("fs");
|
|
7119
|
+
import_node_os7 = require("os");
|
|
7120
|
+
import_node_path21 = require("path");
|
|
6943
7121
|
}
|
|
6944
7122
|
});
|
|
6945
7123
|
|
|
@@ -7056,22 +7234,22 @@ var init_oauth = __esm({
|
|
|
7056
7234
|
|
|
7057
7235
|
// src/brightsy/connected-teams.ts
|
|
7058
7236
|
function storePath4() {
|
|
7059
|
-
return (0,
|
|
7237
|
+
return (0, import_node_path22.join)(appDataDir(), "brightsy-teams.json");
|
|
7060
7238
|
}
|
|
7061
7239
|
function readStore4() {
|
|
7062
7240
|
const path = storePath4();
|
|
7063
|
-
if (!(0,
|
|
7241
|
+
if (!(0, import_node_fs19.existsSync)(path)) return [];
|
|
7064
7242
|
try {
|
|
7065
|
-
const parsed = JSON.parse((0,
|
|
7243
|
+
const parsed = JSON.parse((0, import_node_fs19.readFileSync)(path, "utf8"));
|
|
7066
7244
|
return Array.isArray(parsed.teams) ? parsed.teams : [];
|
|
7067
7245
|
} catch {
|
|
7068
7246
|
return [];
|
|
7069
7247
|
}
|
|
7070
7248
|
}
|
|
7071
7249
|
function writeStore2(teams) {
|
|
7072
|
-
(0,
|
|
7250
|
+
(0, import_node_fs19.mkdirSync)(appDataDir(), { recursive: true });
|
|
7073
7251
|
const path = storePath4();
|
|
7074
|
-
(0,
|
|
7252
|
+
(0, import_node_fs19.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
|
|
7075
7253
|
`, {
|
|
7076
7254
|
mode: 384
|
|
7077
7255
|
});
|
|
@@ -7177,12 +7355,12 @@ function brightsyMcpServerName(slug) {
|
|
|
7177
7355
|
const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
|
|
7178
7356
|
return `brightsy_${cleaned || "team"}`;
|
|
7179
7357
|
}
|
|
7180
|
-
var
|
|
7358
|
+
var import_node_fs19, import_node_path22;
|
|
7181
7359
|
var init_connected_teams = __esm({
|
|
7182
7360
|
"src/brightsy/connected-teams.ts"() {
|
|
7183
7361
|
"use strict";
|
|
7184
|
-
|
|
7185
|
-
|
|
7362
|
+
import_node_fs19 = require("fs");
|
|
7363
|
+
import_node_path22 = require("path");
|
|
7186
7364
|
init_paths();
|
|
7187
7365
|
init_accounts();
|
|
7188
7366
|
init_config();
|
|
@@ -7554,11 +7732,11 @@ async function syncCliForTarget(accountId) {
|
|
|
7554
7732
|
}
|
|
7555
7733
|
applyConnectedTeamToCli(team);
|
|
7556
7734
|
}
|
|
7557
|
-
var
|
|
7735
|
+
var import_node_fs20, brightsyAdapter;
|
|
7558
7736
|
var init_brightsy = __esm({
|
|
7559
7737
|
"src/agents/brightsy.ts"() {
|
|
7560
7738
|
"use strict";
|
|
7561
|
-
|
|
7739
|
+
import_node_fs20 = require("fs");
|
|
7562
7740
|
init_run();
|
|
7563
7741
|
init_connected_teams();
|
|
7564
7742
|
init_config();
|
|
@@ -7573,7 +7751,7 @@ var init_brightsy = __esm({
|
|
|
7573
7751
|
async detect() {
|
|
7574
7752
|
const brightsy = resolveAgentExecutable("brightsy");
|
|
7575
7753
|
if (brightsy !== "brightsy") {
|
|
7576
|
-
if (!(0,
|
|
7754
|
+
if (!(0, import_node_fs20.existsSync)(brightsy)) {
|
|
7577
7755
|
return {
|
|
7578
7756
|
agent: "brightsy",
|
|
7579
7757
|
installed: false,
|
|
@@ -7804,6 +7982,13 @@ function isSubagentToolName(name) {
|
|
|
7804
7982
|
if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
|
|
7805
7983
|
return /connectedAgentRequest/i.test(n);
|
|
7806
7984
|
}
|
|
7985
|
+
function isInternalAgentStatusText(text5) {
|
|
7986
|
+
const t = text5.trim();
|
|
7987
|
+
if (!t) return false;
|
|
7988
|
+
if (/waiting for gate to pass/i.test(t)) return true;
|
|
7989
|
+
if (/^agent is running\b/i.test(t) && t.length < 160) return true;
|
|
7990
|
+
return false;
|
|
7991
|
+
}
|
|
7807
7992
|
function isPollWrapperToolName(name) {
|
|
7808
7993
|
const n = (name ?? "").replace(/[_-]/g, "");
|
|
7809
7994
|
return /^(taskoutput|taskstop|sleep)$/i.test(n);
|
|
@@ -7811,7 +7996,10 @@ function isPollWrapperToolName(name) {
|
|
|
7811
7996
|
function lastTextPart(parts, type) {
|
|
7812
7997
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
7813
7998
|
const p = parts[i];
|
|
7814
|
-
if (p.type
|
|
7999
|
+
if (p.type !== type) continue;
|
|
8000
|
+
const text5 = p.text.trim();
|
|
8001
|
+
if (!text5 || isInternalAgentStatusText(text5)) continue;
|
|
8002
|
+
return text5;
|
|
7815
8003
|
}
|
|
7816
8004
|
return "";
|
|
7817
8005
|
}
|
|
@@ -8148,43 +8336,43 @@ function electronResourcesPath() {
|
|
|
8148
8336
|
function packagedCursorRuntimeDir() {
|
|
8149
8337
|
const resources = electronResourcesPath();
|
|
8150
8338
|
if (!resources) return null;
|
|
8151
|
-
const dir = (0,
|
|
8152
|
-
if (!(0,
|
|
8339
|
+
const dir = (0, import_node_path23.join)(resources, "cursor-runtime");
|
|
8340
|
+
if (!(0, import_node_fs21.existsSync)((0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
8153
8341
|
return dir;
|
|
8154
8342
|
}
|
|
8155
8343
|
function packagedCursorRunnerPath() {
|
|
8156
8344
|
const dir = packagedCursorRuntimeDir();
|
|
8157
|
-
return dir ? (0,
|
|
8345
|
+
return dir ? (0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
8158
8346
|
}
|
|
8159
8347
|
function packagedMcpDir() {
|
|
8160
8348
|
const resources = electronResourcesPath();
|
|
8161
8349
|
if (!resources) return null;
|
|
8162
|
-
const dir = (0,
|
|
8163
|
-
if (!(0,
|
|
8350
|
+
const dir = (0, import_node_path23.join)(resources, "sideboard-mcp");
|
|
8351
|
+
if (!(0, import_node_fs21.existsSync)((0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
8164
8352
|
return dir;
|
|
8165
8353
|
}
|
|
8166
8354
|
function packagedMcpStdioPath() {
|
|
8167
8355
|
const dir = packagedMcpDir();
|
|
8168
|
-
return dir ? (0,
|
|
8356
|
+
return dir ? (0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
8169
8357
|
}
|
|
8170
8358
|
function packagedBundledNodePath() {
|
|
8171
8359
|
const resources = electronResourcesPath();
|
|
8172
8360
|
if (!resources) return null;
|
|
8173
|
-
const bin = (0,
|
|
8174
|
-
if (!(0,
|
|
8361
|
+
const bin = (0, import_node_path23.join)(resources, "node", "bin", "node");
|
|
8362
|
+
if (!(0, import_node_fs21.existsSync)(bin)) return null;
|
|
8175
8363
|
return bin;
|
|
8176
8364
|
}
|
|
8177
8365
|
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
8178
8366
|
const dir = packagedCursorRuntimeDir();
|
|
8179
8367
|
if (!dir) return null;
|
|
8180
|
-
return (0,
|
|
8368
|
+
return (0, import_node_path23.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
8181
8369
|
}
|
|
8182
|
-
var
|
|
8370
|
+
var import_node_fs21, import_node_path23;
|
|
8183
8371
|
var init_packaged_runtime = __esm({
|
|
8184
8372
|
"src/agents/packaged-runtime.ts"() {
|
|
8185
8373
|
"use strict";
|
|
8186
|
-
|
|
8187
|
-
|
|
8374
|
+
import_node_fs21 = require("fs");
|
|
8375
|
+
import_node_path23 = require("path");
|
|
8188
8376
|
}
|
|
8189
8377
|
});
|
|
8190
8378
|
|
|
@@ -8218,7 +8406,7 @@ function unpackedAsarPath(filePath) {
|
|
|
8218
8406
|
if (!isAsarPath(filePath)) return null;
|
|
8219
8407
|
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
8220
8408
|
if (unpacked === filePath) return null;
|
|
8221
|
-
return (0,
|
|
8409
|
+
return (0, import_node_fs22.existsSync)(unpacked) ? unpacked : null;
|
|
8222
8410
|
}
|
|
8223
8411
|
function nodeReadableScriptPath(scriptPath) {
|
|
8224
8412
|
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
@@ -8258,37 +8446,37 @@ function pickPreferredNode(candidates) {
|
|
|
8258
8446
|
return best;
|
|
8259
8447
|
}
|
|
8260
8448
|
function versionDirNodeBins(root, toBin) {
|
|
8261
|
-
if (!(0,
|
|
8449
|
+
if (!(0, import_node_fs22.existsSync)(root)) return [];
|
|
8262
8450
|
try {
|
|
8263
|
-
return (0,
|
|
8451
|
+
return (0, import_node_fs22.readdirSync)(root).map(toBin);
|
|
8264
8452
|
} catch {
|
|
8265
8453
|
return [];
|
|
8266
8454
|
}
|
|
8267
8455
|
}
|
|
8268
|
-
function defaultNodeBinCandidates(home = (0,
|
|
8456
|
+
function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
|
|
8269
8457
|
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
8270
|
-
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0,
|
|
8458
|
+
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path24.join)(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
8271
8459
|
);
|
|
8272
8460
|
return [
|
|
8273
8461
|
...kegs,
|
|
8274
8462
|
"/opt/homebrew/bin/node",
|
|
8275
8463
|
"/usr/local/bin/node",
|
|
8276
|
-
(0,
|
|
8277
|
-
(0,
|
|
8278
|
-
(0,
|
|
8279
|
-
(0,
|
|
8280
|
-
(0,
|
|
8464
|
+
(0, import_node_path24.join)(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
8465
|
+
(0, import_node_path24.join)(home, ".nvm/current/bin/node"),
|
|
8466
|
+
(0, import_node_path24.join)(home, ".volta/bin/node"),
|
|
8467
|
+
(0, import_node_path24.join)(home, ".asdf/shims/node"),
|
|
8468
|
+
(0, import_node_path24.join)(home, ".local/share/mise/shims/node"),
|
|
8281
8469
|
...versionDirNodeBins(
|
|
8282
|
-
(0,
|
|
8283
|
-
(name) => (0,
|
|
8470
|
+
(0, import_node_path24.join)(home, ".nvm", "versions", "node"),
|
|
8471
|
+
(name) => (0, import_node_path24.join)(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
8284
8472
|
),
|
|
8285
8473
|
...versionDirNodeBins(
|
|
8286
|
-
(0,
|
|
8287
|
-
(name) => (0,
|
|
8474
|
+
(0, import_node_path24.join)(home, ".local/share/fnm", "node-versions"),
|
|
8475
|
+
(name) => (0, import_node_path24.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
8288
8476
|
),
|
|
8289
8477
|
...versionDirNodeBins(
|
|
8290
|
-
(0,
|
|
8291
|
-
(name) => (0,
|
|
8478
|
+
(0, import_node_path24.join)(home, ".volta", "tools", "image", "node"),
|
|
8479
|
+
(name) => (0, import_node_path24.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
8292
8480
|
)
|
|
8293
8481
|
];
|
|
8294
8482
|
}
|
|
@@ -8297,10 +8485,10 @@ function uniqueExistingNodeBins(paths) {
|
|
|
8297
8485
|
const out = [];
|
|
8298
8486
|
for (const raw of paths) {
|
|
8299
8487
|
const p = raw.trim();
|
|
8300
|
-
if (!p || !(0,
|
|
8488
|
+
if (!p || !(0, import_node_fs22.existsSync)(p) || isElectronLikeCommand(p)) continue;
|
|
8301
8489
|
let key = p;
|
|
8302
8490
|
try {
|
|
8303
|
-
key = (0,
|
|
8491
|
+
key = (0, import_node_fs22.realpathSync)(p);
|
|
8304
8492
|
} catch {
|
|
8305
8493
|
continue;
|
|
8306
8494
|
}
|
|
@@ -8380,13 +8568,13 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
8380
8568
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
8381
8569
|
};
|
|
8382
8570
|
}
|
|
8383
|
-
var
|
|
8571
|
+
var import_node_fs22, import_node_os8, import_node_path24, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
|
|
8384
8572
|
var init_node_launch = __esm({
|
|
8385
8573
|
"src/agents/node-launch.ts"() {
|
|
8386
8574
|
"use strict";
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8575
|
+
import_node_fs22 = require("fs");
|
|
8576
|
+
import_node_os8 = require("os");
|
|
8577
|
+
import_node_path24 = require("path");
|
|
8390
8578
|
init_nested_electron_env();
|
|
8391
8579
|
init_run();
|
|
8392
8580
|
init_packaged_runtime();
|
|
@@ -8480,37 +8668,37 @@ function corePackageDir() {
|
|
|
8480
8668
|
try {
|
|
8481
8669
|
const url = import_meta.url;
|
|
8482
8670
|
if (typeof url === "string" && url.length > 0) {
|
|
8483
|
-
return (0,
|
|
8671
|
+
return (0, import_node_path25.dirname)((0, import_node_url.fileURLToPath)(url));
|
|
8484
8672
|
}
|
|
8485
8673
|
} catch {
|
|
8486
8674
|
}
|
|
8487
8675
|
try {
|
|
8488
|
-
const req = (0, import_node_module.createRequire)((0,
|
|
8489
|
-
return (0,
|
|
8676
|
+
const req = (0, import_node_module.createRequire)((0, import_node_path25.join)(process.cwd(), "package.json"));
|
|
8677
|
+
return (0, import_node_path25.dirname)(req.resolve("@sideboard-ai/core"));
|
|
8490
8678
|
} catch {
|
|
8491
8679
|
return process.cwd();
|
|
8492
8680
|
}
|
|
8493
8681
|
}
|
|
8494
8682
|
function findSideboardMcpJsEntry() {
|
|
8495
8683
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
8496
|
-
if (override && (0,
|
|
8684
|
+
if (override && (0, import_node_fs23.existsSync)(override)) return override;
|
|
8497
8685
|
const packaged = packagedMcpStdioPath();
|
|
8498
8686
|
if (packaged) return packaged;
|
|
8499
8687
|
let dir = corePackageDir();
|
|
8500
8688
|
for (let i = 0; i < 10; i++) {
|
|
8501
8689
|
const candidates = [
|
|
8502
|
-
(0,
|
|
8503
|
-
(0,
|
|
8504
|
-
(0,
|
|
8505
|
-
(0,
|
|
8506
|
-
(0,
|
|
8507
|
-
(0,
|
|
8508
|
-
(0,
|
|
8690
|
+
(0, import_node_path25.join)(dir, "mcp/run-stdio.js"),
|
|
8691
|
+
(0, import_node_path25.join)(dir, "mcp/run-stdio.cjs"),
|
|
8692
|
+
(0, import_node_path25.join)(dir, "dist/mcp/run-stdio.js"),
|
|
8693
|
+
(0, import_node_path25.join)(dir, "dist/mcp/run-stdio.cjs"),
|
|
8694
|
+
(0, import_node_path25.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
|
|
8695
|
+
(0, import_node_path25.join)(dir, "packages/cli/dist/index.js"),
|
|
8696
|
+
(0, import_node_path25.join)(dir, "cli/dist/index.js")
|
|
8509
8697
|
];
|
|
8510
8698
|
for (const p of candidates) {
|
|
8511
|
-
if ((0,
|
|
8699
|
+
if ((0, import_node_fs23.existsSync)(p) && !isAsarPath(p)) return p;
|
|
8512
8700
|
}
|
|
8513
|
-
const parent = (0,
|
|
8701
|
+
const parent = (0, import_node_path25.dirname)(dir);
|
|
8514
8702
|
if (parent === dir) break;
|
|
8515
8703
|
dir = parent;
|
|
8516
8704
|
}
|
|
@@ -8652,19 +8840,19 @@ function writeMcpServersConfig(servers) {
|
|
|
8652
8840
|
...env ? { env } : {}
|
|
8653
8841
|
};
|
|
8654
8842
|
}
|
|
8655
|
-
const dir = (0,
|
|
8656
|
-
const cfgPath = (0,
|
|
8657
|
-
(0,
|
|
8843
|
+
const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path25.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
|
|
8844
|
+
const cfgPath = (0, import_node_path25.join)(dir, "mcp.json");
|
|
8845
|
+
(0, import_node_fs23.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
8658
8846
|
return cfgPath;
|
|
8659
8847
|
}
|
|
8660
|
-
var
|
|
8848
|
+
var import_node_fs23, import_node_module, import_node_os9, import_node_path25, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
|
|
8661
8849
|
var init_injected_mcp = __esm({
|
|
8662
8850
|
"src/agents/injected-mcp.ts"() {
|
|
8663
8851
|
"use strict";
|
|
8664
|
-
|
|
8852
|
+
import_node_fs23 = require("fs");
|
|
8665
8853
|
import_node_module = require("module");
|
|
8666
|
-
|
|
8667
|
-
|
|
8854
|
+
import_node_os9 = require("os");
|
|
8855
|
+
import_node_path25 = require("path");
|
|
8668
8856
|
import_node_url = require("url");
|
|
8669
8857
|
init_run();
|
|
8670
8858
|
init_config();
|
|
@@ -9003,11 +9191,11 @@ function parseIssuesJson(raw) {
|
|
|
9003
9191
|
}
|
|
9004
9192
|
return [];
|
|
9005
9193
|
}
|
|
9006
|
-
var
|
|
9194
|
+
var import_node_fs24, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
|
|
9007
9195
|
var init_claude = __esm({
|
|
9008
9196
|
"src/agents/claude.ts"() {
|
|
9009
9197
|
"use strict";
|
|
9010
|
-
|
|
9198
|
+
import_node_fs24 = require("fs");
|
|
9011
9199
|
init_run();
|
|
9012
9200
|
init_app_settings();
|
|
9013
9201
|
init_claude_mcp();
|
|
@@ -9047,7 +9235,7 @@ var init_claude = __esm({
|
|
|
9047
9235
|
async detect() {
|
|
9048
9236
|
const claude = resolveClaudeExecutable();
|
|
9049
9237
|
if (claude !== "claude") {
|
|
9050
|
-
if (!(0,
|
|
9238
|
+
if (!(0, import_node_fs24.existsSync)(claude)) {
|
|
9051
9239
|
return {
|
|
9052
9240
|
agent: "claude",
|
|
9053
9241
|
installed: false,
|
|
@@ -9302,7 +9490,7 @@ async function listCodexModels() {
|
|
|
9302
9490
|
if (codex === "codex") {
|
|
9303
9491
|
const which = await run("which", ["codex"], { reject: false });
|
|
9304
9492
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
9305
|
-
} else if (!(0,
|
|
9493
|
+
} else if (!(0, import_node_fs25.existsSync)(codex)) {
|
|
9306
9494
|
return FALLBACK_CODEX_MODELS;
|
|
9307
9495
|
}
|
|
9308
9496
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -9337,12 +9525,12 @@ function usageFromCodex(usage) {
|
|
|
9337
9525
|
}
|
|
9338
9526
|
function codexConfigHasNetworkAccess() {
|
|
9339
9527
|
const candidates = [
|
|
9340
|
-
(0,
|
|
9341
|
-
(0,
|
|
9528
|
+
(0, import_node_path26.join)((0, import_node_os10.homedir)(), ".codex", "config.toml"),
|
|
9529
|
+
(0, import_node_path26.join)((0, import_node_os10.homedir)(), ".config", "codex", "config.toml")
|
|
9342
9530
|
];
|
|
9343
9531
|
for (const path of candidates) {
|
|
9344
|
-
if (!(0,
|
|
9345
|
-
const text5 = (0,
|
|
9532
|
+
if (!(0, import_node_fs25.existsSync)(path)) continue;
|
|
9533
|
+
const text5 = (0, import_node_fs25.readFileSync)(path, "utf8");
|
|
9346
9534
|
if (/network_access\s*=\s*true/.test(text5)) return true;
|
|
9347
9535
|
}
|
|
9348
9536
|
return false;
|
|
@@ -9374,21 +9562,21 @@ function asRecord2(value) {
|
|
|
9374
9562
|
return void 0;
|
|
9375
9563
|
}
|
|
9376
9564
|
function codexLooksAuthenticated() {
|
|
9377
|
-
const authPath = (0,
|
|
9378
|
-
if (!(0,
|
|
9565
|
+
const authPath = (0, import_node_path26.join)((0, import_node_os10.homedir)(), ".codex", "auth.json");
|
|
9566
|
+
if (!(0, import_node_fs25.existsSync)(authPath)) return false;
|
|
9379
9567
|
try {
|
|
9380
|
-
return (0,
|
|
9568
|
+
return (0, import_node_fs25.statSync)(authPath).size > 2;
|
|
9381
9569
|
} catch {
|
|
9382
9570
|
return false;
|
|
9383
9571
|
}
|
|
9384
9572
|
}
|
|
9385
|
-
var
|
|
9573
|
+
var import_node_fs25, import_node_os10, import_node_path26, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
9386
9574
|
var init_codex = __esm({
|
|
9387
9575
|
"src/agents/codex.ts"() {
|
|
9388
9576
|
"use strict";
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9577
|
+
import_node_fs25 = require("fs");
|
|
9578
|
+
import_node_os10 = require("os");
|
|
9579
|
+
import_node_path26 = require("path");
|
|
9392
9580
|
init_run();
|
|
9393
9581
|
init_app_settings();
|
|
9394
9582
|
init_global_workspace();
|
|
@@ -9413,7 +9601,7 @@ var init_codex = __esm({
|
|
|
9413
9601
|
async detect() {
|
|
9414
9602
|
const codex = resolveAgentExecutable("codex");
|
|
9415
9603
|
if (codex !== "codex") {
|
|
9416
|
-
if (!(0,
|
|
9604
|
+
if (!(0, import_node_fs25.existsSync)(codex)) {
|
|
9417
9605
|
return {
|
|
9418
9606
|
agent: "codex",
|
|
9419
9607
|
installed: false,
|
|
@@ -9900,21 +10088,21 @@ function platformRipgrepPackage() {
|
|
|
9900
10088
|
}
|
|
9901
10089
|
function usableRipgrepPath(candidate) {
|
|
9902
10090
|
const raw = candidate?.trim();
|
|
9903
|
-
if (!raw || !(0,
|
|
10091
|
+
if (!raw || !(0, import_node_path27.isAbsolute)(raw)) return null;
|
|
9904
10092
|
const readable = nodeReadableScriptPath(raw);
|
|
9905
|
-
if (!(0,
|
|
10093
|
+
if (!(0, import_node_fs26.existsSync)(readable) || isAsarPath(readable)) return null;
|
|
9906
10094
|
return readable;
|
|
9907
10095
|
}
|
|
9908
10096
|
function walkForBundledRipgrep(startFile) {
|
|
9909
10097
|
if (!startFile) return null;
|
|
9910
10098
|
const pkg = platformRipgrepPackage();
|
|
9911
10099
|
const name = rgBinaryName();
|
|
9912
|
-
let dir = (0,
|
|
9913
|
-
const root = (0,
|
|
10100
|
+
let dir = (0, import_node_path27.dirname)((0, import_node_path27.resolve)(startFile));
|
|
10101
|
+
const root = (0, import_node_path27.parse)(dir).root;
|
|
9914
10102
|
while (dir !== root) {
|
|
9915
|
-
const hit = usableRipgrepPath((0,
|
|
10103
|
+
const hit = usableRipgrepPath((0, import_node_path27.join)(dir, "node_modules", pkg, "bin", name));
|
|
9916
10104
|
if (hit) return hit;
|
|
9917
|
-
const next = (0,
|
|
10105
|
+
const next = (0, import_node_path27.dirname)(dir);
|
|
9918
10106
|
if (next === dir) break;
|
|
9919
10107
|
dir = next;
|
|
9920
10108
|
}
|
|
@@ -9924,7 +10112,7 @@ function requireResolveBundledRipgrep(fromFile) {
|
|
|
9924
10112
|
try {
|
|
9925
10113
|
const req = (0, import_node_module2.createRequire)(fromFile);
|
|
9926
10114
|
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
9927
|
-
return usableRipgrepPath((0,
|
|
10115
|
+
return usableRipgrepPath((0, import_node_path27.join)((0, import_node_path27.dirname)(pkgJson), "bin", rgBinaryName()));
|
|
9928
10116
|
} catch {
|
|
9929
10117
|
return null;
|
|
9930
10118
|
}
|
|
@@ -9946,13 +10134,13 @@ function cursorRipgrepEnv(opts) {
|
|
|
9946
10134
|
const path = resolveCursorRipgrepPath(opts);
|
|
9947
10135
|
return path ? { [RIPGREP_ENV]: path } : {};
|
|
9948
10136
|
}
|
|
9949
|
-
var
|
|
10137
|
+
var import_node_fs26, import_node_module2, import_node_path27, RIPGREP_ENV;
|
|
9950
10138
|
var init_cursor_ripgrep = __esm({
|
|
9951
10139
|
"src/agents/cursor-ripgrep.ts"() {
|
|
9952
10140
|
"use strict";
|
|
9953
|
-
|
|
10141
|
+
import_node_fs26 = require("fs");
|
|
9954
10142
|
import_node_module2 = require("module");
|
|
9955
|
-
|
|
10143
|
+
import_node_path27 = require("path");
|
|
9956
10144
|
init_node_launch();
|
|
9957
10145
|
init_packaged_runtime();
|
|
9958
10146
|
RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
@@ -9998,11 +10186,11 @@ function entryDir() {
|
|
|
9998
10186
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
9999
10187
|
if (cjsDir) return cjsDir;
|
|
10000
10188
|
try {
|
|
10001
|
-
return (0,
|
|
10189
|
+
return (0, import_node_path28.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
|
|
10002
10190
|
} catch {
|
|
10003
10191
|
try {
|
|
10004
10192
|
const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
|
|
10005
|
-
return (0,
|
|
10193
|
+
return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
|
|
10006
10194
|
} catch {
|
|
10007
10195
|
return process.cwd();
|
|
10008
10196
|
}
|
|
@@ -10013,27 +10201,27 @@ function cursorRunnerPath() {
|
|
|
10013
10201
|
if (packaged) return packaged;
|
|
10014
10202
|
const root = entryDir();
|
|
10015
10203
|
const candidates = [
|
|
10016
|
-
(0,
|
|
10017
|
-
(0,
|
|
10204
|
+
(0, import_node_path28.join)(root, "agents", "cursor-runner.js"),
|
|
10205
|
+
(0, import_node_path28.join)(root, "agents", "cursor-runner.cjs"),
|
|
10018
10206
|
// If somehow resolved from package root instead of dist/
|
|
10019
|
-
(0,
|
|
10020
|
-
(0,
|
|
10207
|
+
(0, import_node_path28.join)(root, "dist", "agents", "cursor-runner.js"),
|
|
10208
|
+
(0, import_node_path28.join)(root, "dist", "agents", "cursor-runner.cjs"),
|
|
10021
10209
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
10022
|
-
(0,
|
|
10023
|
-
(0,
|
|
10210
|
+
(0, import_node_path28.join)(root, "cursor-runner.ts"),
|
|
10211
|
+
(0, import_node_path28.join)(root, "src", "agents", "cursor-runner.ts")
|
|
10024
10212
|
];
|
|
10025
10213
|
for (const candidate of candidates) {
|
|
10026
|
-
if ((0,
|
|
10214
|
+
if ((0, import_node_fs27.existsSync)(candidate)) return candidate;
|
|
10027
10215
|
}
|
|
10028
10216
|
return candidates[0];
|
|
10029
10217
|
}
|
|
10030
|
-
var
|
|
10218
|
+
var import_node_fs27, import_node_module3, import_node_path28, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
|
|
10031
10219
|
var init_cursor = __esm({
|
|
10032
10220
|
"src/agents/cursor.ts"() {
|
|
10033
10221
|
"use strict";
|
|
10034
|
-
|
|
10222
|
+
import_node_fs27 = require("fs");
|
|
10035
10223
|
import_node_module3 = require("module");
|
|
10036
|
-
|
|
10224
|
+
import_node_path28 = require("path");
|
|
10037
10225
|
import_node_url2 = require("url");
|
|
10038
10226
|
import_sdk = require("@cursor/sdk");
|
|
10039
10227
|
init_run();
|
|
@@ -10184,7 +10372,7 @@ async function listOpencodeModels() {
|
|
|
10184
10372
|
if (opencode === "opencode") {
|
|
10185
10373
|
const which = await run("which", ["opencode"], { reject: false });
|
|
10186
10374
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
10187
|
-
} else if (!(0,
|
|
10375
|
+
} else if (!(0, import_node_fs28.existsSync)(opencode)) {
|
|
10188
10376
|
return FALLBACK_OPENCODE_MODELS;
|
|
10189
10377
|
}
|
|
10190
10378
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -10214,11 +10402,11 @@ function usageFromOpencode(tokens) {
|
|
|
10214
10402
|
cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
|
|
10215
10403
|
};
|
|
10216
10404
|
}
|
|
10217
|
-
var
|
|
10405
|
+
var import_node_fs28, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
|
|
10218
10406
|
var init_opencode = __esm({
|
|
10219
10407
|
"src/agents/opencode.ts"() {
|
|
10220
10408
|
"use strict";
|
|
10221
|
-
|
|
10409
|
+
import_node_fs28 = require("fs");
|
|
10222
10410
|
init_run();
|
|
10223
10411
|
init_app_settings();
|
|
10224
10412
|
init_global_workspace();
|
|
@@ -10245,7 +10433,7 @@ var init_opencode = __esm({
|
|
|
10245
10433
|
async detect() {
|
|
10246
10434
|
const opencode = resolveAgentExecutable("opencode");
|
|
10247
10435
|
if (opencode !== "opencode") {
|
|
10248
|
-
if (!(0,
|
|
10436
|
+
if (!(0, import_node_fs28.existsSync)(opencode)) {
|
|
10249
10437
|
return {
|
|
10250
10438
|
agent: "opencode",
|
|
10251
10439
|
installed: false,
|
|
@@ -11846,7 +12034,7 @@ function forkMessageSlice(from, throughIndex) {
|
|
|
11846
12034
|
function buildForkTranscriptAttachment(baseTitle, messages) {
|
|
11847
12035
|
const title = baseTitle || "Chat";
|
|
11848
12036
|
return {
|
|
11849
|
-
id: (0,
|
|
12037
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
11850
12038
|
name: `Transcript of ${title}.md`,
|
|
11851
12039
|
kind: "transcript",
|
|
11852
12040
|
content: formatTranscriptMarkdown(title, messages)
|
|
@@ -11903,11 +12091,11 @@ function forkChatTab(input) {
|
|
|
11903
12091
|
}
|
|
11904
12092
|
return tab;
|
|
11905
12093
|
}
|
|
11906
|
-
var
|
|
12094
|
+
var import_node_crypto6;
|
|
11907
12095
|
var init_chat_tabs = __esm({
|
|
11908
12096
|
"src/threads/chat-tabs.ts"() {
|
|
11909
12097
|
"use strict";
|
|
11910
|
-
|
|
12098
|
+
import_node_crypto6 = require("crypto");
|
|
11911
12099
|
init_context_compact();
|
|
11912
12100
|
init_teams();
|
|
11913
12101
|
init_worktree_labels();
|
|
@@ -12077,21 +12265,21 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
12077
12265
|
return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
|
|
12078
12266
|
}
|
|
12079
12267
|
function readTextIfPresent(abs) {
|
|
12080
|
-
if (!(0,
|
|
12268
|
+
if (!(0, import_node_fs29.existsSync)(abs)) return null;
|
|
12081
12269
|
try {
|
|
12082
|
-
const content = (0,
|
|
12270
|
+
const content = (0, import_node_fs29.readFileSync)(abs, "utf8");
|
|
12083
12271
|
return content.trim() ? content : null;
|
|
12084
12272
|
} catch {
|
|
12085
12273
|
return null;
|
|
12086
12274
|
}
|
|
12087
12275
|
}
|
|
12088
12276
|
function readLocalGuidelines(worktreePath) {
|
|
12089
|
-
const localAbs = (0,
|
|
12277
|
+
const localAbs = (0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
12090
12278
|
const localContent = readTextIfPresent(localAbs);
|
|
12091
12279
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
12092
12280
|
return { path: REVIEW_REQUEST_PATH, content: localContent };
|
|
12093
12281
|
}
|
|
12094
|
-
const legacyAbs = (0,
|
|
12282
|
+
const legacyAbs = (0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
12095
12283
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
12096
12284
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
12097
12285
|
return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
|
|
@@ -12107,20 +12295,20 @@ function skillGuidelines(content, source) {
|
|
|
12107
12295
|
};
|
|
12108
12296
|
}
|
|
12109
12297
|
function ensureReviewSkillFile(worktreePath) {
|
|
12110
|
-
const abs = (0,
|
|
12298
|
+
const abs = (0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH);
|
|
12111
12299
|
const existing = readTextIfPresent(abs);
|
|
12112
12300
|
if (existing) {
|
|
12113
12301
|
return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
|
|
12114
12302
|
}
|
|
12115
|
-
const fromRepo = readTextIfPresent((0,
|
|
12303
|
+
const fromRepo = readTextIfPresent((0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH));
|
|
12116
12304
|
const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
|
|
12117
12305
|
const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
|
|
12118
|
-
(0,
|
|
12119
|
-
(0,
|
|
12306
|
+
(0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(abs), { recursive: true });
|
|
12307
|
+
(0, import_node_fs29.writeFileSync)(abs, content, "utf8");
|
|
12120
12308
|
return { path: REVIEW_SKILL_PATH, content, wrote: true };
|
|
12121
12309
|
}
|
|
12122
12310
|
function resolveReviewGuidelines(worktreePath) {
|
|
12123
|
-
const skillContent = readTextIfPresent((0,
|
|
12311
|
+
const skillContent = readTextIfPresent((0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH));
|
|
12124
12312
|
if (skillContent) return skillGuidelines(skillContent, "skill");
|
|
12125
12313
|
const local = readLocalGuidelines(worktreePath);
|
|
12126
12314
|
if (local) {
|
|
@@ -12138,7 +12326,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
12138
12326
|
const path = opts?.path ?? REVIEW_SKILL_PATH;
|
|
12139
12327
|
const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
12140
12328
|
return {
|
|
12141
|
-
id: (0,
|
|
12329
|
+
id: (0, import_node_crypto7.randomUUID)(),
|
|
12142
12330
|
name,
|
|
12143
12331
|
kind: "file",
|
|
12144
12332
|
path,
|
|
@@ -12170,13 +12358,13 @@ async function requestReview(threadRef, send) {
|
|
|
12170
12358
|
const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
|
|
12171
12359
|
return { tab: started, from };
|
|
12172
12360
|
}
|
|
12173
|
-
var
|
|
12361
|
+
var import_node_crypto7, import_node_fs29, import_node_path29, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
|
|
12174
12362
|
var init_request_review = __esm({
|
|
12175
12363
|
"src/review/request-review.ts"() {
|
|
12176
12364
|
"use strict";
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12365
|
+
import_node_crypto7 = require("crypto");
|
|
12366
|
+
import_node_fs29 = require("fs");
|
|
12367
|
+
import_node_path29 = require("path");
|
|
12180
12368
|
init_global_workspace();
|
|
12181
12369
|
init_chat_tabs();
|
|
12182
12370
|
init_thread_store();
|
|
@@ -12201,9 +12389,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
12201
12389
|
return new RegExp(`^${escaped}$`).test(name);
|
|
12202
12390
|
}
|
|
12203
12391
|
function readWorktreeInclude(repoPath) {
|
|
12204
|
-
const path = (0,
|
|
12205
|
-
if (!(0,
|
|
12206
|
-
return (0,
|
|
12392
|
+
const path = (0, import_node_path30.join)(repoPath, ".worktreeinclude");
|
|
12393
|
+
if (!(0, import_node_fs30.existsSync)(path)) return [];
|
|
12394
|
+
return (0, import_node_fs30.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
12207
12395
|
}
|
|
12208
12396
|
function resolveFilesToCopy(repoPath) {
|
|
12209
12397
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -12213,10 +12401,10 @@ function resolveFilesToCopy(repoPath) {
|
|
|
12213
12401
|
if (settings?.fileIncludeGlobs?.length) {
|
|
12214
12402
|
const matched = [];
|
|
12215
12403
|
try {
|
|
12216
|
-
for (const entry of (0,
|
|
12404
|
+
for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
12217
12405
|
if (!entry.isFile()) continue;
|
|
12218
12406
|
for (const glob of settings.fileIncludeGlobs) {
|
|
12219
|
-
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0,
|
|
12407
|
+
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path30.basename)(glob), entry.name)) {
|
|
12220
12408
|
matched.push(entry.name);
|
|
12221
12409
|
break;
|
|
12222
12410
|
}
|
|
@@ -12228,7 +12416,7 @@ function resolveFilesToCopy(repoPath) {
|
|
|
12228
12416
|
}
|
|
12229
12417
|
const defaults = [];
|
|
12230
12418
|
try {
|
|
12231
|
-
for (const entry of (0,
|
|
12419
|
+
for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
12232
12420
|
if (entry.isFile() && entry.name.startsWith(".env")) {
|
|
12233
12421
|
defaults.push(entry.name);
|
|
12234
12422
|
}
|
|
@@ -12242,11 +12430,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
|
|
|
12242
12430
|
const patterns = resolveFilesToCopy(repoPath);
|
|
12243
12431
|
const copied = [];
|
|
12244
12432
|
for (const rel of patterns) {
|
|
12245
|
-
const src = (0,
|
|
12246
|
-
if (!(0,
|
|
12247
|
-
const dest = (0,
|
|
12248
|
-
(0,
|
|
12249
|
-
(0,
|
|
12433
|
+
const src = (0, import_node_path30.join)(repoPath, rel);
|
|
12434
|
+
if (!(0, import_node_fs30.existsSync)(src)) continue;
|
|
12435
|
+
const dest = (0, import_node_path30.join)(worktreePath, rel);
|
|
12436
|
+
(0, import_node_fs30.mkdirSync)((0, import_node_path30.dirname)(dest), { recursive: true });
|
|
12437
|
+
(0, import_node_fs30.copyFileSync)(src, dest);
|
|
12250
12438
|
copied.push(rel);
|
|
12251
12439
|
}
|
|
12252
12440
|
return copied;
|
|
@@ -12281,7 +12469,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
|
12281
12469
|
const env = stripNestedElectronEnv({
|
|
12282
12470
|
...baseEnv ?? process.env
|
|
12283
12471
|
});
|
|
12284
|
-
const name = opts.workspaceName ?? (0,
|
|
12472
|
+
const name = opts.workspaceName ?? (0, import_node_path30.basename)(opts.worktreePath);
|
|
12285
12473
|
const ports = opts.ports ?? [];
|
|
12286
12474
|
const primary = ports[0];
|
|
12287
12475
|
env.SIDEBOARD_WORKSPACE_NAME = name;
|
|
@@ -12436,6 +12624,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
|
|
|
12436
12624
|
};
|
|
12437
12625
|
}
|
|
12438
12626
|
async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
|
|
12627
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
12439
12628
|
const reviewSkill = ensureReviewSkillFile(worktreePath);
|
|
12440
12629
|
if (reviewSkill.wrote) {
|
|
12441
12630
|
onLine?.(
|
|
@@ -12542,13 +12731,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
|
|
|
12542
12731
|
done: handle.done
|
|
12543
12732
|
};
|
|
12544
12733
|
}
|
|
12545
|
-
var
|
|
12734
|
+
var import_node_fs30, import_node_net, import_node_path30, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
|
|
12546
12735
|
var init_conductor = __esm({
|
|
12547
12736
|
"src/hook/conductor.ts"() {
|
|
12548
12737
|
"use strict";
|
|
12549
|
-
|
|
12738
|
+
import_node_fs30 = require("fs");
|
|
12550
12739
|
import_node_net = require("net");
|
|
12551
|
-
|
|
12740
|
+
import_node_path30 = require("path");
|
|
12552
12741
|
import_execa4 = require("execa");
|
|
12553
12742
|
import_node_readline3 = require("readline");
|
|
12554
12743
|
init_settings();
|
|
@@ -12557,6 +12746,7 @@ var init_conductor = __esm({
|
|
|
12557
12746
|
init_cursor_worktrees();
|
|
12558
12747
|
init_git_auth_mode();
|
|
12559
12748
|
init_request_review();
|
|
12749
|
+
init_worktree_exclude();
|
|
12560
12750
|
init_nested_electron_env();
|
|
12561
12751
|
PORT_RANGE_SIZE = 10;
|
|
12562
12752
|
cachedLoginEnv = null;
|
|
@@ -12574,9 +12764,9 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
12574
12764
|
repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
|
|
12575
12765
|
);
|
|
12576
12766
|
const homeRoot = sideboardWorkspacesDir();
|
|
12577
|
-
if ((0,
|
|
12767
|
+
if ((0, import_node_fs31.existsSync)(homeRoot)) {
|
|
12578
12768
|
try {
|
|
12579
|
-
for (const entry of (0,
|
|
12769
|
+
for (const entry of (0, import_node_fs31.readdirSync)(homeRoot, { withFileTypes: true })) {
|
|
12580
12770
|
if (!entry.isDirectory()) continue;
|
|
12581
12771
|
void entry;
|
|
12582
12772
|
}
|
|
@@ -12586,7 +12776,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
12586
12776
|
const orphans = [];
|
|
12587
12777
|
const seen = /* @__PURE__ */ new Set();
|
|
12588
12778
|
for (const repoPath of repos) {
|
|
12589
|
-
if (!repoPath || !(0,
|
|
12779
|
+
if (!repoPath || !(0, import_node_fs31.existsSync)(repoPath)) continue;
|
|
12590
12780
|
try {
|
|
12591
12781
|
const wts = await listWorktrees(repoPath);
|
|
12592
12782
|
for (const wt of wts) {
|
|
@@ -12597,7 +12787,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
12597
12787
|
seen.add(path);
|
|
12598
12788
|
let mtimeMs = 0;
|
|
12599
12789
|
try {
|
|
12600
|
-
mtimeMs = (0,
|
|
12790
|
+
mtimeMs = (0, import_node_fs31.statSync)(path).mtimeMs;
|
|
12601
12791
|
} catch {
|
|
12602
12792
|
mtimeMs = 0;
|
|
12603
12793
|
}
|
|
@@ -12607,16 +12797,16 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
12607
12797
|
}
|
|
12608
12798
|
try {
|
|
12609
12799
|
const root = worktreesRoot(repoPath);
|
|
12610
|
-
if ((0,
|
|
12611
|
-
for (const entry of (0,
|
|
12800
|
+
if ((0, import_node_fs31.existsSync)(root)) {
|
|
12801
|
+
for (const entry of (0, import_node_fs31.readdirSync)(root, { withFileTypes: true })) {
|
|
12612
12802
|
if (!entry.isDirectory()) continue;
|
|
12613
|
-
const path = (0,
|
|
12803
|
+
const path = (0, import_node_path31.join)(root, entry.name).replace(/\/$/, "");
|
|
12614
12804
|
if (known.has(path) || seen.has(path)) continue;
|
|
12615
|
-
if (!(0,
|
|
12805
|
+
if (!(0, import_node_fs31.existsSync)((0, import_node_path31.join)(path, ".git"))) continue;
|
|
12616
12806
|
seen.add(path);
|
|
12617
12807
|
let mtimeMs = 0;
|
|
12618
12808
|
try {
|
|
12619
|
-
mtimeMs = (0,
|
|
12809
|
+
mtimeMs = (0, import_node_fs31.statSync)(path).mtimeMs;
|
|
12620
12810
|
} catch {
|
|
12621
12811
|
mtimeMs = Date.now();
|
|
12622
12812
|
}
|
|
@@ -12668,12 +12858,12 @@ function shouldRunWorktreeCleanup(settings = loadAppSettings()) {
|
|
|
12668
12858
|
const elapsed = Date.now() - Date.parse(last);
|
|
12669
12859
|
return elapsed >= intervalHours * 36e5;
|
|
12670
12860
|
}
|
|
12671
|
-
var
|
|
12861
|
+
var import_node_fs31, import_node_path31;
|
|
12672
12862
|
var init_orphan_cleanup = __esm({
|
|
12673
12863
|
"src/git/orphan-cleanup.ts"() {
|
|
12674
12864
|
"use strict";
|
|
12675
|
-
|
|
12676
|
-
|
|
12865
|
+
import_node_fs31 = require("fs");
|
|
12866
|
+
import_node_path31 = require("path");
|
|
12677
12867
|
init_worktree();
|
|
12678
12868
|
init_thread_store();
|
|
12679
12869
|
init_paths();
|
|
@@ -12780,38 +12970,38 @@ __export(workspaces_exports, {
|
|
|
12780
12970
|
syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
|
|
12781
12971
|
});
|
|
12782
12972
|
function workspacesFile() {
|
|
12783
|
-
return (0,
|
|
12973
|
+
return (0, import_node_path32.join)(appDataDir(), "workspaces.json");
|
|
12784
12974
|
}
|
|
12785
12975
|
function removedWorkspacesFile() {
|
|
12786
|
-
return (0,
|
|
12976
|
+
return (0, import_node_path32.join)(appDataDir(), "removed-workspaces.json");
|
|
12787
12977
|
}
|
|
12788
12978
|
function readAll() {
|
|
12789
12979
|
const path = workspacesFile();
|
|
12790
|
-
if (!(0,
|
|
12980
|
+
if (!(0, import_node_fs32.existsSync)(path)) return [];
|
|
12791
12981
|
try {
|
|
12792
|
-
const raw = JSON.parse((0,
|
|
12982
|
+
const raw = JSON.parse((0, import_node_fs32.readFileSync)(path, "utf8"));
|
|
12793
12983
|
return Array.isArray(raw) ? raw : [];
|
|
12794
12984
|
} catch {
|
|
12795
12985
|
return [];
|
|
12796
12986
|
}
|
|
12797
12987
|
}
|
|
12798
12988
|
function writeAll(list) {
|
|
12799
|
-
(0,
|
|
12800
|
-
(0,
|
|
12989
|
+
(0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
|
|
12990
|
+
(0, import_node_fs32.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
|
|
12801
12991
|
}
|
|
12802
12992
|
function readRemoved() {
|
|
12803
12993
|
const path = removedWorkspacesFile();
|
|
12804
|
-
if (!(0,
|
|
12994
|
+
if (!(0, import_node_fs32.existsSync)(path)) return /* @__PURE__ */ new Set();
|
|
12805
12995
|
try {
|
|
12806
|
-
const raw = JSON.parse((0,
|
|
12996
|
+
const raw = JSON.parse((0, import_node_fs32.readFileSync)(path, "utf8"));
|
|
12807
12997
|
return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
|
|
12808
12998
|
} catch {
|
|
12809
12999
|
return /* @__PURE__ */ new Set();
|
|
12810
13000
|
}
|
|
12811
13001
|
}
|
|
12812
13002
|
function writeRemoved(paths) {
|
|
12813
|
-
(0,
|
|
12814
|
-
(0,
|
|
13003
|
+
(0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
|
|
13004
|
+
(0, import_node_fs32.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
|
|
12815
13005
|
}
|
|
12816
13006
|
function rememberRemoved(repoPath) {
|
|
12817
13007
|
const next = readRemoved();
|
|
@@ -12834,7 +13024,7 @@ function listWorkspaces() {
|
|
|
12834
13024
|
async function addWorkspace(repoPath) {
|
|
12835
13025
|
const root = await resolveRepoRoot(repoPath);
|
|
12836
13026
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
12837
|
-
if (!(0,
|
|
13027
|
+
if (!(0, import_node_fs32.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
|
|
12838
13028
|
forgetRemoved(root);
|
|
12839
13029
|
await ensureGhPreferOrigin(root);
|
|
12840
13030
|
const current = readAll();
|
|
@@ -12842,7 +13032,7 @@ async function addWorkspace(repoPath) {
|
|
|
12842
13032
|
if (existing) return existing;
|
|
12843
13033
|
const next = {
|
|
12844
13034
|
path: root,
|
|
12845
|
-
name: (0,
|
|
13035
|
+
name: (0, import_node_path32.basename)(root),
|
|
12846
13036
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12847
13037
|
};
|
|
12848
13038
|
writeAll([...current, next]);
|
|
@@ -12864,10 +13054,10 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
12864
13054
|
if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
|
|
12865
13055
|
continue;
|
|
12866
13056
|
}
|
|
12867
|
-
if (!(0,
|
|
13057
|
+
if (!(0, import_node_fs32.existsSync)(path)) continue;
|
|
12868
13058
|
const ws = {
|
|
12869
13059
|
path,
|
|
12870
|
-
name: (0,
|
|
13060
|
+
name: (0, import_node_path32.basename)(path),
|
|
12871
13061
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12872
13062
|
};
|
|
12873
13063
|
byPath.set(path, ws);
|
|
@@ -12877,12 +13067,12 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
12877
13067
|
if (dirty) writeAll(next);
|
|
12878
13068
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
12879
13069
|
}
|
|
12880
|
-
var
|
|
13070
|
+
var import_node_fs32, import_node_path32;
|
|
12881
13071
|
var init_workspaces2 = __esm({
|
|
12882
13072
|
"src/store/workspaces.ts"() {
|
|
12883
13073
|
"use strict";
|
|
12884
|
-
|
|
12885
|
-
|
|
13074
|
+
import_node_fs32 = require("fs");
|
|
13075
|
+
import_node_path32 = require("path");
|
|
12886
13076
|
init_paths();
|
|
12887
13077
|
init_global_workspace();
|
|
12888
13078
|
init_worktree();
|
|
@@ -12895,12 +13085,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
12895
13085
|
if (!url) throw new Error("Clone URL is required");
|
|
12896
13086
|
let name = opts.name?.trim();
|
|
12897
13087
|
if (!name) {
|
|
12898
|
-
const leaf = (0,
|
|
13088
|
+
const leaf = (0, import_node_path33.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
|
|
12899
13089
|
name = leaf || "repo";
|
|
12900
13090
|
}
|
|
12901
13091
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
12902
|
-
const dest = (0,
|
|
12903
|
-
if ((0,
|
|
13092
|
+
const dest = (0, import_node_path33.join)(sideboardReposDir(), name);
|
|
13093
|
+
if ((0, import_node_fs33.existsSync)(dest)) {
|
|
12904
13094
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
12905
13095
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
12906
13096
|
return { repoPath: repoPath2, workspace: workspace2 };
|
|
@@ -12915,12 +13105,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
12915
13105
|
const workspace = await ensureWorkspace(repoPath);
|
|
12916
13106
|
return { repoPath, workspace };
|
|
12917
13107
|
}
|
|
12918
|
-
var
|
|
13108
|
+
var import_node_fs33, import_node_path33, import_execa6;
|
|
12919
13109
|
var init_clone_repo = __esm({
|
|
12920
13110
|
"src/git/clone-repo.ts"() {
|
|
12921
13111
|
"use strict";
|
|
12922
|
-
|
|
12923
|
-
|
|
13112
|
+
import_node_fs33 = require("fs");
|
|
13113
|
+
import_node_path33 = require("path");
|
|
12924
13114
|
import_execa6 = require("execa");
|
|
12925
13115
|
init_paths();
|
|
12926
13116
|
init_workspaces2();
|
|
@@ -12930,11 +13120,11 @@ var init_clone_repo = __esm({
|
|
|
12930
13120
|
|
|
12931
13121
|
// src/store/desktop-host.ts
|
|
12932
13122
|
function desktopHostPidPath() {
|
|
12933
|
-
return (0,
|
|
13123
|
+
return (0, import_node_path34.join)(appDataDir(), "desktop-host.pid");
|
|
12934
13124
|
}
|
|
12935
13125
|
function readDesktopHostPid() {
|
|
12936
13126
|
try {
|
|
12937
|
-
const pid = Number.parseInt((0,
|
|
13127
|
+
const pid = Number.parseInt((0, import_node_fs34.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
|
|
12938
13128
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
12939
13129
|
return pid;
|
|
12940
13130
|
} catch {
|
|
@@ -12960,12 +13150,12 @@ function thisProcessShouldDrainAgentQueues() {
|
|
|
12960
13150
|
if (isThisProcessDesktopHost()) return true;
|
|
12961
13151
|
return !isDesktopHostAlive();
|
|
12962
13152
|
}
|
|
12963
|
-
var
|
|
13153
|
+
var import_node_fs34, import_node_path34;
|
|
12964
13154
|
var init_desktop_host = __esm({
|
|
12965
13155
|
"src/store/desktop-host.ts"() {
|
|
12966
13156
|
"use strict";
|
|
12967
|
-
|
|
12968
|
-
|
|
13157
|
+
import_node_fs34 = require("fs");
|
|
13158
|
+
import_node_path34 = require("path");
|
|
12969
13159
|
init_paths();
|
|
12970
13160
|
}
|
|
12971
13161
|
});
|
|
@@ -13967,7 +14157,7 @@ function persistCreateAttachments(worktreePath, attachments) {
|
|
|
13967
14157
|
}
|
|
13968
14158
|
async function createThread(input, _onSetupLine) {
|
|
13969
14159
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
13970
|
-
if (!(0,
|
|
14160
|
+
if (!(0, import_node_fs35.existsSync)(repoPath)) {
|
|
13971
14161
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
13972
14162
|
}
|
|
13973
14163
|
if (input.reuseExisting !== false) {
|
|
@@ -14142,11 +14332,11 @@ async function listLinearIssues(agent, repoPath) {
|
|
|
14142
14332
|
}
|
|
14143
14333
|
return adapter.listLinearIssues(repoPath);
|
|
14144
14334
|
}
|
|
14145
|
-
var
|
|
14335
|
+
var import_node_fs35;
|
|
14146
14336
|
var init_create = __esm({
|
|
14147
14337
|
"src/threads/create.ts"() {
|
|
14148
14338
|
"use strict";
|
|
14149
|
-
|
|
14339
|
+
import_node_fs35 = require("fs");
|
|
14150
14340
|
init_detect();
|
|
14151
14341
|
init_worktree();
|
|
14152
14342
|
init_home_board();
|
|
@@ -14249,20 +14439,20 @@ function writeTurnLive(threadId, progress) {
|
|
|
14249
14439
|
const path = threadLivePath(threadId);
|
|
14250
14440
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
14251
14441
|
try {
|
|
14252
|
-
(0,
|
|
14253
|
-
(0,
|
|
14442
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
|
|
14443
|
+
(0, import_node_fs36.renameSync)(tmp, path);
|
|
14254
14444
|
} catch {
|
|
14255
14445
|
try {
|
|
14256
|
-
(0,
|
|
14446
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
14257
14447
|
} catch {
|
|
14258
14448
|
}
|
|
14259
14449
|
}
|
|
14260
14450
|
}
|
|
14261
14451
|
function readTurnLive(threadId) {
|
|
14262
14452
|
const path = threadLivePath(threadId);
|
|
14263
|
-
if (!(0,
|
|
14453
|
+
if (!(0, import_node_fs36.existsSync)(path)) return null;
|
|
14264
14454
|
try {
|
|
14265
|
-
const raw = JSON.parse((0,
|
|
14455
|
+
const raw = JSON.parse((0, import_node_fs36.readFileSync)(path, "utf8"));
|
|
14266
14456
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
14267
14457
|
return raw;
|
|
14268
14458
|
} catch {
|
|
@@ -14274,17 +14464,17 @@ function clearTurnLive(threadId) {
|
|
|
14274
14464
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
14275
14465
|
buffers.delete(threadId);
|
|
14276
14466
|
const path = threadLivePath(threadId);
|
|
14277
|
-
if (!(0,
|
|
14467
|
+
if (!(0, import_node_fs36.existsSync)(path)) return;
|
|
14278
14468
|
try {
|
|
14279
|
-
(0,
|
|
14469
|
+
(0, import_node_fs36.unlinkSync)(path);
|
|
14280
14470
|
} catch {
|
|
14281
14471
|
}
|
|
14282
14472
|
}
|
|
14283
|
-
var
|
|
14473
|
+
var import_node_fs36, buffers, FLUSH_MS, MAX_PARTS;
|
|
14284
14474
|
var init_turn_live = __esm({
|
|
14285
14475
|
"src/store/turn-live.ts"() {
|
|
14286
14476
|
"use strict";
|
|
14287
|
-
|
|
14477
|
+
import_node_fs36 = require("fs");
|
|
14288
14478
|
init_message_parts();
|
|
14289
14479
|
init_paths();
|
|
14290
14480
|
buffers = /* @__PURE__ */ new Map();
|
|
@@ -14458,7 +14648,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
14458
14648
|
`- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
|
|
14459
14649
|
].join("\n");
|
|
14460
14650
|
return {
|
|
14461
|
-
id: (0,
|
|
14651
|
+
id: (0, import_node_crypto8.randomUUID)(),
|
|
14462
14652
|
name: "Orchestration quota handoff.md",
|
|
14463
14653
|
kind: "transcript",
|
|
14464
14654
|
content: body
|
|
@@ -14479,11 +14669,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
14479
14669
|
sourceType: "orchestration"
|
|
14480
14670
|
});
|
|
14481
14671
|
}
|
|
14482
|
-
var
|
|
14672
|
+
var import_node_crypto8, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
|
|
14483
14673
|
var init_quota_failover = __esm({
|
|
14484
14674
|
"src/orchestrator/quota-failover.ts"() {
|
|
14485
14675
|
"use strict";
|
|
14486
|
-
|
|
14676
|
+
import_node_crypto8 = require("crypto");
|
|
14487
14677
|
init_session_quota();
|
|
14488
14678
|
init_app_settings();
|
|
14489
14679
|
init_global_workspace();
|
|
@@ -14500,7 +14690,7 @@ var init_quota_failover = __esm({
|
|
|
14500
14690
|
// src/threads/adopt.ts
|
|
14501
14691
|
function thisModuleFile() {
|
|
14502
14692
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
14503
|
-
return cjsFile || process.argv[1] || (0,
|
|
14693
|
+
return cjsFile || process.argv[1] || (0, import_node_path35.join)(process.cwd(), "package.json");
|
|
14504
14694
|
}
|
|
14505
14695
|
function openReadonlySqlite(file) {
|
|
14506
14696
|
const req = (0, import_node_module4.createRequire)(thisModuleFile());
|
|
@@ -14518,21 +14708,21 @@ function mapAgentType(raw) {
|
|
|
14518
14708
|
return null;
|
|
14519
14709
|
}
|
|
14520
14710
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
14521
|
-
if (!workspacePath || !(0,
|
|
14711
|
+
if (!workspacePath || !(0, import_node_fs37.existsSync)(CURSOR_SDK_STORE)) return null;
|
|
14522
14712
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
14523
14713
|
let best = null;
|
|
14524
14714
|
let hashes;
|
|
14525
14715
|
try {
|
|
14526
|
-
hashes = (0,
|
|
14716
|
+
hashes = (0, import_node_fs37.readdirSync)(CURSOR_SDK_STORE);
|
|
14527
14717
|
} catch {
|
|
14528
14718
|
return null;
|
|
14529
14719
|
}
|
|
14530
14720
|
for (const hash of hashes) {
|
|
14531
|
-
const agentsFile = (0,
|
|
14532
|
-
if (!(0,
|
|
14721
|
+
const agentsFile = (0, import_node_path35.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
14722
|
+
if (!(0, import_node_fs37.existsSync)(agentsFile)) continue;
|
|
14533
14723
|
let text5;
|
|
14534
14724
|
try {
|
|
14535
|
-
text5 = (0,
|
|
14725
|
+
text5 = (0, import_node_fs37.readFileSync)(agentsFile, "utf8");
|
|
14536
14726
|
} catch {
|
|
14537
14727
|
continue;
|
|
14538
14728
|
}
|
|
@@ -14556,7 +14746,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
14556
14746
|
return best?.agentId ?? null;
|
|
14557
14747
|
}
|
|
14558
14748
|
async function adoptThread(input) {
|
|
14559
|
-
if (!(0,
|
|
14749
|
+
if (!(0, import_node_fs37.existsSync)(input.worktreePath)) {
|
|
14560
14750
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
14561
14751
|
}
|
|
14562
14752
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -14577,21 +14767,23 @@ async function adoptThread(input) {
|
|
|
14577
14767
|
writeThread(thread);
|
|
14578
14768
|
const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
|
|
14579
14769
|
await ensureWorkspace2(repoPath);
|
|
14770
|
+
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
|
|
14771
|
+
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
14580
14772
|
return thread;
|
|
14581
14773
|
}
|
|
14582
14774
|
function listConductorWorkspaces() {
|
|
14583
|
-
if (!(0,
|
|
14775
|
+
if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
|
|
14584
14776
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
14585
14777
|
}
|
|
14586
|
-
const tmp = (0,
|
|
14587
|
-
const snapshot = (0,
|
|
14778
|
+
const tmp = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
|
|
14779
|
+
const snapshot = (0, import_node_path35.join)(tmp, "conductor.db");
|
|
14588
14780
|
try {
|
|
14589
|
-
(0,
|
|
14781
|
+
(0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
14590
14782
|
for (const suffix of ["-wal", "-shm"]) {
|
|
14591
14783
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
14592
|
-
if ((0,
|
|
14784
|
+
if ((0, import_node_fs37.existsSync)(src)) {
|
|
14593
14785
|
try {
|
|
14594
|
-
(0,
|
|
14786
|
+
(0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
14595
14787
|
} catch {
|
|
14596
14788
|
}
|
|
14597
14789
|
}
|
|
@@ -14667,22 +14859,22 @@ function listConductorWorkspaces() {
|
|
|
14667
14859
|
db.close();
|
|
14668
14860
|
}
|
|
14669
14861
|
} finally {
|
|
14670
|
-
(0,
|
|
14862
|
+
(0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
|
|
14671
14863
|
}
|
|
14672
14864
|
}
|
|
14673
14865
|
function importConductorWorkspace(workspaceId) {
|
|
14674
|
-
if (!(0,
|
|
14866
|
+
if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
|
|
14675
14867
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
14676
14868
|
}
|
|
14677
|
-
const tmp = (0,
|
|
14678
|
-
const snapshot = (0,
|
|
14869
|
+
const tmp = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
|
|
14870
|
+
const snapshot = (0, import_node_path35.join)(tmp, "conductor.db");
|
|
14679
14871
|
try {
|
|
14680
|
-
(0,
|
|
14872
|
+
(0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
14681
14873
|
for (const suffix of ["-wal", "-shm"]) {
|
|
14682
14874
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
14683
|
-
if ((0,
|
|
14875
|
+
if ((0, import_node_fs37.existsSync)(src)) {
|
|
14684
14876
|
try {
|
|
14685
|
-
(0,
|
|
14877
|
+
(0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
14686
14878
|
} catch {
|
|
14687
14879
|
}
|
|
14688
14880
|
}
|
|
@@ -14700,7 +14892,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
14700
14892
|
).get(workspaceId);
|
|
14701
14893
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
14702
14894
|
const worktreePath = String(row.workspacePath);
|
|
14703
|
-
if (!(0,
|
|
14895
|
+
if (!(0, import_node_fs37.existsSync)(worktreePath)) {
|
|
14704
14896
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
14705
14897
|
}
|
|
14706
14898
|
let sessionId = null;
|
|
@@ -14763,31 +14955,31 @@ function importConductorWorkspace(workspaceId) {
|
|
|
14763
14955
|
db.close();
|
|
14764
14956
|
}
|
|
14765
14957
|
} finally {
|
|
14766
|
-
(0,
|
|
14958
|
+
(0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
|
|
14767
14959
|
}
|
|
14768
14960
|
}
|
|
14769
14961
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
14770
14962
|
return importConductorWorkspace(workspaceId);
|
|
14771
14963
|
}
|
|
14772
|
-
var import_node_child_process3,
|
|
14964
|
+
var import_node_child_process3, import_node_fs37, import_node_os11, import_node_path35, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
|
|
14773
14965
|
var init_adopt = __esm({
|
|
14774
14966
|
"src/threads/adopt.ts"() {
|
|
14775
14967
|
"use strict";
|
|
14776
14968
|
import_node_child_process3 = require("child_process");
|
|
14777
|
-
|
|
14778
|
-
|
|
14779
|
-
|
|
14969
|
+
import_node_fs37 = require("fs");
|
|
14970
|
+
import_node_os11 = require("os");
|
|
14971
|
+
import_node_path35 = require("path");
|
|
14780
14972
|
import_node_module4 = require("module");
|
|
14781
14973
|
init_worktree();
|
|
14782
14974
|
init_thread_store();
|
|
14783
|
-
CONDUCTOR_APP_SUPPORT = (0,
|
|
14975
|
+
CONDUCTOR_APP_SUPPORT = (0, import_node_path35.join)(
|
|
14784
14976
|
process.env.HOME ?? "",
|
|
14785
14977
|
"Library",
|
|
14786
14978
|
"Application Support",
|
|
14787
14979
|
"com.conductor.app"
|
|
14788
14980
|
);
|
|
14789
|
-
CONDUCTOR_DB = (0,
|
|
14790
|
-
CURSOR_SDK_STORE = (0,
|
|
14981
|
+
CONDUCTOR_DB = (0, import_node_path35.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
14982
|
+
CURSOR_SDK_STORE = (0, import_node_path35.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
14791
14983
|
}
|
|
14792
14984
|
});
|
|
14793
14985
|
|
|
@@ -14854,7 +15046,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
14854
15046
|
let createdWorktree = false;
|
|
14855
15047
|
const trees = await listWorktrees(repoPath);
|
|
14856
15048
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
14857
|
-
if (checkedOut?.path && (0,
|
|
15049
|
+
if (checkedOut?.path && (0, import_node_fs38.existsSync)(checkedOut.path)) {
|
|
14858
15050
|
if (input.reuseExistingWorktree !== false) {
|
|
14859
15051
|
worktreePath = checkedOut.path;
|
|
14860
15052
|
} else {
|
|
@@ -14996,7 +15188,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
14996
15188
|
async function createPrStack(input, onSetupLine) {
|
|
14997
15189
|
await requireAgent(input.agent);
|
|
14998
15190
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
14999
|
-
if (!(0,
|
|
15191
|
+
if (!(0, import_node_fs38.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
15000
15192
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
15001
15193
|
const status = await detectGhStack(repoPath);
|
|
15002
15194
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -15063,7 +15255,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
15063
15255
|
}
|
|
15064
15256
|
}
|
|
15065
15257
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
15066
|
-
if (!claimed.has(bootstrap.worktreePath) && (0,
|
|
15258
|
+
if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs38.existsSync)(bootstrap.worktreePath)) {
|
|
15067
15259
|
try {
|
|
15068
15260
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
15069
15261
|
deleteBranch: bootstrap.branchName
|
|
@@ -15073,11 +15265,11 @@ async function createPrStack(input, onSetupLine) {
|
|
|
15073
15265
|
}
|
|
15074
15266
|
return { stack, threads, createdThreadIds };
|
|
15075
15267
|
}
|
|
15076
|
-
var
|
|
15268
|
+
var import_node_fs38;
|
|
15077
15269
|
var init_stack_layers = __esm({
|
|
15078
15270
|
"src/threads/stack-layers.ts"() {
|
|
15079
15271
|
"use strict";
|
|
15080
|
-
|
|
15272
|
+
import_node_fs38 = require("fs");
|
|
15081
15273
|
init_detect();
|
|
15082
15274
|
init_run();
|
|
15083
15275
|
init_stack();
|
|
@@ -15090,7 +15282,7 @@ var init_stack_layers = __esm({
|
|
|
15090
15282
|
|
|
15091
15283
|
// src/diff/diff.ts
|
|
15092
15284
|
async function inspectGitWorktree(worktreePath) {
|
|
15093
|
-
if (!worktreePath || !(0,
|
|
15285
|
+
if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) return "missing_worktree";
|
|
15094
15286
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
15095
15287
|
reject: false
|
|
15096
15288
|
});
|
|
@@ -15098,7 +15290,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
15098
15290
|
return "ok";
|
|
15099
15291
|
}
|
|
15100
15292
|
async function initializeGitRepository(worktreePath) {
|
|
15101
|
-
if (!worktreePath || !(0,
|
|
15293
|
+
if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) {
|
|
15102
15294
|
throw new Error("Worktree not found");
|
|
15103
15295
|
}
|
|
15104
15296
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -15232,11 +15424,11 @@ new file mode 100644
|
|
|
15232
15424
|
};
|
|
15233
15425
|
}
|
|
15234
15426
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
15235
|
-
const abs = (0,
|
|
15427
|
+
const abs = (0, import_node_path36.join)(worktreePath, path);
|
|
15236
15428
|
try {
|
|
15237
|
-
const st = (0,
|
|
15429
|
+
const st = (0, import_node_fs39.statSync)(abs);
|
|
15238
15430
|
if (st.isFile() && st.size > maxHunk) {
|
|
15239
|
-
const buf = (0,
|
|
15431
|
+
const buf = (0, import_node_fs39.readFileSync)(abs).subarray(0, maxHunk);
|
|
15240
15432
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
15241
15433
|
}
|
|
15242
15434
|
} catch {
|
|
@@ -15725,8 +15917,8 @@ function isImageRelativePath(relativePath) {
|
|
|
15725
15917
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
15726
15918
|
assertSafeRelativePath(relativePath);
|
|
15727
15919
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
15728
|
-
const abs = (0,
|
|
15729
|
-
const st = (0,
|
|
15920
|
+
const abs = (0, import_node_path36.join)(worktreePath, relativePath);
|
|
15921
|
+
const st = (0, import_node_fs39.statSync)(abs);
|
|
15730
15922
|
if (!st.isFile()) {
|
|
15731
15923
|
throw new Error(`Not a file: ${relativePath}`);
|
|
15732
15924
|
}
|
|
@@ -15735,7 +15927,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
15735
15927
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
15736
15928
|
);
|
|
15737
15929
|
}
|
|
15738
|
-
const buf = (0,
|
|
15930
|
+
const buf = (0, import_node_fs39.readFileSync)(abs);
|
|
15739
15931
|
return {
|
|
15740
15932
|
path: relativePath,
|
|
15741
15933
|
contentBase64: buf.toString("base64"),
|
|
@@ -15745,12 +15937,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
15745
15937
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
15746
15938
|
assertSafeRelativePath(relativePath);
|
|
15747
15939
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
15748
|
-
const abs = (0,
|
|
15749
|
-
const st = (0,
|
|
15940
|
+
const abs = (0, import_node_path36.join)(worktreePath, relativePath);
|
|
15941
|
+
const st = (0, import_node_fs39.statSync)(abs);
|
|
15750
15942
|
if (!st.isFile()) {
|
|
15751
15943
|
throw new Error(`Not a file: ${relativePath}`);
|
|
15752
15944
|
}
|
|
15753
|
-
const buf = (0,
|
|
15945
|
+
const buf = (0, import_node_fs39.readFileSync)(abs);
|
|
15754
15946
|
if (isImageRelativePath(relativePath)) {
|
|
15755
15947
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
15756
15948
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -15793,9 +15985,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
15793
15985
|
}
|
|
15794
15986
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
15795
15987
|
assertSafeRelativePath(relativePath);
|
|
15796
|
-
const abs = (0,
|
|
15797
|
-
(0,
|
|
15798
|
-
(0,
|
|
15988
|
+
const abs = (0, import_node_path36.join)(worktreePath, relativePath);
|
|
15989
|
+
(0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(abs), { recursive: true });
|
|
15990
|
+
(0, import_node_fs39.writeFileSync)(abs, content, "utf8");
|
|
15799
15991
|
return { path: relativePath };
|
|
15800
15992
|
}
|
|
15801
15993
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -15812,12 +16004,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
15812
16004
|
truncated: full.files.length > maxFiles
|
|
15813
16005
|
};
|
|
15814
16006
|
}
|
|
15815
|
-
var
|
|
16007
|
+
var import_node_fs39, import_node_path36, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
|
|
15816
16008
|
var init_diff = __esm({
|
|
15817
16009
|
"src/diff/diff.ts"() {
|
|
15818
16010
|
"use strict";
|
|
15819
|
-
|
|
15820
|
-
|
|
16011
|
+
import_node_fs39 = require("fs");
|
|
16012
|
+
import_node_path36 = require("path");
|
|
15821
16013
|
init_run();
|
|
15822
16014
|
init_worktree();
|
|
15823
16015
|
mergeBaseCache = /* @__PURE__ */ new Map();
|
|
@@ -16075,7 +16267,7 @@ function parseFrontmatter(content) {
|
|
|
16075
16267
|
}
|
|
16076
16268
|
function readSkill(skillMd, source) {
|
|
16077
16269
|
try {
|
|
16078
|
-
const content = (0,
|
|
16270
|
+
const content = (0, import_node_fs40.readFileSync)(skillMd, "utf8");
|
|
16079
16271
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
16080
16272
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
16081
16273
|
const name = fmName || dirName;
|
|
@@ -16094,19 +16286,19 @@ function readSkill(skillMd, source) {
|
|
|
16094
16286
|
}
|
|
16095
16287
|
}
|
|
16096
16288
|
function scanSkillsDir(dir, source, out) {
|
|
16097
|
-
if (!(0,
|
|
16289
|
+
if (!(0, import_node_fs40.existsSync)(dir)) return;
|
|
16098
16290
|
let entries;
|
|
16099
16291
|
try {
|
|
16100
|
-
entries = (0,
|
|
16292
|
+
entries = (0, import_node_fs40.readdirSync)(dir);
|
|
16101
16293
|
} catch {
|
|
16102
16294
|
return;
|
|
16103
16295
|
}
|
|
16104
16296
|
for (const entry of entries) {
|
|
16105
16297
|
if (entry.startsWith(".")) continue;
|
|
16106
|
-
const skillMd = (0,
|
|
16107
|
-
if (!(0,
|
|
16298
|
+
const skillMd = (0, import_node_path37.join)(dir, entry, "SKILL.md");
|
|
16299
|
+
if (!(0, import_node_fs40.existsSync)(skillMd)) continue;
|
|
16108
16300
|
try {
|
|
16109
|
-
if (!(0,
|
|
16301
|
+
if (!(0, import_node_fs40.statSync)(skillMd).isFile()) continue;
|
|
16110
16302
|
} catch {
|
|
16111
16303
|
continue;
|
|
16112
16304
|
}
|
|
@@ -16115,24 +16307,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
16115
16307
|
}
|
|
16116
16308
|
}
|
|
16117
16309
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
16118
|
-
if (!(0,
|
|
16310
|
+
if (!(0, import_node_fs40.existsSync)(pluginsRoot)) return;
|
|
16119
16311
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
16120
16312
|
if (depth > 7) return;
|
|
16121
16313
|
let entries;
|
|
16122
16314
|
try {
|
|
16123
|
-
entries = (0,
|
|
16315
|
+
entries = (0, import_node_fs40.readdirSync)(dir);
|
|
16124
16316
|
} catch {
|
|
16125
16317
|
return;
|
|
16126
16318
|
}
|
|
16127
16319
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
16128
|
-
const skill = readSkill((0,
|
|
16320
|
+
const skill = readSkill((0, import_node_path37.join)(dir, "SKILL.md"), "cli");
|
|
16129
16321
|
if (skill) out.push(skill);
|
|
16130
16322
|
}
|
|
16131
16323
|
for (const entry of entries) {
|
|
16132
16324
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
16133
|
-
const full = (0,
|
|
16325
|
+
const full = (0, import_node_path37.join)(dir, entry);
|
|
16134
16326
|
try {
|
|
16135
|
-
if (!(0,
|
|
16327
|
+
if (!(0, import_node_fs40.statSync)(full).isDirectory()) continue;
|
|
16136
16328
|
} catch {
|
|
16137
16329
|
continue;
|
|
16138
16330
|
}
|
|
@@ -16147,20 +16339,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
16147
16339
|
walk(pluginsRoot, 0, false);
|
|
16148
16340
|
}
|
|
16149
16341
|
function discoverSkills(worktreePath) {
|
|
16150
|
-
const home = (0,
|
|
16342
|
+
const home = (0, import_node_os12.homedir)();
|
|
16151
16343
|
const collected = [];
|
|
16152
16344
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
16153
|
-
scanSkillsDir((0,
|
|
16345
|
+
scanSkillsDir((0, import_node_path37.join)(worktreePath, rel), "workspace", collected);
|
|
16154
16346
|
}
|
|
16155
16347
|
for (const abs of [
|
|
16156
|
-
(0,
|
|
16157
|
-
(0,
|
|
16158
|
-
(0,
|
|
16159
|
-
(0,
|
|
16348
|
+
(0, import_node_path37.join)(home, ".claude/skills"),
|
|
16349
|
+
(0, import_node_path37.join)(home, ".cursor/skills"),
|
|
16350
|
+
(0, import_node_path37.join)(home, ".sideboard/skills"),
|
|
16351
|
+
(0, import_node_path37.join)(home, ".brightsy/skills")
|
|
16160
16352
|
]) {
|
|
16161
16353
|
scanSkillsDir(abs, "user", collected);
|
|
16162
16354
|
}
|
|
16163
|
-
scanClaudePluginSkills((0,
|
|
16355
|
+
scanClaudePluginSkills((0, import_node_path37.join)(home, ".claude/plugins"), collected);
|
|
16164
16356
|
collected.push(...bundledSkills());
|
|
16165
16357
|
const rank = {
|
|
16166
16358
|
workspace: 0,
|
|
@@ -16186,7 +16378,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
16186
16378
|
\u2026(truncated)` : body;
|
|
16187
16379
|
}
|
|
16188
16380
|
}
|
|
16189
|
-
const raw = (0,
|
|
16381
|
+
const raw = (0, import_node_fs40.readFileSync)(skillPath, "utf8");
|
|
16190
16382
|
if (raw.startsWith("---")) {
|
|
16191
16383
|
const end = raw.indexOf("\n---", 3);
|
|
16192
16384
|
if (end >= 0) {
|
|
@@ -16200,13 +16392,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
16200
16392
|
|
|
16201
16393
|
\u2026(truncated)` : raw;
|
|
16202
16394
|
}
|
|
16203
|
-
var
|
|
16395
|
+
var import_node_fs40, import_node_os12, import_node_path37, BUNDLED_SKILL_PREFIX;
|
|
16204
16396
|
var init_discover = __esm({
|
|
16205
16397
|
"src/skills/discover.ts"() {
|
|
16206
16398
|
"use strict";
|
|
16207
|
-
|
|
16208
|
-
|
|
16209
|
-
|
|
16399
|
+
import_node_fs40 = require("fs");
|
|
16400
|
+
import_node_os12 = require("os");
|
|
16401
|
+
import_node_path37 = require("path");
|
|
16210
16402
|
init_long_running();
|
|
16211
16403
|
BUNDLED_SKILL_PREFIX = "bundled:";
|
|
16212
16404
|
}
|
|
@@ -16301,17 +16493,17 @@ var init_expand = __esm({
|
|
|
16301
16493
|
function packagedDetachedJobPath() {
|
|
16302
16494
|
const dir = packagedMcpDir();
|
|
16303
16495
|
if (!dir) return null;
|
|
16304
|
-
const script = (0,
|
|
16305
|
-
return (0,
|
|
16496
|
+
const script = (0, import_node_path38.join)(dir, "scripts", "detached-job.js");
|
|
16497
|
+
return (0, import_node_fs41.existsSync)(script) ? script : null;
|
|
16306
16498
|
}
|
|
16307
16499
|
function resolveDetachedJobScript() {
|
|
16308
16500
|
const packaged = packagedDetachedJobPath();
|
|
16309
16501
|
if (packaged) return packaged;
|
|
16310
|
-
let dir = (0,
|
|
16502
|
+
let dir = (0, import_node_path38.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
|
|
16311
16503
|
for (let i = 0; i < 8; i++) {
|
|
16312
|
-
const candidate = (0,
|
|
16313
|
-
if ((0,
|
|
16314
|
-
const parent = (0,
|
|
16504
|
+
const candidate = (0, import_node_path38.join)(dir, "scripts", "detached-job.js");
|
|
16505
|
+
if ((0, import_node_fs41.existsSync)(candidate)) return candidate;
|
|
16506
|
+
const parent = (0, import_node_path38.dirname)(dir);
|
|
16315
16507
|
if (parent === dir) break;
|
|
16316
16508
|
dir = parent;
|
|
16317
16509
|
}
|
|
@@ -16322,12 +16514,12 @@ function formatDetachedJobInvoke(scriptPath) {
|
|
|
16322
16514
|
if (resolved) return `node ${JSON.stringify(resolved)}`;
|
|
16323
16515
|
return "node scripts/detached-job.js";
|
|
16324
16516
|
}
|
|
16325
|
-
var
|
|
16517
|
+
var import_node_fs41, import_node_path38, import_node_url3, import_meta3;
|
|
16326
16518
|
var init_detached_job_path = __esm({
|
|
16327
16519
|
"src/skills/detached-job-path.ts"() {
|
|
16328
16520
|
"use strict";
|
|
16329
|
-
|
|
16330
|
-
|
|
16521
|
+
import_node_fs41 = require("fs");
|
|
16522
|
+
import_node_path38 = require("path");
|
|
16331
16523
|
import_node_url3 = require("url");
|
|
16332
16524
|
init_packaged_runtime();
|
|
16333
16525
|
import_meta3 = {};
|
|
@@ -16400,11 +16592,11 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
16400
16592
|
);
|
|
16401
16593
|
} else if (opts?.githubSlug) {
|
|
16402
16594
|
lines.push(
|
|
16403
|
-
`- Prefer a draft PR first: \`gh pr create --draft -R ${opts.githubSlug}\` (or update via \`gh pr edit -R ${opts.githubSlug}\`) once the change set is coherent. Always pass \`-R ${opts.githubSlug}\` (this worktree's origin). Bare \`gh pr create\` may target upstream instead of origin on dual-remote checkouts. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name
|
|
16595
|
+
`- Prefer a draft PR first: \`gh pr create --draft -R ${opts.githubSlug}\` (or update via \`gh pr edit -R ${opts.githubSlug}\`) once the change set is coherent. Always pass \`-R ${opts.githubSlug}\` (this worktree's origin). Bare \`gh pr create\` may target upstream instead of origin on dual-remote checkouts. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name. If GitHub rejects the GraphQL body as too long, retry with a short \`--body-file\` (limit 65,536 characters) \u2014 do not paste a changelog or diff into \`--body\`.`
|
|
16404
16596
|
);
|
|
16405
16597
|
} else {
|
|
16406
16598
|
lines.push(
|
|
16407
|
-
"- Prefer a draft PR first: `gh pr create --draft -R <origin-owner/name>` (or update via `gh pr edit -R \u2026`) once the change set is coherent. Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree \u2014 never from `upstream`. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name."
|
|
16599
|
+
"- Prefer a draft PR first: `gh pr create --draft -R <origin-owner/name>` (or update via `gh pr edit -R \u2026`) once the change set is coherent. Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree \u2014 never from `upstream`. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name. If GitHub rejects the GraphQL body as too long, retry with a short `--body-file` (limit 65,536 characters) \u2014 do not paste a changelog or diff into `--body`."
|
|
16408
16600
|
);
|
|
16409
16601
|
}
|
|
16410
16602
|
lines.push("");
|
|
@@ -16495,12 +16687,12 @@ function formatArtifactDirective() {
|
|
|
16495
16687
|
function formatUiReminder() {
|
|
16496
16688
|
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). ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
|
|
16497
16689
|
}
|
|
16498
|
-
var
|
|
16690
|
+
var import_node_fs42, import_node_path39;
|
|
16499
16691
|
var init_instructions = __esm({
|
|
16500
16692
|
"src/agents/instructions.ts"() {
|
|
16501
16693
|
"use strict";
|
|
16502
|
-
|
|
16503
|
-
|
|
16694
|
+
import_node_fs42 = require("fs");
|
|
16695
|
+
import_node_path39 = require("path");
|
|
16504
16696
|
init_git_auth_mode();
|
|
16505
16697
|
init_worktree_labels();
|
|
16506
16698
|
init_detached_job_path();
|
|
@@ -16670,40 +16862,40 @@ __export(plan_file_exports, {
|
|
|
16670
16862
|
writePlanFile: () => writePlanFile
|
|
16671
16863
|
});
|
|
16672
16864
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
16673
|
-
const gitignoreAbs = (0,
|
|
16674
|
-
if ((0,
|
|
16675
|
-
(0,
|
|
16676
|
-
(0,
|
|
16865
|
+
const gitignoreAbs = (0, import_node_path40.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
16866
|
+
if ((0, import_node_fs43.existsSync)(gitignoreAbs)) return;
|
|
16867
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(gitignoreAbs), { recursive: true });
|
|
16868
|
+
(0, import_node_fs43.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
16677
16869
|
}
|
|
16678
16870
|
function planFileAbs(worktreePath) {
|
|
16679
|
-
return (0,
|
|
16871
|
+
return (0, import_node_path40.join)(worktreePath, PLAN_FILE_REL);
|
|
16680
16872
|
}
|
|
16681
16873
|
function readTextIfPresent2(abs) {
|
|
16682
|
-
if (!(0,
|
|
16874
|
+
if (!(0, import_node_fs43.existsSync)(abs)) return null;
|
|
16683
16875
|
try {
|
|
16684
|
-
const content = (0,
|
|
16876
|
+
const content = (0, import_node_fs43.readFileSync)(abs, "utf8");
|
|
16685
16877
|
return content.trim() ? content : null;
|
|
16686
16878
|
} catch {
|
|
16687
16879
|
return null;
|
|
16688
16880
|
}
|
|
16689
16881
|
}
|
|
16690
16882
|
function readPlanFile(worktreePath) {
|
|
16691
|
-
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0,
|
|
16883
|
+
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path40.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path40.join)(worktreePath, LEGACY_PLAN_FILE_REL));
|
|
16692
16884
|
}
|
|
16693
16885
|
function writePlanFile(worktreePath, content) {
|
|
16694
16886
|
ensureAttachmentsGitignore(worktreePath);
|
|
16695
16887
|
const abs = planFileAbs(worktreePath);
|
|
16696
|
-
(0,
|
|
16888
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(abs), { recursive: true });
|
|
16697
16889
|
const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
|
|
16698
|
-
(0,
|
|
16890
|
+
(0, import_node_fs43.writeFileSync)(abs, body, "utf8");
|
|
16699
16891
|
return PLAN_FILE_REL;
|
|
16700
16892
|
}
|
|
16701
|
-
var
|
|
16893
|
+
var import_node_fs43, import_node_path40;
|
|
16702
16894
|
var init_plan_file = __esm({
|
|
16703
16895
|
"src/plan/plan-file.ts"() {
|
|
16704
16896
|
"use strict";
|
|
16705
|
-
|
|
16706
|
-
|
|
16897
|
+
import_node_fs43 = require("fs");
|
|
16898
|
+
import_node_path40 = require("path");
|
|
16707
16899
|
init_workspace_scratch();
|
|
16708
16900
|
init_plan_present();
|
|
16709
16901
|
init_plan_present();
|
|
@@ -16763,7 +16955,7 @@ function setCaffeinateHoldHooks(next) {
|
|
|
16763
16955
|
hooks = next;
|
|
16764
16956
|
}
|
|
16765
16957
|
function caffeinateHoldPath() {
|
|
16766
|
-
return (0,
|
|
16958
|
+
return (0, import_node_path41.join)(appDataDir(), "caffeinate-hold.json");
|
|
16767
16959
|
}
|
|
16768
16960
|
function processAlive(pid) {
|
|
16769
16961
|
if (hooks.processAlive) return hooks.processAlive(pid);
|
|
@@ -16797,9 +16989,9 @@ function uniqueIds(ids) {
|
|
|
16797
16989
|
}
|
|
16798
16990
|
function readHold() {
|
|
16799
16991
|
const path = caffeinateHoldPath();
|
|
16800
|
-
if (!(0,
|
|
16992
|
+
if (!(0, import_node_fs44.existsSync)(path)) return null;
|
|
16801
16993
|
try {
|
|
16802
|
-
const parsed = JSON.parse((0,
|
|
16994
|
+
const parsed = JSON.parse((0, import_node_fs44.readFileSync)(path, "utf8"));
|
|
16803
16995
|
if (typeof parsed?.pid === "number" && parsed.pid > 0) {
|
|
16804
16996
|
return {
|
|
16805
16997
|
pid: parsed.pid,
|
|
@@ -16821,7 +17013,7 @@ function writeHold(pid, threadIds) {
|
|
|
16821
17013
|
}
|
|
16822
17014
|
function clearHold() {
|
|
16823
17015
|
try {
|
|
16824
|
-
(0,
|
|
17016
|
+
(0, import_node_fs44.unlinkSync)(caffeinateHoldPath());
|
|
16825
17017
|
} catch {
|
|
16826
17018
|
}
|
|
16827
17019
|
}
|
|
@@ -16906,13 +17098,13 @@ function releaseCaffeinateHoldForThread(threadId) {
|
|
|
16906
17098
|
}
|
|
16907
17099
|
return setCaffeinateHold(false, { threadId: id });
|
|
16908
17100
|
}
|
|
16909
|
-
var import_node_child_process4,
|
|
17101
|
+
var import_node_child_process4, import_node_fs44, import_node_path41, hooks;
|
|
16910
17102
|
var init_caffeinate_hold = __esm({
|
|
16911
17103
|
"src/store/caffeinate-hold.ts"() {
|
|
16912
17104
|
"use strict";
|
|
16913
17105
|
import_node_child_process4 = require("child_process");
|
|
16914
|
-
|
|
16915
|
-
|
|
17106
|
+
import_node_fs44 = require("fs");
|
|
17107
|
+
import_node_path41 = require("path");
|
|
16916
17108
|
init_paths();
|
|
16917
17109
|
init_private_file();
|
|
16918
17110
|
hooks = {};
|
|
@@ -16921,7 +17113,7 @@ var init_caffeinate_hold = __esm({
|
|
|
16921
17113
|
|
|
16922
17114
|
// src/store/schedules.ts
|
|
16923
17115
|
function schedulesPath() {
|
|
16924
|
-
return (0,
|
|
17116
|
+
return (0, import_node_path42.join)(appDataDir(), "schedules.json");
|
|
16925
17117
|
}
|
|
16926
17118
|
function parseDurationMs(every) {
|
|
16927
17119
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -17021,9 +17213,9 @@ function normalizeTask(raw) {
|
|
|
17021
17213
|
}
|
|
17022
17214
|
function readAll2() {
|
|
17023
17215
|
const path = schedulesPath();
|
|
17024
|
-
if (!(0,
|
|
17216
|
+
if (!(0, import_node_fs45.existsSync)(path)) return [];
|
|
17025
17217
|
try {
|
|
17026
|
-
const parsed = JSON.parse((0,
|
|
17218
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)(path, "utf8"));
|
|
17027
17219
|
if (!Array.isArray(parsed)) return [];
|
|
17028
17220
|
return parsed.map((row) => {
|
|
17029
17221
|
try {
|
|
@@ -17048,7 +17240,7 @@ function buildTask(input, now) {
|
|
|
17048
17240
|
const ts = nowIso2(now);
|
|
17049
17241
|
const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
|
|
17050
17242
|
return {
|
|
17051
|
-
id: (0,
|
|
17243
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
17052
17244
|
name: input.name?.trim() || defaultScheduleName(prompt),
|
|
17053
17245
|
prompt,
|
|
17054
17246
|
enabled: input.enabled !== false,
|
|
@@ -17135,13 +17327,13 @@ function recordScheduleRun(id, result) {
|
|
|
17135
17327
|
writeAll2(rows);
|
|
17136
17328
|
return next;
|
|
17137
17329
|
}
|
|
17138
|
-
var
|
|
17330
|
+
var import_node_crypto9, import_node_fs45, import_node_path42, import_croner, DURATION_RE, UNIT_MS;
|
|
17139
17331
|
var init_schedules = __esm({
|
|
17140
17332
|
"src/store/schedules.ts"() {
|
|
17141
17333
|
"use strict";
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17334
|
+
import_node_crypto9 = require("crypto");
|
|
17335
|
+
import_node_fs45 = require("fs");
|
|
17336
|
+
import_node_path42 = require("path");
|
|
17145
17337
|
import_croner = require("croner");
|
|
17146
17338
|
init_orchestrator_capable();
|
|
17147
17339
|
init_paths();
|
|
@@ -17283,13 +17475,13 @@ var init_schedule_runner = __esm({
|
|
|
17283
17475
|
|
|
17284
17476
|
// src/agents/cursor-store.ts
|
|
17285
17477
|
function cursorSdkStoreDir(threadId) {
|
|
17286
|
-
const root = (0,
|
|
17478
|
+
const root = (0, import_node_path43.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
|
|
17287
17479
|
const id = sanitizeCursorStoreSegment(threadId);
|
|
17288
17480
|
if (!id) return root;
|
|
17289
|
-
return (0,
|
|
17481
|
+
return (0, import_node_path43.join)(root, "threads", id);
|
|
17290
17482
|
}
|
|
17291
17483
|
function cursorSdkRunsNdjsonPath(threadId) {
|
|
17292
|
-
return (0,
|
|
17484
|
+
return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
|
|
17293
17485
|
}
|
|
17294
17486
|
function cursorSdkRunsNdjsonSearchPaths(threadId) {
|
|
17295
17487
|
const scoped = cursorSdkRunsNdjsonPath(threadId);
|
|
@@ -17302,11 +17494,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
|
|
|
17302
17494
|
function sanitizeCursorStoreSegment(threadId) {
|
|
17303
17495
|
return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
17304
17496
|
}
|
|
17305
|
-
var
|
|
17497
|
+
var import_node_path43, CURSOR_SDK_STORE_DIR;
|
|
17306
17498
|
var init_cursor_store = __esm({
|
|
17307
17499
|
"src/agents/cursor-store.ts"() {
|
|
17308
17500
|
"use strict";
|
|
17309
|
-
|
|
17501
|
+
import_node_path43 = require("path");
|
|
17310
17502
|
init_paths();
|
|
17311
17503
|
CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
|
|
17312
17504
|
}
|
|
@@ -17328,9 +17520,9 @@ function recoverFinishedCursorRun(opts) {
|
|
|
17328
17520
|
return best;
|
|
17329
17521
|
}
|
|
17330
17522
|
function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
17331
|
-
if (!(0,
|
|
17523
|
+
if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
|
|
17332
17524
|
try {
|
|
17333
|
-
const lines = (0,
|
|
17525
|
+
const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
|
|
17334
17526
|
let best = null;
|
|
17335
17527
|
for (const line of lines) {
|
|
17336
17528
|
const trimmed = line.trim();
|
|
@@ -17356,11 +17548,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
|
17356
17548
|
return null;
|
|
17357
17549
|
}
|
|
17358
17550
|
}
|
|
17359
|
-
var
|
|
17551
|
+
var import_node_fs46;
|
|
17360
17552
|
var init_cursor_recover = __esm({
|
|
17361
17553
|
"src/agents/cursor-recover.ts"() {
|
|
17362
17554
|
"use strict";
|
|
17363
|
-
|
|
17555
|
+
import_node_fs46 = require("fs");
|
|
17364
17556
|
init_cursor_store();
|
|
17365
17557
|
}
|
|
17366
17558
|
});
|
|
@@ -17399,6 +17591,7 @@ var init_title = __esm({
|
|
|
17399
17591
|
// src/orchestrator/orchestrator.ts
|
|
17400
17592
|
var orchestrator_exports = {};
|
|
17401
17593
|
__export(orchestrator_exports, {
|
|
17594
|
+
LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
|
|
17402
17595
|
Orchestrator: () => Orchestrator,
|
|
17403
17596
|
getOrchestrator: () => getOrchestrator,
|
|
17404
17597
|
isPidAlive: () => isPidAlive,
|
|
@@ -17491,13 +17684,13 @@ async function startOrchestration(opts) {
|
|
|
17491
17684
|
}
|
|
17492
17685
|
return updated;
|
|
17493
17686
|
}
|
|
17494
|
-
var import_node_events,
|
|
17687
|
+
var import_node_events, import_node_fs47, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
|
|
17495
17688
|
var init_orchestrator = __esm({
|
|
17496
17689
|
"src/orchestrator/orchestrator.ts"() {
|
|
17497
17690
|
"use strict";
|
|
17498
17691
|
import_node_events = require("events");
|
|
17499
17692
|
init_outbound_watch();
|
|
17500
|
-
|
|
17693
|
+
import_node_fs47 = require("fs");
|
|
17501
17694
|
init_error_detail();
|
|
17502
17695
|
init_run();
|
|
17503
17696
|
init_stale_lock();
|
|
@@ -17512,6 +17705,7 @@ var init_orchestrator = __esm({
|
|
|
17512
17705
|
init_orphan_cleanup();
|
|
17513
17706
|
init_apply_into_main();
|
|
17514
17707
|
init_clone_repo();
|
|
17708
|
+
init_message_parts();
|
|
17515
17709
|
init_usage();
|
|
17516
17710
|
init_thread_store();
|
|
17517
17711
|
init_desktop_host();
|
|
@@ -17549,6 +17743,7 @@ var init_orchestrator = __esm({
|
|
|
17549
17743
|
init_caffeinate_hold();
|
|
17550
17744
|
init_schedule_runner();
|
|
17551
17745
|
init_coordinator_prompt();
|
|
17746
|
+
LIVE_TURN_SPAWN_GRACE_MS = 15e3;
|
|
17552
17747
|
STALE_AGENT_PID_WAIT_MS = 2500;
|
|
17553
17748
|
Orchestrator = class {
|
|
17554
17749
|
events = new import_node_events.EventEmitter();
|
|
@@ -17605,6 +17800,39 @@ var init_orchestrator = __esm({
|
|
|
17605
17800
|
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
|
|
17606
17801
|
return true;
|
|
17607
17802
|
}
|
|
17803
|
+
/**
|
|
17804
|
+
* Whether a child is actually turning — not leftover disk `running` after
|
|
17805
|
+
* the process died. Coordinators were telling users “Agent is running.
|
|
17806
|
+
* Waiting for gate to pass” from stale stillRunning.
|
|
17807
|
+
*/
|
|
17808
|
+
threadLooksLive(thread) {
|
|
17809
|
+
if (thread.status === "queued") {
|
|
17810
|
+
if (this.draining.has(thread.id) || this.startingTurns.has(thread.id)) return true;
|
|
17811
|
+
return thread.queue.length > 0;
|
|
17812
|
+
}
|
|
17813
|
+
if (thread.status !== "running") return false;
|
|
17814
|
+
if (this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id)) return true;
|
|
17815
|
+
const pid = thread.agentPid;
|
|
17816
|
+
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return true;
|
|
17817
|
+
const updated = Date.parse(thread.updatedAt ?? "");
|
|
17818
|
+
if (Number.isFinite(updated) && Date.now() - updated < LIVE_TURN_SPAWN_GRACE_MS) return true;
|
|
17819
|
+
return false;
|
|
17820
|
+
}
|
|
17821
|
+
/** Desktop-only: persist idle/stopped when MCP would otherwise keep reporting live. */
|
|
17822
|
+
healStaleReportedActivity(thread) {
|
|
17823
|
+
if (!thisProcessShouldDrainAgentQueues()) return thread;
|
|
17824
|
+
if (this.threadLooksLive(thread)) return thread;
|
|
17825
|
+
if (thread.status === "running") {
|
|
17826
|
+
this.healStaleRunningTurns();
|
|
17827
|
+
return readThread(thread.id) ?? thread;
|
|
17828
|
+
}
|
|
17829
|
+
if (thread.status === "queued" && thread.queue.length === 0 && !this.activeTurns.has(thread.id) && !this.startingTurns.has(thread.id) && !this.draining.has(thread.id)) {
|
|
17830
|
+
setStatus(thread.id, "idle");
|
|
17831
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "idle" });
|
|
17832
|
+
return readThread(thread.id) ?? thread;
|
|
17833
|
+
}
|
|
17834
|
+
return thread;
|
|
17835
|
+
}
|
|
17608
17836
|
async reconcile(repoPath, opts) {
|
|
17609
17837
|
const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
|
|
17610
17838
|
const drainQueues = opts?.drainQueues !== false;
|
|
@@ -17629,7 +17857,7 @@ var init_orchestrator = __esm({
|
|
|
17629
17857
|
}
|
|
17630
17858
|
continue;
|
|
17631
17859
|
}
|
|
17632
|
-
if (!(0,
|
|
17860
|
+
if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
|
|
17633
17861
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
17634
17862
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
17635
17863
|
continue;
|
|
@@ -17939,12 +18167,14 @@ var init_orchestrator = __esm({
|
|
|
17939
18167
|
this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
|
|
17940
18168
|
return thread;
|
|
17941
18169
|
}
|
|
17942
|
-
async send(threadRef, prompt) {
|
|
18170
|
+
async send(threadRef, prompt, opts) {
|
|
17943
18171
|
const thread = this.requireThread(threadRef);
|
|
17944
18172
|
if (thread.status === "archived") {
|
|
17945
18173
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
17946
18174
|
}
|
|
17947
|
-
|
|
18175
|
+
const followUp = opts?.followUp === "steer" ? "steer" : "queue";
|
|
18176
|
+
let shouldSteer = false;
|
|
18177
|
+
const sent = await withThreadLock(thread.id, async () => {
|
|
17948
18178
|
const current = this.requireThread(thread.id);
|
|
17949
18179
|
if (current.status === "archived") {
|
|
17950
18180
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
@@ -17953,6 +18183,7 @@ var init_orchestrator = __esm({
|
|
|
17953
18183
|
this.crashContinued.delete(thread.id);
|
|
17954
18184
|
this.haltDrain.delete(thread.id);
|
|
17955
18185
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
18186
|
+
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
17956
18187
|
const patch = { queue };
|
|
17957
18188
|
if (!inFlight) patch.status = "queued";
|
|
17958
18189
|
const pid = current.agentPid;
|
|
@@ -17964,16 +18195,20 @@ var init_orchestrator = __esm({
|
|
|
17964
18195
|
if (!inFlight) {
|
|
17965
18196
|
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
17966
18197
|
}
|
|
17967
|
-
if (thisProcessShouldDrainAgentQueues()) {
|
|
18198
|
+
if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
|
|
17968
18199
|
void this.drainQueue(thread.id);
|
|
17969
18200
|
}
|
|
17970
18201
|
return this.requireThread(thread.id);
|
|
17971
18202
|
});
|
|
18203
|
+
if (shouldSteer && sent.queue.length > 0) {
|
|
18204
|
+
return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
|
|
18205
|
+
}
|
|
18206
|
+
return sent;
|
|
17972
18207
|
}
|
|
17973
|
-
async fanOut(threadRefs, prompt) {
|
|
18208
|
+
async fanOut(threadRefs, prompt, opts) {
|
|
17974
18209
|
const results = [];
|
|
17975
18210
|
for (const ref of threadRefs) {
|
|
17976
|
-
results.push(await this.send(ref, prompt));
|
|
18211
|
+
results.push(await this.send(ref, prompt, opts));
|
|
17977
18212
|
}
|
|
17978
18213
|
return results;
|
|
17979
18214
|
}
|
|
@@ -18777,8 +19012,8 @@ var init_orchestrator = __esm({
|
|
|
18777
19012
|
return created;
|
|
18778
19013
|
}
|
|
18779
19014
|
async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
|
|
18780
|
-
const thread = this.requireThread(threadRef);
|
|
18781
|
-
if (!
|
|
19015
|
+
const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
|
|
19016
|
+
if (!this.threadLooksLive(thread)) {
|
|
18782
19017
|
return thread;
|
|
18783
19018
|
}
|
|
18784
19019
|
const start = Date.now();
|
|
@@ -18815,12 +19050,13 @@ var init_orchestrator = __esm({
|
|
|
18815
19050
|
}
|
|
18816
19051
|
});
|
|
18817
19052
|
timer = setInterval(() => {
|
|
18818
|
-
const
|
|
18819
|
-
if (!
|
|
19053
|
+
const raw = readThread(thread.id);
|
|
19054
|
+
if (!raw) {
|
|
18820
19055
|
finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
|
|
18821
19056
|
return;
|
|
18822
19057
|
}
|
|
18823
|
-
|
|
19058
|
+
const current = this.healStaleReportedActivity(raw);
|
|
19059
|
+
if (!this.threadLooksLive(current)) {
|
|
18824
19060
|
finish(() => resolve(current));
|
|
18825
19061
|
return;
|
|
18826
19062
|
}
|
|
@@ -18843,20 +19079,22 @@ var init_orchestrator = __esm({
|
|
|
18843
19079
|
};
|
|
18844
19080
|
}
|
|
18845
19081
|
getTurnResult(threadRef) {
|
|
18846
|
-
const thread = this.requireThread(threadRef);
|
|
19082
|
+
const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
|
|
18847
19083
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
18848
19084
|
const lastError = thread.lastError ?? null;
|
|
18849
|
-
const
|
|
18850
|
-
const
|
|
19085
|
+
const rawText = (lastAgent?.text ?? "").trim();
|
|
19086
|
+
const text5 = (rawText && !isInternalAgentStatusText(rawText) ? rawText : "") || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
|
|
19087
|
+
const stillRunning = this.threadLooksLive(thread);
|
|
18851
19088
|
const live = stillRunning ? readTurnLive(thread.id) : null;
|
|
18852
|
-
const
|
|
19089
|
+
const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
|
|
19090
|
+
const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
|
|
18853
19091
|
return {
|
|
18854
19092
|
text: text5,
|
|
18855
19093
|
status: thread.status,
|
|
18856
19094
|
sessionId: thread.sessionId,
|
|
18857
19095
|
lastError,
|
|
18858
19096
|
stillRunning,
|
|
18859
|
-
progress:
|
|
19097
|
+
progress: liveSummary ?? queuedHint,
|
|
18860
19098
|
lastActivityAt: live?.updatedAt ?? null,
|
|
18861
19099
|
usage: lastAgent?.usage ?? null
|
|
18862
19100
|
};
|
|
@@ -19204,7 +19442,14 @@ var init_orchestrator = __esm({
|
|
|
19204
19442
|
);
|
|
19205
19443
|
}
|
|
19206
19444
|
if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
|
|
19207
|
-
|
|
19445
|
+
try {
|
|
19446
|
+
await this.pushAndMaybeOpenPr(thread, action);
|
|
19447
|
+
} catch (err) {
|
|
19448
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
19449
|
+
updateThread(thread.id, { lastError: message });
|
|
19450
|
+
this.emit({ type: "error", threadId: thread.id, message });
|
|
19451
|
+
throw err;
|
|
19452
|
+
}
|
|
19208
19453
|
return this.requireThread(threadRef);
|
|
19209
19454
|
}
|
|
19210
19455
|
let prBase;
|
|
@@ -19407,7 +19652,7 @@ var init_orchestrator = __esm({
|
|
|
19407
19652
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
19408
19653
|
return restored2;
|
|
19409
19654
|
}
|
|
19410
|
-
if (!(0,
|
|
19655
|
+
if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
|
|
19411
19656
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
19412
19657
|
throw new Error(
|
|
19413
19658
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
@@ -19419,6 +19664,8 @@ var init_orchestrator = __esm({
|
|
|
19419
19664
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
19420
19665
|
await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
|
|
19421
19666
|
});
|
|
19667
|
+
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
|
|
19668
|
+
await ensureWorktreeSideboardIgnored2(dest);
|
|
19422
19669
|
void createThreadWorktree2;
|
|
19423
19670
|
void slug;
|
|
19424
19671
|
}
|
|
@@ -19487,8 +19734,8 @@ init_nested_electron_env();
|
|
|
19487
19734
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
19488
19735
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
19489
19736
|
var import_zod5 = require("zod");
|
|
19490
|
-
var
|
|
19491
|
-
var
|
|
19737
|
+
var import_node_crypto12 = require("crypto");
|
|
19738
|
+
var import_node_path46 = require("path");
|
|
19492
19739
|
init_orchestrator();
|
|
19493
19740
|
init_worktree();
|
|
19494
19741
|
|
|
@@ -19502,7 +19749,7 @@ init_abletime();
|
|
|
19502
19749
|
init_fetch();
|
|
19503
19750
|
|
|
19504
19751
|
// src/integrations/linear-oauth.ts
|
|
19505
|
-
var
|
|
19752
|
+
var import_node_crypto10 = require("crypto");
|
|
19506
19753
|
var import_node_http = require("http");
|
|
19507
19754
|
init_app_settings();
|
|
19508
19755
|
init_fetch();
|
|
@@ -19680,6 +19927,22 @@ query SideboardAssignedIssues($first: Int!) {
|
|
|
19680
19927
|
}
|
|
19681
19928
|
}
|
|
19682
19929
|
`;
|
|
19930
|
+
var ISSUES_QUERY = `
|
|
19931
|
+
query SideboardIssues($first: Int!, $filter: IssueFilter) {
|
|
19932
|
+
viewer { id name }
|
|
19933
|
+
issues(first: $first, orderBy: updatedAt, filter: $filter) {
|
|
19934
|
+
nodes { ${LIST_ISSUE_FIELDS} }
|
|
19935
|
+
}
|
|
19936
|
+
}
|
|
19937
|
+
`;
|
|
19938
|
+
var SEARCH_ISSUES_QUERY = `
|
|
19939
|
+
query SideboardSearchIssues($term: String!, $first: Int!, $filter: IssueFilter) {
|
|
19940
|
+
viewer { id name }
|
|
19941
|
+
searchIssues(term: $term, first: $first, includeArchived: false, filter: $filter) {
|
|
19942
|
+
nodes { ${LIST_ISSUE_FIELDS} }
|
|
19943
|
+
}
|
|
19944
|
+
}
|
|
19945
|
+
`;
|
|
19683
19946
|
var TEAMS_QUERY = `
|
|
19684
19947
|
query SideboardTeams {
|
|
19685
19948
|
viewer { id name }
|
|
@@ -19963,19 +20226,73 @@ function normalizePriority(priority) {
|
|
|
19963
20226
|
}
|
|
19964
20227
|
return priority;
|
|
19965
20228
|
}
|
|
19966
|
-
|
|
19967
|
-
|
|
19968
|
-
|
|
20229
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
20230
|
+
function assigneeFilterKey(assignee) {
|
|
20231
|
+
return (assignee ?? "").trim();
|
|
20232
|
+
}
|
|
20233
|
+
function buildLinearIssueFilter(input) {
|
|
20234
|
+
const filter = {
|
|
20235
|
+
state: { type: { nin: ["completed", "canceled"] } }
|
|
20236
|
+
};
|
|
20237
|
+
const raw = assigneeFilterKey(input?.assignee) || "me";
|
|
20238
|
+
const key = raw.toLowerCase();
|
|
20239
|
+
if (key === "all" || key === "*") return filter;
|
|
20240
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
20241
|
+
filter.assignee = { null: true };
|
|
20242
|
+
return filter;
|
|
20243
|
+
}
|
|
20244
|
+
if (key === "me" || key === "@me") {
|
|
20245
|
+
filter.assignee = { isMe: true };
|
|
20246
|
+
return filter;
|
|
20247
|
+
}
|
|
20248
|
+
if (UUID_RE.test(raw)) {
|
|
20249
|
+
filter.assignee = { id: { eq: raw } };
|
|
20250
|
+
return filter;
|
|
20251
|
+
}
|
|
20252
|
+
filter.assignee = { name: { eqIgnoreCase: raw } };
|
|
20253
|
+
return filter;
|
|
20254
|
+
}
|
|
20255
|
+
function isAssignedToMe(assignee) {
|
|
20256
|
+
const key = assignee.toLowerCase();
|
|
20257
|
+
return key === "me" || key === "@me";
|
|
20258
|
+
}
|
|
20259
|
+
function listedLinearIssues(json, nodes) {
|
|
19969
20260
|
return {
|
|
19970
20261
|
viewer: {
|
|
19971
20262
|
id: String(json.viewer?.id ?? ""),
|
|
19972
20263
|
name: String(json.viewer?.name ?? "")
|
|
19973
20264
|
},
|
|
19974
|
-
issues: (
|
|
19975
|
-
(node) => toIssueInfo(mapIssue(node))
|
|
19976
|
-
)
|
|
20265
|
+
issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
|
|
19977
20266
|
};
|
|
19978
20267
|
}
|
|
20268
|
+
async function listLinearIssuesFiltered(opts) {
|
|
20269
|
+
const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
|
|
20270
|
+
const query = opts?.query?.trim() ?? "";
|
|
20271
|
+
const assignee = assigneeFilterKey(opts?.assignee) || (query ? "all" : "me");
|
|
20272
|
+
const filter = buildLinearIssueFilter({ assignee });
|
|
20273
|
+
if (query) {
|
|
20274
|
+
const json2 = await linearGraphql(
|
|
20275
|
+
SEARCH_ISSUES_QUERY,
|
|
20276
|
+
{ term: query, first, filter },
|
|
20277
|
+
opts
|
|
20278
|
+
);
|
|
20279
|
+
return listedLinearIssues(json2, json2.searchIssues?.nodes);
|
|
20280
|
+
}
|
|
20281
|
+
if (isAssignedToMe(assignee)) {
|
|
20282
|
+
const json2 = await linearGraphql(
|
|
20283
|
+
ASSIGNED_ISSUES_QUERY,
|
|
20284
|
+
{ first },
|
|
20285
|
+
opts
|
|
20286
|
+
);
|
|
20287
|
+
return listedLinearIssues(json2, json2.viewer?.assignedIssues?.nodes);
|
|
20288
|
+
}
|
|
20289
|
+
const json = await linearGraphql(
|
|
20290
|
+
ISSUES_QUERY,
|
|
20291
|
+
{ first, filter },
|
|
20292
|
+
opts
|
|
20293
|
+
);
|
|
20294
|
+
return listedLinearIssues(json, json.issues?.nodes);
|
|
20295
|
+
}
|
|
19979
20296
|
async function listLinearTeams(opts) {
|
|
19980
20297
|
const json = await linearGraphql(TEAMS_QUERY, void 0, opts);
|
|
19981
20298
|
return {
|
|
@@ -20082,6 +20399,22 @@ async function commentLinearIssue(input, opts) {
|
|
|
20082
20399
|
}
|
|
20083
20400
|
|
|
20084
20401
|
// src/integrations/issues.ts
|
|
20402
|
+
function assigneeKey(assignee) {
|
|
20403
|
+
return (assignee ?? "").trim().toLowerCase();
|
|
20404
|
+
}
|
|
20405
|
+
function issueMatchesAssignee(issue, assignee, viewerName = "") {
|
|
20406
|
+
const key = assigneeKey(assignee);
|
|
20407
|
+
if (!key || key === "all" || key === "*") return true;
|
|
20408
|
+
const names = [...issue.assignees ?? [], issue.assignee ?? ""].map((name) => name.trim().toLowerCase()).filter(Boolean);
|
|
20409
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
20410
|
+
return names.length === 0;
|
|
20411
|
+
}
|
|
20412
|
+
if (key === "me" || key === "@me") {
|
|
20413
|
+
const me = viewerName.trim().toLowerCase();
|
|
20414
|
+
return Boolean(me && names.includes(me));
|
|
20415
|
+
}
|
|
20416
|
+
return names.includes(key);
|
|
20417
|
+
}
|
|
20085
20418
|
async function listGitHubIssues(repoPath, opts) {
|
|
20086
20419
|
const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
|
|
20087
20420
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
@@ -20095,6 +20428,17 @@ async function listGitHubIssues(repoPath, opts) {
|
|
|
20095
20428
|
"--state",
|
|
20096
20429
|
"open"
|
|
20097
20430
|
];
|
|
20431
|
+
const query = opts?.query?.trim() ?? "";
|
|
20432
|
+
const assignee = opts?.assignee?.trim() ?? "";
|
|
20433
|
+
const key = assignee.toLowerCase();
|
|
20434
|
+
const searchParts = [];
|
|
20435
|
+
if (query) searchParts.push(query);
|
|
20436
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
20437
|
+
searchParts.push("no:assignee");
|
|
20438
|
+
} else if (key && key !== "all" && key !== "*") {
|
|
20439
|
+
args.push("--assignee", key === "me" || key === "@me" ? "@me" : assignee);
|
|
20440
|
+
}
|
|
20441
|
+
if (searchParts.length) args.push("--search", searchParts.join(" "));
|
|
20098
20442
|
if (slug) args.push("--repo", slug);
|
|
20099
20443
|
const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
|
|
20100
20444
|
if (exitCode !== 0 || !stdout.trim()) return [];
|
|
@@ -20132,14 +20476,20 @@ async function githubViewerLogin(repoPath) {
|
|
|
20132
20476
|
if (exitCode !== 0) return "";
|
|
20133
20477
|
return stdout.trim();
|
|
20134
20478
|
}
|
|
20135
|
-
async function listIssues(repoPath) {
|
|
20479
|
+
async function listIssues(repoPath, opts) {
|
|
20136
20480
|
const settings = loadAppSettings();
|
|
20137
20481
|
const preferredSource = settings.integrations.issueSource ?? "github";
|
|
20138
20482
|
const linearConnected = isLinearConnected(settings);
|
|
20139
20483
|
const abletimeConnected = isAbleTimeConnected(settings);
|
|
20140
20484
|
const source = resolveEffectiveIssueSource(settings);
|
|
20485
|
+
const query = opts?.query?.trim() || void 0;
|
|
20486
|
+
const assignee = opts?.assignee?.trim() || void 0;
|
|
20141
20487
|
if (source === "linear") {
|
|
20142
|
-
const listed = await
|
|
20488
|
+
const listed = await listLinearIssuesFiltered({
|
|
20489
|
+
assignee,
|
|
20490
|
+
query,
|
|
20491
|
+
limit: opts?.limit
|
|
20492
|
+
});
|
|
20143
20493
|
return {
|
|
20144
20494
|
source,
|
|
20145
20495
|
preferredSource,
|
|
@@ -20153,13 +20503,20 @@ async function listIssues(repoPath) {
|
|
|
20153
20503
|
};
|
|
20154
20504
|
}
|
|
20155
20505
|
if (source === "abletime") {
|
|
20156
|
-
const listed = await
|
|
20506
|
+
const [listed, searched] = await Promise.all([
|
|
20507
|
+
listAbleTimeAssignedIssues(),
|
|
20508
|
+
query ? searchAbleTimeTasks(query) : Promise.resolve(null)
|
|
20509
|
+
]);
|
|
20510
|
+
const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
|
|
20511
|
+
const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
|
|
20512
|
+
(issue) => issueMatchesAssignee(issue, assignee, viewerName)
|
|
20513
|
+
);
|
|
20157
20514
|
return {
|
|
20158
20515
|
source,
|
|
20159
20516
|
preferredSource,
|
|
20160
20517
|
linearConnected,
|
|
20161
20518
|
abletimeConnected,
|
|
20162
|
-
issues:
|
|
20519
|
+
issues: issues2,
|
|
20163
20520
|
viewer: {
|
|
20164
20521
|
login: listed.viewer.name,
|
|
20165
20522
|
name: listed.viewer.name
|
|
@@ -20167,7 +20524,7 @@ async function listIssues(repoPath) {
|
|
|
20167
20524
|
};
|
|
20168
20525
|
}
|
|
20169
20526
|
const [issues, login] = await Promise.all([
|
|
20170
|
-
listGitHubIssues(repoPath),
|
|
20527
|
+
listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
|
|
20171
20528
|
githubViewerLogin(repoPath)
|
|
20172
20529
|
]);
|
|
20173
20530
|
return {
|
|
@@ -20220,14 +20577,16 @@ function mcpWaitFinishedHint(status) {
|
|
|
20220
20577
|
}
|
|
20221
20578
|
|
|
20222
20579
|
// src/mcp/server.ts
|
|
20580
|
+
init_message_parts();
|
|
20223
20581
|
init_turn_live();
|
|
20224
20582
|
|
|
20225
20583
|
// src/mcp/thread-visibility.ts
|
|
20584
|
+
init_message_parts();
|
|
20226
20585
|
function lastMessagePreview(messages, max = 160) {
|
|
20227
20586
|
if (!messages?.length) return null;
|
|
20228
20587
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
20229
20588
|
const text5 = messages[i]?.text?.trim();
|
|
20230
|
-
if (!text5) continue;
|
|
20589
|
+
if (!text5 || isInternalAgentStatusText(text5)) continue;
|
|
20231
20590
|
const flat = text5.replace(/\s+/g, " ");
|
|
20232
20591
|
return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
|
|
20233
20592
|
}
|
|
@@ -20897,6 +21256,22 @@ function registerLinearTools(server) {
|
|
|
20897
21256
|
}
|
|
20898
21257
|
}
|
|
20899
21258
|
);
|
|
21259
|
+
server.tool(
|
|
21260
|
+
"linear_search_issues",
|
|
21261
|
+
"Search or list open Linear issues. Not limited to the current user \u2014 pass assignee=unassigned for issues with no owner, assignee=all (default when query is set) for anyone including unassigned, assignee=me for yours, or a user id / name. Optional query uses Linear search (title, identifier, description).",
|
|
21262
|
+
{
|
|
21263
|
+
query: import_zod3.z.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
|
|
21264
|
+
assignee: import_zod3.z.string().optional().describe("me, unassigned, all, a Linear user id, or a display name. Default: all when query is set, otherwise me."),
|
|
21265
|
+
limit: import_zod3.z.number().int().positive().max(250).optional()
|
|
21266
|
+
},
|
|
21267
|
+
async ({ query, assignee, limit }) => {
|
|
21268
|
+
try {
|
|
21269
|
+
return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
|
|
21270
|
+
} catch (err) {
|
|
21271
|
+
return fail3(err);
|
|
21272
|
+
}
|
|
21273
|
+
}
|
|
21274
|
+
);
|
|
20900
21275
|
server.tool(
|
|
20901
21276
|
"linear_get_issue",
|
|
20902
21277
|
"Get a Linear issue by uuid or identifier (ENG-123). Returns description, comments, relations (blocks/blockedBy/related/duplicate), parent/children, project, cycle, labels, and other metadata.",
|
|
@@ -21131,30 +21506,31 @@ function registerScheduleTools(server) {
|
|
|
21131
21506
|
|
|
21132
21507
|
// src/mcp/server.ts
|
|
21133
21508
|
init_agent_git_actions();
|
|
21509
|
+
init_gh_errors();
|
|
21134
21510
|
init_git_auth_mode();
|
|
21135
21511
|
|
|
21136
21512
|
// src/board/load-home-board.ts
|
|
21137
|
-
var
|
|
21138
|
-
var
|
|
21513
|
+
var import_node_fs49 = require("fs");
|
|
21514
|
+
var import_node_path45 = require("path");
|
|
21139
21515
|
init_worktree();
|
|
21140
21516
|
init_paths();
|
|
21141
21517
|
|
|
21142
21518
|
// src/board/board-pins.ts
|
|
21143
|
-
var
|
|
21144
|
-
var
|
|
21145
|
-
var
|
|
21519
|
+
var import_node_crypto11 = require("crypto");
|
|
21520
|
+
var import_node_fs48 = require("fs");
|
|
21521
|
+
var import_node_path44 = require("path");
|
|
21146
21522
|
init_paths();
|
|
21147
21523
|
init_home_board();
|
|
21148
21524
|
var FILE = "home-board-pins.json";
|
|
21149
21525
|
var VERSION = 1;
|
|
21150
21526
|
function pinsFile() {
|
|
21151
|
-
return (0,
|
|
21527
|
+
return (0, import_node_path44.join)(appDataDir(), FILE);
|
|
21152
21528
|
}
|
|
21153
21529
|
function readDisk() {
|
|
21154
21530
|
const path = pinsFile();
|
|
21155
|
-
if (!(0,
|
|
21531
|
+
if (!(0, import_node_fs48.existsSync)(path)) return [];
|
|
21156
21532
|
try {
|
|
21157
|
-
const raw = JSON.parse((0,
|
|
21533
|
+
const raw = JSON.parse((0, import_node_fs48.readFileSync)(path, "utf8"));
|
|
21158
21534
|
if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
|
|
21159
21535
|
return raw.items.filter((item) => item?.id && item.kind && item.ref);
|
|
21160
21536
|
} catch {
|
|
@@ -21162,8 +21538,8 @@ function readDisk() {
|
|
|
21162
21538
|
}
|
|
21163
21539
|
}
|
|
21164
21540
|
function writeDisk(items) {
|
|
21165
|
-
(0,
|
|
21166
|
-
(0,
|
|
21541
|
+
(0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
|
|
21542
|
+
(0, import_node_fs48.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
|
|
21167
21543
|
}
|
|
21168
21544
|
function listBoardPins() {
|
|
21169
21545
|
return readDisk();
|
|
@@ -21184,7 +21560,7 @@ function homeBoardWorkspaceKey(workspaces) {
|
|
|
21184
21560
|
return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
|
|
21185
21561
|
}
|
|
21186
21562
|
function cacheFile() {
|
|
21187
|
-
return (0,
|
|
21563
|
+
return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
|
|
21188
21564
|
}
|
|
21189
21565
|
function emptyInputs() {
|
|
21190
21566
|
return {
|
|
@@ -21210,9 +21586,9 @@ function shouldCacheHomeBoardInputs(inputs) {
|
|
|
21210
21586
|
}
|
|
21211
21587
|
function readDiskCache() {
|
|
21212
21588
|
const path = cacheFile();
|
|
21213
|
-
if (!(0,
|
|
21589
|
+
if (!(0, import_node_fs49.existsSync)(path)) return null;
|
|
21214
21590
|
try {
|
|
21215
|
-
const raw = JSON.parse((0,
|
|
21591
|
+
const raw = JSON.parse((0, import_node_fs49.readFileSync)(path, "utf8"));
|
|
21216
21592
|
if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
|
|
21217
21593
|
return null;
|
|
21218
21594
|
}
|
|
@@ -21226,8 +21602,8 @@ function readDiskCache() {
|
|
|
21226
21602
|
}
|
|
21227
21603
|
function writeDiskCache(entry) {
|
|
21228
21604
|
try {
|
|
21229
|
-
(0,
|
|
21230
|
-
(0,
|
|
21605
|
+
(0, import_node_fs49.mkdirSync)(appDataDir(), { recursive: true });
|
|
21606
|
+
(0, import_node_fs49.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
|
|
21231
21607
|
} catch {
|
|
21232
21608
|
}
|
|
21233
21609
|
}
|
|
@@ -21516,13 +21892,13 @@ async function startMcpServer() {
|
|
|
21516
21892
|
async () => {
|
|
21517
21893
|
const threads = orch.getThreads(true);
|
|
21518
21894
|
const lines = threads.map((t) => {
|
|
21519
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
21520
|
-
const live =
|
|
21895
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path46.basename)(t.repoPath) || t.repoPath;
|
|
21896
|
+
const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
|
|
21521
21897
|
const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
|
|
21522
21898
|
const preview = lastMessagePreview(t.messages, 80);
|
|
21523
21899
|
const previewBit = preview ? ` ${preview}` : "";
|
|
21524
21900
|
const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
|
|
21525
|
-
const progress = live?.summary ? ` ${live.summary}` : "";
|
|
21901
|
+
const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
|
|
21526
21902
|
return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title}${parent}${previewBit}${err} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}${progress}`;
|
|
21527
21903
|
});
|
|
21528
21904
|
return {
|
|
@@ -21584,7 +21960,9 @@ async function startMcpServer() {
|
|
|
21584
21960
|
if (!t) {
|
|
21585
21961
|
return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
|
|
21586
21962
|
}
|
|
21587
|
-
const
|
|
21963
|
+
const stillRunning = orch.threadLooksLive(t);
|
|
21964
|
+
const live = stillRunning ? readTurnLive(t.id) : null;
|
|
21965
|
+
const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
|
|
21588
21966
|
const spend = orch.getThreadUsage(t.id);
|
|
21589
21967
|
const summary = {
|
|
21590
21968
|
id: t.id,
|
|
@@ -21604,8 +21982,8 @@ async function startMcpServer() {
|
|
|
21604
21982
|
devPort: t.devPort,
|
|
21605
21983
|
prUrl: t.prUrl,
|
|
21606
21984
|
lastError: t.lastError ?? null,
|
|
21607
|
-
stillRunning
|
|
21608
|
-
progress:
|
|
21985
|
+
stillRunning,
|
|
21986
|
+
progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
|
|
21609
21987
|
lastActivityAt: live?.updatedAt ?? null,
|
|
21610
21988
|
usage: spend.usage,
|
|
21611
21989
|
lastTurnUsage: spend.lastTurnUsage
|
|
@@ -21886,7 +22264,7 @@ async function startMcpServer() {
|
|
|
21886
22264
|
const ident = issue?.identifier ?? ref.trim();
|
|
21887
22265
|
const attachments = issue ? [
|
|
21888
22266
|
{
|
|
21889
|
-
id: (0,
|
|
22267
|
+
id: (0, import_node_crypto12.randomUUID)(),
|
|
21890
22268
|
name: issue.identifier,
|
|
21891
22269
|
kind: "issue",
|
|
21892
22270
|
content: [
|
|
@@ -21962,7 +22340,7 @@ async function startMcpServer() {
|
|
|
21962
22340
|
);
|
|
21963
22341
|
server.tool(
|
|
21964
22342
|
"wait_for_turn",
|
|
21965
|
-
"Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. On status stopped or broken, the child did not finish \u2014 resume with send_to_thread or tell the user; do not treat that as success. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
|
|
22343
|
+
"Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. stillRunning is the source of truth \u2014 if false, the child is not working (do not say it is waiting for a gate). If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. On status stopped or broken, the child did not finish \u2014 resume with send_to_thread or tell the user; do not treat that as success. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
|
|
21966
22344
|
{
|
|
21967
22345
|
ref: import_zod5.z.string(),
|
|
21968
22346
|
timeoutMs: import_zod5.z.number().optional()
|
|
@@ -22154,7 +22532,7 @@ async function startMcpServer() {
|
|
|
22154
22532
|
);
|
|
22155
22533
|
server.tool(
|
|
22156
22534
|
"ask_git",
|
|
22157
|
-
"Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh`
|
|
22535
|
+
"Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
|
|
22158
22536
|
{
|
|
22159
22537
|
ref: import_zod5.z.string().describe("Worktree thread id/ref"),
|
|
22160
22538
|
action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
|
|
@@ -22179,8 +22557,26 @@ async function startMcpServer() {
|
|
|
22179
22557
|
]
|
|
22180
22558
|
};
|
|
22181
22559
|
} catch (err) {
|
|
22182
|
-
const
|
|
22183
|
-
|
|
22560
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
22561
|
+
const message = formatGhLandError(raw);
|
|
22562
|
+
return {
|
|
22563
|
+
content: [
|
|
22564
|
+
{
|
|
22565
|
+
type: "text",
|
|
22566
|
+
text: JSON.stringify(
|
|
22567
|
+
{
|
|
22568
|
+
error: true,
|
|
22569
|
+
action,
|
|
22570
|
+
lastError: message,
|
|
22571
|
+
hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_thread so the worktree agent runs gh pr create --draft -R <origin> --body-file <short.md>. Keep the description short." : void 0
|
|
22572
|
+
},
|
|
22573
|
+
null,
|
|
22574
|
+
2
|
|
22575
|
+
)
|
|
22576
|
+
}
|
|
22577
|
+
],
|
|
22578
|
+
isError: true
|
|
22579
|
+
};
|
|
22184
22580
|
}
|
|
22185
22581
|
}
|
|
22186
22582
|
);
|
|
@@ -22575,11 +22971,15 @@ async function startMcpServer() {
|
|
|
22575
22971
|
);
|
|
22576
22972
|
server.tool(
|
|
22577
22973
|
"list_issues",
|
|
22578
|
-
"List issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
|
|
22579
|
-
{
|
|
22580
|
-
|
|
22974
|
+
"List or search issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear defaults to issues assigned to you; pass assignee=unassigned for no owner, assignee=all for everyone (including unassigned), or a user id / GitHub login. Optional query searches title/identifier. Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. Prefer linear_search_issues when Linear is connected and you need unassigned or other people's tickets. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
|
|
22975
|
+
{
|
|
22976
|
+
repoPath: import_zod5.z.string(),
|
|
22977
|
+
query: import_zod5.z.string().optional().describe("Search title, identifier, or description"),
|
|
22978
|
+
assignee: import_zod5.z.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
|
|
22979
|
+
},
|
|
22980
|
+
async ({ repoPath, query, assignee }) => {
|
|
22581
22981
|
const root = await resolveRepoRoot(repoPath);
|
|
22582
|
-
const result = await listIssues(root);
|
|
22982
|
+
const result = await listIssues(root, { query, assignee });
|
|
22583
22983
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22584
22984
|
}
|
|
22585
22985
|
);
|