@sideboard-ai/core 0.1.149 → 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 +40 -35
- package/dist/agents/cursor-runner.js +2 -2
- package/dist/{agents-HSVQ2Z6Y.js → agents-KKXGTEV6.js} +10 -9
- package/dist/{agents-V4MTDWXS.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-TZWO7J4W.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-LAFA56WD.js → chunk-HEII7W3Q.js} +1 -1
- package/dist/{chunk-EGDRPA4B.js → chunk-NOTANBYC.js} +6 -6
- package/dist/{chunk-JDYKQ6OI.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-PTI5H3RK.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-Q5DHVMXB.js → chunk-YGGBJY5A.js} +18 -7
- 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 +998 -574
- 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 +976 -579
- package/dist/mcp/run-stdio.js +196 -43
- package/dist/{orchestrator-6TXQWBXN.js → orchestrator-GZE4X3XV.js} +14 -11
- package/dist/{orchestrator-Z2O5OVJA.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
|
@@ -1764,16 +1764,98 @@ var init_path = __esm({
|
|
|
1764
1764
|
}
|
|
1765
1765
|
});
|
|
1766
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
|
+
|
|
1767
1849
|
// src/git/stale-lock.ts
|
|
1768
1850
|
function isIndexLockError(text5) {
|
|
1769
1851
|
return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text5);
|
|
1770
1852
|
}
|
|
1771
1853
|
function clearStaleIndexLock(gitDir, maxAgeMs = STALE_INDEX_LOCK_MS, now = Date.now()) {
|
|
1772
|
-
const lockPath = (0,
|
|
1854
|
+
const lockPath = (0, import_node_path13.join)(gitDir, "index.lock");
|
|
1773
1855
|
try {
|
|
1774
|
-
if (!(0,
|
|
1775
|
-
if (now - (0,
|
|
1776
|
-
(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);
|
|
1777
1859
|
return lockPath;
|
|
1778
1860
|
} catch {
|
|
1779
1861
|
return null;
|
|
@@ -1788,12 +1870,12 @@ function clearStaleIndexLocks(gitDirs, maxAgeMs = STALE_INDEX_LOCK_MS) {
|
|
|
1788
1870
|
}
|
|
1789
1871
|
return removed;
|
|
1790
1872
|
}
|
|
1791
|
-
var
|
|
1873
|
+
var import_node_fs12, import_node_path13, STALE_INDEX_LOCK_MS;
|
|
1792
1874
|
var init_stale_lock = __esm({
|
|
1793
1875
|
"src/git/stale-lock.ts"() {
|
|
1794
1876
|
"use strict";
|
|
1795
|
-
|
|
1796
|
-
|
|
1877
|
+
import_node_fs12 = require("fs");
|
|
1878
|
+
import_node_path13 = require("path");
|
|
1797
1879
|
STALE_INDEX_LOCK_MS = 2e4;
|
|
1798
1880
|
}
|
|
1799
1881
|
});
|
|
@@ -1890,7 +1972,10 @@ async function gh(args, cwd, opts) {
|
|
|
1890
1972
|
timeoutMs: opts?.timeoutMs,
|
|
1891
1973
|
env: {
|
|
1892
1974
|
GH_PROMPT_DISABLED: "1",
|
|
1893
|
-
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() : {}
|
|
1894
1979
|
}
|
|
1895
1980
|
});
|
|
1896
1981
|
}
|
|
@@ -1906,6 +1991,7 @@ var init_run = __esm({
|
|
|
1906
1991
|
"use strict";
|
|
1907
1992
|
import_execa2 = require("execa");
|
|
1908
1993
|
init_path();
|
|
1994
|
+
init_github_agent_auth();
|
|
1909
1995
|
init_stale_lock();
|
|
1910
1996
|
}
|
|
1911
1997
|
});
|
|
@@ -2744,6 +2830,18 @@ var init_worktree_labels = __esm({
|
|
|
2744
2830
|
function isGhRateLimitError(text5) {
|
|
2745
2831
|
return /API rate limit (already )?exceeded/i.test(text5) || /rate limit exceeded/i.test(text5);
|
|
2746
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
|
+
}
|
|
2747
2845
|
function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
2748
2846
|
const ms = resetEpochSec * 1e3 - nowMs;
|
|
2749
2847
|
if (ms <= 0) return "soon";
|
|
@@ -2754,18 +2852,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
|
2754
2852
|
const hours = Math.ceil(mins / 60);
|
|
2755
2853
|
return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
|
|
2756
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
|
+
}
|
|
2757
2866
|
function extractGhErrorDetail(text5) {
|
|
2758
|
-
const trimmed = text5.trim();
|
|
2867
|
+
const trimmed = omitGhBodyArg(text5.trim());
|
|
2759
2868
|
if (!trimmed) return "";
|
|
2869
|
+
if (isGhPrBodyTooLongError(text5) || isGhPrBodyTooLongError(trimmed)) {
|
|
2870
|
+
return "GraphQL: body is too long (GitHub PR body / request size limit).";
|
|
2871
|
+
}
|
|
2760
2872
|
const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
|
|
2761
|
-
if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}
|
|
2873
|
+
if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
|
|
2762
2874
|
const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
|
|
2763
|
-
if (http?.[1]) return `HTTP: ${http[1].trim()}
|
|
2875
|
+
if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
|
|
2764
2876
|
const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
2765
2877
|
if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
|
|
2766
|
-
return lines.slice(1).join(" ").trim() || lines[0];
|
|
2878
|
+
return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
|
|
2767
2879
|
}
|
|
2768
|
-
return trimmed;
|
|
2880
|
+
return capGhErrorText(trimmed);
|
|
2769
2881
|
}
|
|
2770
2882
|
function formatGhLandError(raw, opts) {
|
|
2771
2883
|
const trimmed = raw.trim();
|
|
@@ -2783,6 +2895,10 @@ function formatGhLandError(raw, opts) {
|
|
|
2783
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>.";
|
|
2784
2896
|
return `Could not create the pull request.${hint}`;
|
|
2785
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
|
+
}
|
|
2786
2902
|
if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
|
|
2787
2903
|
const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
|
|
2788
2904
|
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
@@ -2803,15 +2919,82 @@ function formatMergePrError(raw) {
|
|
|
2803
2919
|
}
|
|
2804
2920
|
return extractGhErrorDetail(trimmed) || trimmed;
|
|
2805
2921
|
}
|
|
2922
|
+
var GITHUB_PR_BODY_MAX_CHARS, GITHUB_PR_BODY_SAFE_CHARS;
|
|
2806
2923
|
var init_gh_errors = __esm({
|
|
2807
2924
|
"src/git/gh-errors.ts"() {
|
|
2808
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";
|
|
2809
2992
|
}
|
|
2810
2993
|
});
|
|
2811
2994
|
|
|
2812
2995
|
// src/store/secret-vault.ts
|
|
2813
2996
|
function secretVaultPath() {
|
|
2814
|
-
return (0,
|
|
2997
|
+
return (0, import_node_path15.join)(appDataDir(), "secrets.json");
|
|
2815
2998
|
}
|
|
2816
2999
|
function loadSecretVault() {
|
|
2817
3000
|
const parsed = readSecureJson(secretVaultPath());
|
|
@@ -2870,11 +3053,11 @@ function normalizeVault(raw) {
|
|
|
2870
3053
|
}
|
|
2871
3054
|
return out;
|
|
2872
3055
|
}
|
|
2873
|
-
var
|
|
3056
|
+
var import_node_path15;
|
|
2874
3057
|
var init_secret_vault = __esm({
|
|
2875
3058
|
"src/store/secret-vault.ts"() {
|
|
2876
3059
|
"use strict";
|
|
2877
|
-
|
|
3060
|
+
import_node_path15 = require("path");
|
|
2878
3061
|
init_paths();
|
|
2879
3062
|
init_secure_file();
|
|
2880
3063
|
}
|
|
@@ -2903,6 +3086,7 @@ var init_issue_source_labels = __esm({
|
|
|
2903
3086
|
// src/store/app-settings.ts
|
|
2904
3087
|
var app_settings_exports = {};
|
|
2905
3088
|
__export(app_settings_exports, {
|
|
3089
|
+
FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
|
|
2906
3090
|
GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
|
|
2907
3091
|
HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
|
|
2908
3092
|
ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
|
|
@@ -2928,6 +3112,7 @@ __export(app_settings_exports, {
|
|
|
2928
3112
|
disconnectLinearConnection: () => disconnectLinearConnection,
|
|
2929
3113
|
emptyPublicIntegrations: () => emptyPublicIntegrations,
|
|
2930
3114
|
ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
|
|
3115
|
+
followUpBehavior: () => followUpBehavior,
|
|
2931
3116
|
getAbleTimeAccessToken: () => getAbleTimeAccessToken,
|
|
2932
3117
|
getAbleTimeHost: () => getAbleTimeHost,
|
|
2933
3118
|
getDefaultAgent: () => getDefaultAgent,
|
|
@@ -3036,10 +3221,10 @@ function toPublicAppSettings(settings) {
|
|
|
3036
3221
|
};
|
|
3037
3222
|
}
|
|
3038
3223
|
function appSettingsPath() {
|
|
3039
|
-
return (0,
|
|
3224
|
+
return (0, import_node_path16.join)(appDataDir(), "settings.json");
|
|
3040
3225
|
}
|
|
3041
3226
|
function claudeUserSettingsPath() {
|
|
3042
|
-
return (0,
|
|
3227
|
+
return (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".claude", "settings.json");
|
|
3043
3228
|
}
|
|
3044
3229
|
function normalizeClaude(raw) {
|
|
3045
3230
|
if (!raw || typeof raw !== "object") return {};
|
|
@@ -3284,6 +3469,9 @@ function normalizeAdvanced(raw) {
|
|
|
3284
3469
|
if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent) && source.orchestrationQuotaFallbackAgent !== "brightsy") {
|
|
3285
3470
|
out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
|
|
3286
3471
|
}
|
|
3472
|
+
if (source.followUpBehavior === "queue" || source.followUpBehavior === "steer") {
|
|
3473
|
+
out.followUpBehavior = source.followUpBehavior;
|
|
3474
|
+
}
|
|
3287
3475
|
return out;
|
|
3288
3476
|
}
|
|
3289
3477
|
function normalizeSettings(raw) {
|
|
@@ -3343,10 +3531,10 @@ function normalizeSettings(raw) {
|
|
|
3343
3531
|
}
|
|
3344
3532
|
function readSettingsFile() {
|
|
3345
3533
|
const path = appSettingsPath();
|
|
3346
|
-
if (!(0,
|
|
3534
|
+
if (!(0, import_node_fs14.existsSync)(path)) return { ...EMPTY_SETTINGS };
|
|
3347
3535
|
try {
|
|
3348
3536
|
chmodOwnerOnly(path);
|
|
3349
|
-
const parsed = JSON.parse((0,
|
|
3537
|
+
const parsed = JSON.parse((0, import_node_fs14.readFileSync)(path, "utf8"));
|
|
3350
3538
|
return normalizeSettings(parsed);
|
|
3351
3539
|
} catch {
|
|
3352
3540
|
return { ...EMPTY_SETTINGS };
|
|
@@ -3892,7 +4080,7 @@ function ensureSlackDeviceIdentity(settings = loadAppSettings()) {
|
|
|
3892
4080
|
}
|
|
3893
4081
|
if (!deviceLabel) {
|
|
3894
4082
|
try {
|
|
3895
|
-
deviceLabel = (0,
|
|
4083
|
+
deviceLabel = (0, import_node_os5.hostname)().split(".")[0]?.trim() || "This Mac";
|
|
3896
4084
|
} catch {
|
|
3897
4085
|
deviceLabel = "This Mac";
|
|
3898
4086
|
}
|
|
@@ -3975,6 +4163,9 @@ function updateAdvancedSettings(patch) {
|
|
|
3975
4163
|
if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent) && patch.orchestrationQuotaFallbackAgent !== "brightsy") {
|
|
3976
4164
|
advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
|
|
3977
4165
|
}
|
|
4166
|
+
if (patch.followUpBehavior === "queue" || patch.followUpBehavior === "steer") {
|
|
4167
|
+
advanced.followUpBehavior = patch.followUpBehavior;
|
|
4168
|
+
}
|
|
3978
4169
|
return saveAppSettings({ ...current, advanced });
|
|
3979
4170
|
}
|
|
3980
4171
|
function autoRenameBranchEnabled(settings = loadAppSettings()) {
|
|
@@ -4020,6 +4211,9 @@ function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
|
|
|
4020
4211
|
}
|
|
4021
4212
|
return "cursor";
|
|
4022
4213
|
}
|
|
4214
|
+
function followUpBehavior(settings = loadAppSettings()) {
|
|
4215
|
+
return settings.advanced.followUpBehavior === "queue" ? "queue" : "steer";
|
|
4216
|
+
}
|
|
4023
4217
|
function maxConcurrentAgents(settings = loadAppSettings()) {
|
|
4024
4218
|
const n = settings.advanced.maxConcurrent;
|
|
4025
4219
|
if (typeof n === "number" && Number.isFinite(n)) {
|
|
@@ -4107,14 +4301,14 @@ function childEnvWithAppSettings(extra) {
|
|
|
4107
4301
|
function harnessEnvKey(harness) {
|
|
4108
4302
|
return HARNESS_ENV_KEYS[harness];
|
|
4109
4303
|
}
|
|
4110
|
-
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;
|
|
4111
4305
|
var init_app_settings = __esm({
|
|
4112
4306
|
"src/store/app-settings.ts"() {
|
|
4113
4307
|
"use strict";
|
|
4114
4308
|
import_node_crypto3 = require("crypto");
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4309
|
+
import_node_fs14 = require("fs");
|
|
4310
|
+
import_node_os5 = require("os");
|
|
4311
|
+
import_node_path16 = require("path");
|
|
4118
4312
|
init_thinking_effort();
|
|
4119
4313
|
init_nested_electron_env();
|
|
4120
4314
|
init_paths();
|
|
@@ -4136,6 +4330,7 @@ var init_app_settings = __esm({
|
|
|
4136
4330
|
"cursor"
|
|
4137
4331
|
]);
|
|
4138
4332
|
GITHUB_GIT_AUTH_MODES = ["auto", "gh", "ssh", "token"];
|
|
4333
|
+
FOLLOW_UP_BEHAVIORS = ["steer", "queue"];
|
|
4139
4334
|
CLOUD_CONNECT_AGENTS = /* @__PURE__ */ new Set([
|
|
4140
4335
|
"claude",
|
|
4141
4336
|
"codex",
|
|
@@ -4163,89 +4358,26 @@ var init_app_settings = __esm({
|
|
|
4163
4358
|
}
|
|
4164
4359
|
});
|
|
4165
4360
|
|
|
4166
|
-
// src/git/
|
|
4167
|
-
function
|
|
4168
|
-
const
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
}
|
|
4175
|
-
|
|
4176
|
-
return (0, import_node_path15.join)(githubAgentAuthDir(), "gh");
|
|
4177
|
-
}
|
|
4178
|
-
function writePrivateFile2(file, body) {
|
|
4179
|
-
(0, import_node_fs13.mkdirSync)((0, import_node_path15.dirname)(file), { recursive: true, mode: 448 });
|
|
4180
|
-
try {
|
|
4181
|
-
(0, import_node_fs13.chmodSync)((0, import_node_path15.dirname)(file), 448);
|
|
4182
|
-
} catch {
|
|
4183
|
-
}
|
|
4184
|
-
(0, import_node_fs13.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
4185
|
-
try {
|
|
4186
|
-
(0, import_node_fs13.chmodSync)(file, 384);
|
|
4187
|
-
} 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
|
+
});
|
|
4188
4371
|
}
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
}
|
|
4194
|
-
|
|
4195
|
-
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
4196
|
-
return [
|
|
4197
|
-
"github.com:",
|
|
4198
|
-
" git_protocol: https",
|
|
4199
|
-
` user: ${u}`,
|
|
4200
|
-
` oauth_token: ${token}`,
|
|
4201
|
-
" users:",
|
|
4202
|
-
` ${u}:`,
|
|
4203
|
-
` oauth_token: ${token}`,
|
|
4204
|
-
""
|
|
4205
|
-
].join("\n");
|
|
4206
|
-
}
|
|
4207
|
-
function materializeGithubAgentAuth(token, user) {
|
|
4208
|
-
const trimmed = token.trim();
|
|
4209
|
-
if (!trimmed) return;
|
|
4210
|
-
const root = githubAgentAuthDir();
|
|
4211
|
-
(0, import_node_fs13.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
4212
|
-
try {
|
|
4213
|
-
(0, import_node_fs13.chmodSync)(root, 448);
|
|
4214
|
-
} 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
|
+
});
|
|
4215
4378
|
}
|
|
4216
|
-
|
|
4217
|
-
const ghDir = githubGhConfigDir();
|
|
4218
|
-
(0, import_node_fs13.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
4219
|
-
writePrivateFile2((0, import_node_path15.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
4220
|
-
writePrivateFile2((0, import_node_path15.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
4221
|
-
}
|
|
4222
|
-
function githubAgentAuthReady() {
|
|
4223
|
-
return (0, import_node_fs13.existsSync)(githubCredentialStorePath()) && (0, import_node_fs13.existsSync)((0, import_node_path15.join)(githubGhConfigDir(), "hosts.yml"));
|
|
4224
|
-
}
|
|
4225
|
-
function githubCredentialHelperGitConfig() {
|
|
4226
|
-
const file = githubCredentialStorePath();
|
|
4227
|
-
return [
|
|
4228
|
-
{ key: "credential.helper", value: "" },
|
|
4229
|
-
{ key: "credential.helper", value: `store --file=${file}` }
|
|
4230
|
-
];
|
|
4231
|
-
}
|
|
4232
|
-
function githubGhConfigEnv() {
|
|
4233
|
-
return {
|
|
4234
|
-
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
4235
|
-
GH_PROMPT_DISABLED: "1"
|
|
4236
|
-
};
|
|
4379
|
+
return entries;
|
|
4237
4380
|
}
|
|
4238
|
-
var import_node_fs13, import_node_os5, import_node_path15;
|
|
4239
|
-
var init_github_agent_auth = __esm({
|
|
4240
|
-
"src/git/github-agent-auth.ts"() {
|
|
4241
|
-
"use strict";
|
|
4242
|
-
import_node_fs13 = require("fs");
|
|
4243
|
-
import_node_os5 = require("os");
|
|
4244
|
-
import_node_path15 = require("path");
|
|
4245
|
-
}
|
|
4246
|
-
});
|
|
4247
|
-
|
|
4248
|
-
// src/git/git-auth-mode.ts
|
|
4249
4381
|
function nonInteractiveGitProcessEnv() {
|
|
4250
4382
|
return {
|
|
4251
4383
|
GIT_TERMINAL_PROMPT: "0",
|
|
@@ -4268,16 +4400,19 @@ function appendIndexedGitConfig(existing, entries) {
|
|
|
4268
4400
|
out.GIT_CONFIG_COUNT = String(count + entries.length);
|
|
4269
4401
|
return out;
|
|
4270
4402
|
}
|
|
4271
|
-
function githubAgentGitEnv(existing) {
|
|
4403
|
+
function githubAgentGitEnv(existing, opts) {
|
|
4272
4404
|
const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
|
|
4273
|
-
return appendIndexedGitConfig(existing, [
|
|
4405
|
+
return appendIndexedGitConfig(existing, [
|
|
4406
|
+
...githubHttpsInsteadOfEntries(opts?.remoteUrl),
|
|
4407
|
+
...helpers
|
|
4408
|
+
]);
|
|
4274
4409
|
}
|
|
4275
4410
|
function applyGithubGitAuthEnv(existing, opts) {
|
|
4276
4411
|
const out = { ...nonInteractiveGitProcessEnv() };
|
|
4277
4412
|
const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
|
|
4278
4413
|
if (token) materializeGithubAgentAuth(token);
|
|
4279
4414
|
Object.assign(out, githubGhConfigEnv());
|
|
4280
|
-
if (opts.mode === "ssh") return out;
|
|
4415
|
+
if (opts.mode === "ssh" && !token) return out;
|
|
4281
4416
|
Object.assign(out, githubAgentGitEnv(existing));
|
|
4282
4417
|
return out;
|
|
4283
4418
|
}
|
|
@@ -4333,7 +4468,7 @@ async function warmGithubAgentAuth(opts) {
|
|
|
4333
4468
|
}
|
|
4334
4469
|
function normalizeWritableRoot(raw) {
|
|
4335
4470
|
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
4336
|
-
return trimmed && (0,
|
|
4471
|
+
return trimmed && (0, import_node_path17.isAbsolute)(trimmed) ? trimmed : null;
|
|
4337
4472
|
}
|
|
4338
4473
|
async function resolveCodexGitWritableRoots(cwd) {
|
|
4339
4474
|
const roots = /* @__PURE__ */ new Set();
|
|
@@ -4390,8 +4525,9 @@ function formatGitAuthModeDirective(mode) {
|
|
|
4390
4525
|
case "ssh":
|
|
4391
4526
|
return [
|
|
4392
4527
|
"Git authentication (Settings \u2192 Git mode: SSH):",
|
|
4393
|
-
"-
|
|
4394
|
-
"-
|
|
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).",
|
|
4395
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.",
|
|
4396
4532
|
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
4397
4533
|
].join("\n");
|
|
@@ -4410,11 +4546,11 @@ function formatGitAuthModeDirective(mode) {
|
|
|
4410
4546
|
].join("\n");
|
|
4411
4547
|
}
|
|
4412
4548
|
}
|
|
4413
|
-
var
|
|
4549
|
+
var import_node_path17, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
|
|
4414
4550
|
var init_git_auth_mode = __esm({
|
|
4415
4551
|
"src/git/git-auth-mode.ts"() {
|
|
4416
4552
|
"use strict";
|
|
4417
|
-
|
|
4553
|
+
import_node_path17 = require("path");
|
|
4418
4554
|
init_app_settings();
|
|
4419
4555
|
init_github_agent_auth();
|
|
4420
4556
|
init_run();
|
|
@@ -4762,7 +4898,7 @@ function attachmentsGitignoreBody() {
|
|
|
4762
4898
|
}
|
|
4763
4899
|
function isWorkspaceScratchPath(relativePath) {
|
|
4764
4900
|
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
4765
|
-
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/");
|
|
4766
4902
|
}
|
|
4767
4903
|
var ATTACHMENTS_DIR, LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_GITIGNORE;
|
|
4768
4904
|
var init_workspace_scratch = __esm({
|
|
@@ -4869,7 +5005,7 @@ async function resolveRepoRoot(cwd) {
|
|
|
4869
5005
|
}
|
|
4870
5006
|
function canonicalizeRepoPath(path) {
|
|
4871
5007
|
try {
|
|
4872
|
-
return (0,
|
|
5008
|
+
return (0, import_node_fs15.realpathSync)(path);
|
|
4873
5009
|
} catch {
|
|
4874
5010
|
return path.replace(/\/+$/, "");
|
|
4875
5011
|
}
|
|
@@ -5608,6 +5744,16 @@ function originFetchBranch(sourceRef) {
|
|
|
5608
5744
|
if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
|
|
5609
5745
|
return ref;
|
|
5610
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
|
+
}
|
|
5611
5757
|
async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
5612
5758
|
const first = await git(args, repoPath, { reject: false, timeoutMs });
|
|
5613
5759
|
if (first.exitCode === 0) return true;
|
|
@@ -5617,15 +5763,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
|
5617
5763
|
} catch {
|
|
5618
5764
|
return false;
|
|
5619
5765
|
}
|
|
5620
|
-
if (mode === "ssh") return false;
|
|
5621
5766
|
const token = await resolveGithubAgentToken(mode, repoPath);
|
|
5622
5767
|
if (!token) return false;
|
|
5768
|
+
const remoteUrl = await originRemoteUrl(repoPath);
|
|
5623
5769
|
const tryHttps = async (header) => git(args, repoPath, {
|
|
5624
5770
|
reject: false,
|
|
5625
5771
|
timeoutMs,
|
|
5626
|
-
env:
|
|
5772
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
5627
5773
|
config: {
|
|
5628
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
5629
5774
|
"http.extraHeader": header
|
|
5630
5775
|
}
|
|
5631
5776
|
});
|
|
@@ -5707,8 +5852,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
|
|
|
5707
5852
|
}
|
|
5708
5853
|
async function createThreadWorktree(opts) {
|
|
5709
5854
|
let branchName = `thread/${opts.slug}`;
|
|
5710
|
-
const worktreePath = (0,
|
|
5711
|
-
if ((0,
|
|
5855
|
+
const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
5856
|
+
if ((0, import_node_fs15.existsSync)(worktreePath)) {
|
|
5712
5857
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
5713
5858
|
}
|
|
5714
5859
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -5743,13 +5888,14 @@ ${add.stdout}`;
|
|
|
5743
5888
|
});
|
|
5744
5889
|
branchName = added;
|
|
5745
5890
|
await ensureGhPreferOrigin(worktreePath);
|
|
5891
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5746
5892
|
return { branchName, worktreePath };
|
|
5747
5893
|
}
|
|
5748
5894
|
async function createExistingBranchWorktree(opts) {
|
|
5749
5895
|
const branchName = opts.branchName.trim();
|
|
5750
5896
|
if (!branchName) throw new Error("branch name required");
|
|
5751
|
-
const worktreePath = (0,
|
|
5752
|
-
if ((0,
|
|
5897
|
+
const worktreePath = (0, import_node_path18.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
5898
|
+
if ((0, import_node_fs15.existsSync)(worktreePath)) {
|
|
5753
5899
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
5754
5900
|
}
|
|
5755
5901
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -5787,6 +5933,7 @@ async function createExistingBranchWorktree(opts) {
|
|
|
5787
5933
|
await git(["checkout", "-B", branchName], worktreePath, { reject: false });
|
|
5788
5934
|
}
|
|
5789
5935
|
await ensureGhPreferOrigin(worktreePath);
|
|
5936
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5790
5937
|
return { branchName, worktreePath };
|
|
5791
5938
|
}
|
|
5792
5939
|
async function removeWorktree(repoPath, worktreePath, opts) {
|
|
@@ -5875,7 +6022,9 @@ async function currentBranch(worktreePath) {
|
|
|
5875
6022
|
async function commitAll(worktreePath, message) {
|
|
5876
6023
|
const dirty = await isDirty(worktreePath);
|
|
5877
6024
|
if (!dirty) return false;
|
|
6025
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5878
6026
|
await git(["add", "-A"], worktreePath);
|
|
6027
|
+
await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
|
|
5879
6028
|
await git(["commit", "-m", message], worktreePath);
|
|
5880
6029
|
return true;
|
|
5881
6030
|
}
|
|
@@ -5889,14 +6038,14 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
5889
6038
|
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
|
|
5890
6039
|
if (!slug || !token) {
|
|
5891
6040
|
throw new Error(
|
|
5892
|
-
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)" : "")
|
|
5893
6042
|
);
|
|
5894
6043
|
}
|
|
6044
|
+
const remoteUrl = await originRemoteUrl(worktreePath);
|
|
5895
6045
|
const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
|
|
5896
6046
|
reject: false,
|
|
5897
|
-
env:
|
|
6047
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
5898
6048
|
config: {
|
|
5899
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
5900
6049
|
"http.extraHeader": header
|
|
5901
6050
|
}
|
|
5902
6051
|
});
|
|
@@ -6026,6 +6175,32 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6026
6175
|
const repoArgs = ghRepoSelectArgs(slug);
|
|
6027
6176
|
const headRef = ghHeadRef(slug, opts.head);
|
|
6028
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;
|
|
6029
6204
|
const existing = await gh(
|
|
6030
6205
|
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
6031
6206
|
worktreePath,
|
|
@@ -6041,8 +6216,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6041
6216
|
branchOnly,
|
|
6042
6217
|
"--title",
|
|
6043
6218
|
opts.title,
|
|
6044
|
-
|
|
6045
|
-
opts.body ?? opts.title
|
|
6219
|
+
...bodyArgs
|
|
6046
6220
|
],
|
|
6047
6221
|
worktreePath,
|
|
6048
6222
|
{ reject: false }
|
|
@@ -6057,8 +6231,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6057
6231
|
"--web",
|
|
6058
6232
|
"--title",
|
|
6059
6233
|
opts.title,
|
|
6060
|
-
|
|
6061
|
-
opts.body ?? opts.title,
|
|
6234
|
+
...bodyArgs,
|
|
6062
6235
|
"--base",
|
|
6063
6236
|
opts.base,
|
|
6064
6237
|
"--head",
|
|
@@ -6079,8 +6252,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6079
6252
|
"create",
|
|
6080
6253
|
"--title",
|
|
6081
6254
|
opts.title,
|
|
6082
|
-
|
|
6083
|
-
opts.body ?? opts.title,
|
|
6255
|
+
...bodyArgs,
|
|
6084
6256
|
"--base",
|
|
6085
6257
|
opts.base,
|
|
6086
6258
|
"--head",
|
|
@@ -6104,10 +6276,10 @@ function sameRepoPath(a, b) {
|
|
|
6104
6276
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
6105
6277
|
}
|
|
6106
6278
|
function listLocalThreadBranchSlugs(repoPath) {
|
|
6107
|
-
const refsDir = (0,
|
|
6108
|
-
if (!(0,
|
|
6279
|
+
const refsDir = (0, import_node_path18.join)(repoPath, ".git", "refs", "heads", "thread");
|
|
6280
|
+
if (!(0, import_node_fs15.existsSync)(refsDir)) return [];
|
|
6109
6281
|
try {
|
|
6110
|
-
return (0,
|
|
6282
|
+
return (0, import_node_fs15.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
|
|
6111
6283
|
} catch {
|
|
6112
6284
|
return [];
|
|
6113
6285
|
}
|
|
@@ -6115,8 +6287,8 @@ function listLocalThreadBranchSlugs(repoPath) {
|
|
|
6115
6287
|
function collectTakenTeamSlugs(repoPath) {
|
|
6116
6288
|
const taken = /* @__PURE__ */ new Set();
|
|
6117
6289
|
const root = worktreesRoot(repoPath);
|
|
6118
|
-
if ((0,
|
|
6119
|
-
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 })) {
|
|
6120
6292
|
if (entry.isDirectory() && entry.name !== ".DS_Store") {
|
|
6121
6293
|
taken.add(normalizeTakenSlug(entry.name));
|
|
6122
6294
|
}
|
|
@@ -6137,23 +6309,26 @@ function allocateTeamSlug(repoPath) {
|
|
|
6137
6309
|
const taken = collectTakenTeamSlugs(repoPath);
|
|
6138
6310
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
6139
6311
|
const team = allocateTeamName(taken);
|
|
6140
|
-
const path = (0,
|
|
6141
|
-
if (!(0,
|
|
6312
|
+
const path = (0, import_node_path18.join)(worktreesRoot(repoPath), team.slug);
|
|
6313
|
+
if (!(0, import_node_fs15.existsSync)(path)) return team;
|
|
6142
6314
|
taken.add(team.slug);
|
|
6143
6315
|
}
|
|
6144
6316
|
throw new Error("No available soccer team worktree directories left");
|
|
6145
6317
|
}
|
|
6146
|
-
var
|
|
6318
|
+
var import_node_crypto4, import_node_fs15, import_node_os6, import_node_path18;
|
|
6147
6319
|
var init_worktree = __esm({
|
|
6148
6320
|
"src/git/worktree.ts"() {
|
|
6149
6321
|
"use strict";
|
|
6150
|
-
|
|
6151
|
-
|
|
6322
|
+
import_node_crypto4 = require("crypto");
|
|
6323
|
+
import_node_fs15 = require("fs");
|
|
6324
|
+
import_node_os6 = require("os");
|
|
6325
|
+
import_node_path18 = require("path");
|
|
6152
6326
|
init_paths();
|
|
6153
6327
|
init_thread_store();
|
|
6154
6328
|
init_teams();
|
|
6155
6329
|
init_worktree_labels();
|
|
6156
6330
|
init_gh_errors();
|
|
6331
|
+
init_worktree_exclude();
|
|
6157
6332
|
init_git_auth_mode();
|
|
6158
6333
|
init_run();
|
|
6159
6334
|
init_repo_git_lock();
|
|
@@ -6197,7 +6372,7 @@ var init_cloud_connect_constants = __esm({
|
|
|
6197
6372
|
|
|
6198
6373
|
// src/composer/stage-files.ts
|
|
6199
6374
|
function fileExtension(filePath) {
|
|
6200
|
-
const base = (0,
|
|
6375
|
+
const base = (0, import_node_path19.basename)(filePath).toLowerCase();
|
|
6201
6376
|
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
6202
6377
|
}
|
|
6203
6378
|
function isImageFilePath(filePath) {
|
|
@@ -6207,24 +6382,24 @@ function imageMimeType(filePath) {
|
|
|
6207
6382
|
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
6208
6383
|
}
|
|
6209
6384
|
function ensureAttachmentsDir(worktreePath) {
|
|
6210
|
-
const dir = (0,
|
|
6211
|
-
(0,
|
|
6212
|
-
const gi = (0,
|
|
6213
|
-
if (!(0,
|
|
6214
|
-
(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");
|
|
6215
6390
|
}
|
|
6216
6391
|
return dir;
|
|
6217
6392
|
}
|
|
6218
6393
|
function uniqueAttachmentName(dir, originalName) {
|
|
6219
6394
|
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
6220
|
-
if (!(0,
|
|
6221
|
-
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);
|
|
6222
6397
|
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
6223
6398
|
for (let i = 1; i < 1e4; i++) {
|
|
6224
6399
|
const candidate = `${stem}-${i}${ext}`;
|
|
6225
|
-
if (!(0,
|
|
6400
|
+
if (!(0, import_node_fs16.existsSync)((0, import_node_path19.join)(dir, candidate))) return candidate;
|
|
6226
6401
|
}
|
|
6227
|
-
return `${stem}-${(0,
|
|
6402
|
+
return `${stem}-${(0, import_node_crypto5.randomUUID)()}${ext}`;
|
|
6228
6403
|
}
|
|
6229
6404
|
function previewDataUrlFromBuf(filePath, buf) {
|
|
6230
6405
|
if (!isImageFilePath(filePath)) return void 0;
|
|
@@ -6236,7 +6411,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
6236
6411
|
if (isImageFilePath(name)) {
|
|
6237
6412
|
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
6238
6413
|
return {
|
|
6239
|
-
id: (0,
|
|
6414
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6240
6415
|
name,
|
|
6241
6416
|
kind: "file",
|
|
6242
6417
|
path: opts.path,
|
|
@@ -6249,7 +6424,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
6249
6424
|
}
|
|
6250
6425
|
if (buf.length > MAX_INLINE_BYTES) {
|
|
6251
6426
|
return {
|
|
6252
|
-
id: (0,
|
|
6427
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6253
6428
|
name,
|
|
6254
6429
|
kind: "file",
|
|
6255
6430
|
path: opts.path,
|
|
@@ -6258,7 +6433,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
6258
6433
|
}
|
|
6259
6434
|
if (buf.includes(0)) {
|
|
6260
6435
|
return {
|
|
6261
|
-
id: (0,
|
|
6436
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6262
6437
|
name,
|
|
6263
6438
|
kind: "file",
|
|
6264
6439
|
path: opts.path,
|
|
@@ -6266,7 +6441,7 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
6266
6441
|
};
|
|
6267
6442
|
}
|
|
6268
6443
|
return {
|
|
6269
|
-
id: (0,
|
|
6444
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6270
6445
|
name,
|
|
6271
6446
|
kind: "file",
|
|
6272
6447
|
path: opts.path,
|
|
@@ -6278,19 +6453,19 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
|
6278
6453
|
const dir = ensureAttachmentsDir(worktreePath);
|
|
6279
6454
|
const out = [];
|
|
6280
6455
|
for (const abs of absolutePaths) {
|
|
6281
|
-
const originalName = (0,
|
|
6456
|
+
const originalName = (0, import_node_path19.basename)(abs);
|
|
6282
6457
|
try {
|
|
6283
|
-
const st = (0,
|
|
6458
|
+
const st = (0, import_node_fs16.statSync)(abs);
|
|
6284
6459
|
if (!st.isFile()) continue;
|
|
6285
6460
|
const name = uniqueAttachmentName(dir, originalName);
|
|
6286
|
-
const destAbs = (0,
|
|
6287
|
-
(0,
|
|
6461
|
+
const destAbs = (0, import_node_path19.join)(dir, name);
|
|
6462
|
+
(0, import_node_fs16.copyFileSync)(abs, destAbs);
|
|
6288
6463
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
6289
|
-
const buf = (0,
|
|
6464
|
+
const buf = (0, import_node_fs16.readFileSync)(destAbs);
|
|
6290
6465
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
6291
6466
|
} catch (err) {
|
|
6292
6467
|
out.push({
|
|
6293
|
-
id: (0,
|
|
6468
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6294
6469
|
name: originalName,
|
|
6295
6470
|
kind: "file",
|
|
6296
6471
|
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -6308,13 +6483,13 @@ function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
|
6308
6483
|
try {
|
|
6309
6484
|
const buf = Buffer.from(item.dataBase64, "base64");
|
|
6310
6485
|
const name = uniqueAttachmentName(dir, originalName);
|
|
6311
|
-
const destAbs = (0,
|
|
6312
|
-
(0,
|
|
6486
|
+
const destAbs = (0, import_node_path19.join)(dir, name);
|
|
6487
|
+
(0, import_node_fs16.writeFileSync)(destAbs, buf);
|
|
6313
6488
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
6314
6489
|
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
6315
6490
|
} catch (err) {
|
|
6316
6491
|
out.push({
|
|
6317
|
-
id: (0,
|
|
6492
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6318
6493
|
name: originalName,
|
|
6319
6494
|
kind: "file",
|
|
6320
6495
|
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -6369,23 +6544,23 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
6369
6544
|
for (const rel of relativePaths) {
|
|
6370
6545
|
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
6371
6546
|
out.push({
|
|
6372
|
-
id: (0,
|
|
6373
|
-
name: (0,
|
|
6547
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6548
|
+
name: (0, import_node_path19.basename)(rel) || "file",
|
|
6374
6549
|
kind: "file",
|
|
6375
6550
|
content: `(invalid path: ${rel})`
|
|
6376
6551
|
});
|
|
6377
6552
|
continue;
|
|
6378
6553
|
}
|
|
6379
|
-
const name = (0,
|
|
6554
|
+
const name = (0, import_node_path19.basename)(rel);
|
|
6380
6555
|
try {
|
|
6381
|
-
const abs = (0,
|
|
6382
|
-
const st = (0,
|
|
6556
|
+
const abs = (0, import_node_path19.join)(worktreePath, rel);
|
|
6557
|
+
const st = (0, import_node_fs16.statSync)(abs);
|
|
6383
6558
|
if (!st.isFile()) continue;
|
|
6384
|
-
const buf = (0,
|
|
6559
|
+
const buf = (0, import_node_fs16.readFileSync)(abs);
|
|
6385
6560
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
6386
6561
|
} catch (err) {
|
|
6387
6562
|
out.push({
|
|
6388
|
-
id: (0,
|
|
6563
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
6389
6564
|
name,
|
|
6390
6565
|
kind: "file",
|
|
6391
6566
|
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
@@ -6394,13 +6569,13 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
6394
6569
|
}
|
|
6395
6570
|
return out;
|
|
6396
6571
|
}
|
|
6397
|
-
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;
|
|
6398
6573
|
var init_stage_files = __esm({
|
|
6399
6574
|
"src/composer/stage-files.ts"() {
|
|
6400
6575
|
"use strict";
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6576
|
+
import_node_fs16 = require("fs");
|
|
6577
|
+
import_node_path19 = require("path");
|
|
6578
|
+
import_node_crypto5 = require("crypto");
|
|
6404
6579
|
init_workspace_scratch();
|
|
6405
6580
|
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6406
6581
|
"png",
|
|
@@ -6517,7 +6692,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
6517
6692
|
function ensureGlobalCoordinatorCwd(opts) {
|
|
6518
6693
|
const dir = globalAgentCwd();
|
|
6519
6694
|
try {
|
|
6520
|
-
(0,
|
|
6695
|
+
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
6521
6696
|
} catch {
|
|
6522
6697
|
return dir;
|
|
6523
6698
|
}
|
|
@@ -6525,7 +6700,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
6525
6700
|
let orchId = opts?.orchestratorThreadId?.trim() || "";
|
|
6526
6701
|
if (!orchId) {
|
|
6527
6702
|
try {
|
|
6528
|
-
const existing = (0,
|
|
6703
|
+
const existing = (0, import_node_fs17.readFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), "utf8");
|
|
6529
6704
|
const m = existing.match(
|
|
6530
6705
|
/YOUR orchestration thread id is `([0-9a-f-]{36})`/i
|
|
6531
6706
|
);
|
|
@@ -6568,9 +6743,9 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
6568
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."
|
|
6569
6744
|
].join("\n");
|
|
6570
6745
|
try {
|
|
6571
|
-
(0,
|
|
6746
|
+
(0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
|
|
6572
6747
|
`, "utf8");
|
|
6573
|
-
(0,
|
|
6748
|
+
(0, import_node_fs17.writeFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), `${body}
|
|
6574
6749
|
`, "utf8");
|
|
6575
6750
|
} catch {
|
|
6576
6751
|
}
|
|
@@ -6602,12 +6777,12 @@ function coordinatorSystemPrompt(opts) {
|
|
|
6602
6777
|
formatWorkspaceInventory(opts.workspaces)
|
|
6603
6778
|
].join("\n");
|
|
6604
6779
|
}
|
|
6605
|
-
var
|
|
6780
|
+
var import_node_fs17, import_node_path20, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
|
|
6606
6781
|
var init_coordinator_prompt = __esm({
|
|
6607
6782
|
"src/orchestrator/coordinator-prompt.ts"() {
|
|
6608
6783
|
"use strict";
|
|
6609
|
-
|
|
6610
|
-
|
|
6784
|
+
import_node_fs17 = require("fs");
|
|
6785
|
+
import_node_path20 = require("path");
|
|
6611
6786
|
init_worktree();
|
|
6612
6787
|
init_app_settings();
|
|
6613
6788
|
init_paths();
|
|
@@ -6617,8 +6792,8 @@ var init_coordinator_prompt = __esm({
|
|
|
6617
6792
|
"Discover:",
|
|
6618
6793
|
"- list_workspaces \u2014 registered repos (path + github slug when known)",
|
|
6619
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.",
|
|
6620
|
-
"- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues)",
|
|
6621
|
-
"- 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.",
|
|
6622
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).",
|
|
6623
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",
|
|
6624
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).",
|
|
@@ -6637,7 +6812,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6637
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.",
|
|
6638
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.",
|
|
6639
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)",
|
|
6640
|
-
"- 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.",
|
|
6641
6816
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
6642
6817
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
6643
6818
|
"Setup / run:",
|
|
@@ -6646,7 +6821,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6646
6821
|
"Inspect / review / PRs:",
|
|
6647
6822
|
"- get_diff \u2014 compact diff summary",
|
|
6648
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',
|
|
6649
|
-
"- 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.",
|
|
6650
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.',
|
|
6651
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.',
|
|
6652
6827
|
"Process guides:",
|
|
@@ -6917,32 +7092,32 @@ var init_global_workspace = __esm({
|
|
|
6917
7092
|
function brightsyConfigPath() {
|
|
6918
7093
|
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
6919
7094
|
if (override) return override;
|
|
6920
|
-
return (0,
|
|
7095
|
+
return (0, import_node_path21.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
|
|
6921
7096
|
}
|
|
6922
7097
|
function loadBrightsyConfig() {
|
|
6923
7098
|
const path = brightsyConfigPath();
|
|
6924
|
-
if (!(0,
|
|
7099
|
+
if (!(0, import_node_fs18.existsSync)(path)) {
|
|
6925
7100
|
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
6926
7101
|
}
|
|
6927
|
-
const raw = JSON.parse((0,
|
|
7102
|
+
const raw = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
|
|
6928
7103
|
if (!raw.access_token || !raw.account_id) {
|
|
6929
7104
|
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
6930
7105
|
}
|
|
6931
7106
|
return raw;
|
|
6932
7107
|
}
|
|
6933
7108
|
function saveBrightsyConfig(cfg) {
|
|
6934
|
-
(0,
|
|
7109
|
+
(0, import_node_fs18.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
6935
7110
|
`, {
|
|
6936
7111
|
mode: 384
|
|
6937
7112
|
});
|
|
6938
7113
|
}
|
|
6939
|
-
var
|
|
7114
|
+
var import_node_fs18, import_node_os7, import_node_path21;
|
|
6940
7115
|
var init_config = __esm({
|
|
6941
7116
|
"src/brightsy/config.ts"() {
|
|
6942
7117
|
"use strict";
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
7118
|
+
import_node_fs18 = require("fs");
|
|
7119
|
+
import_node_os7 = require("os");
|
|
7120
|
+
import_node_path21 = require("path");
|
|
6946
7121
|
}
|
|
6947
7122
|
});
|
|
6948
7123
|
|
|
@@ -7059,22 +7234,22 @@ var init_oauth = __esm({
|
|
|
7059
7234
|
|
|
7060
7235
|
// src/brightsy/connected-teams.ts
|
|
7061
7236
|
function storePath4() {
|
|
7062
|
-
return (0,
|
|
7237
|
+
return (0, import_node_path22.join)(appDataDir(), "brightsy-teams.json");
|
|
7063
7238
|
}
|
|
7064
7239
|
function readStore4() {
|
|
7065
7240
|
const path = storePath4();
|
|
7066
|
-
if (!(0,
|
|
7241
|
+
if (!(0, import_node_fs19.existsSync)(path)) return [];
|
|
7067
7242
|
try {
|
|
7068
|
-
const parsed = JSON.parse((0,
|
|
7243
|
+
const parsed = JSON.parse((0, import_node_fs19.readFileSync)(path, "utf8"));
|
|
7069
7244
|
return Array.isArray(parsed.teams) ? parsed.teams : [];
|
|
7070
7245
|
} catch {
|
|
7071
7246
|
return [];
|
|
7072
7247
|
}
|
|
7073
7248
|
}
|
|
7074
7249
|
function writeStore2(teams) {
|
|
7075
|
-
(0,
|
|
7250
|
+
(0, import_node_fs19.mkdirSync)(appDataDir(), { recursive: true });
|
|
7076
7251
|
const path = storePath4();
|
|
7077
|
-
(0,
|
|
7252
|
+
(0, import_node_fs19.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
|
|
7078
7253
|
`, {
|
|
7079
7254
|
mode: 384
|
|
7080
7255
|
});
|
|
@@ -7180,12 +7355,12 @@ function brightsyMcpServerName(slug) {
|
|
|
7180
7355
|
const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
|
|
7181
7356
|
return `brightsy_${cleaned || "team"}`;
|
|
7182
7357
|
}
|
|
7183
|
-
var
|
|
7358
|
+
var import_node_fs19, import_node_path22;
|
|
7184
7359
|
var init_connected_teams = __esm({
|
|
7185
7360
|
"src/brightsy/connected-teams.ts"() {
|
|
7186
7361
|
"use strict";
|
|
7187
|
-
|
|
7188
|
-
|
|
7362
|
+
import_node_fs19 = require("fs");
|
|
7363
|
+
import_node_path22 = require("path");
|
|
7189
7364
|
init_paths();
|
|
7190
7365
|
init_accounts();
|
|
7191
7366
|
init_config();
|
|
@@ -7557,11 +7732,11 @@ async function syncCliForTarget(accountId) {
|
|
|
7557
7732
|
}
|
|
7558
7733
|
applyConnectedTeamToCli(team);
|
|
7559
7734
|
}
|
|
7560
|
-
var
|
|
7735
|
+
var import_node_fs20, brightsyAdapter;
|
|
7561
7736
|
var init_brightsy = __esm({
|
|
7562
7737
|
"src/agents/brightsy.ts"() {
|
|
7563
7738
|
"use strict";
|
|
7564
|
-
|
|
7739
|
+
import_node_fs20 = require("fs");
|
|
7565
7740
|
init_run();
|
|
7566
7741
|
init_connected_teams();
|
|
7567
7742
|
init_config();
|
|
@@ -7576,7 +7751,7 @@ var init_brightsy = __esm({
|
|
|
7576
7751
|
async detect() {
|
|
7577
7752
|
const brightsy = resolveAgentExecutable("brightsy");
|
|
7578
7753
|
if (brightsy !== "brightsy") {
|
|
7579
|
-
if (!(0,
|
|
7754
|
+
if (!(0, import_node_fs20.existsSync)(brightsy)) {
|
|
7580
7755
|
return {
|
|
7581
7756
|
agent: "brightsy",
|
|
7582
7757
|
installed: false,
|
|
@@ -7807,6 +7982,13 @@ function isSubagentToolName(name) {
|
|
|
7807
7982
|
if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
|
|
7808
7983
|
return /connectedAgentRequest/i.test(n);
|
|
7809
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
|
+
}
|
|
7810
7992
|
function isPollWrapperToolName(name) {
|
|
7811
7993
|
const n = (name ?? "").replace(/[_-]/g, "");
|
|
7812
7994
|
return /^(taskoutput|taskstop|sleep)$/i.test(n);
|
|
@@ -7814,7 +7996,10 @@ function isPollWrapperToolName(name) {
|
|
|
7814
7996
|
function lastTextPart(parts, type) {
|
|
7815
7997
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
7816
7998
|
const p = parts[i];
|
|
7817
|
-
if (p.type
|
|
7999
|
+
if (p.type !== type) continue;
|
|
8000
|
+
const text5 = p.text.trim();
|
|
8001
|
+
if (!text5 || isInternalAgentStatusText(text5)) continue;
|
|
8002
|
+
return text5;
|
|
7818
8003
|
}
|
|
7819
8004
|
return "";
|
|
7820
8005
|
}
|
|
@@ -8151,43 +8336,43 @@ function electronResourcesPath() {
|
|
|
8151
8336
|
function packagedCursorRuntimeDir() {
|
|
8152
8337
|
const resources = electronResourcesPath();
|
|
8153
8338
|
if (!resources) return null;
|
|
8154
|
-
const dir = (0,
|
|
8155
|
-
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;
|
|
8156
8341
|
return dir;
|
|
8157
8342
|
}
|
|
8158
8343
|
function packagedCursorRunnerPath() {
|
|
8159
8344
|
const dir = packagedCursorRuntimeDir();
|
|
8160
|
-
return dir ? (0,
|
|
8345
|
+
return dir ? (0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
8161
8346
|
}
|
|
8162
8347
|
function packagedMcpDir() {
|
|
8163
8348
|
const resources = electronResourcesPath();
|
|
8164
8349
|
if (!resources) return null;
|
|
8165
|
-
const dir = (0,
|
|
8166
|
-
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;
|
|
8167
8352
|
return dir;
|
|
8168
8353
|
}
|
|
8169
8354
|
function packagedMcpStdioPath() {
|
|
8170
8355
|
const dir = packagedMcpDir();
|
|
8171
|
-
return dir ? (0,
|
|
8356
|
+
return dir ? (0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
8172
8357
|
}
|
|
8173
8358
|
function packagedBundledNodePath() {
|
|
8174
8359
|
const resources = electronResourcesPath();
|
|
8175
8360
|
if (!resources) return null;
|
|
8176
|
-
const bin = (0,
|
|
8177
|
-
if (!(0,
|
|
8361
|
+
const bin = (0, import_node_path23.join)(resources, "node", "bin", "node");
|
|
8362
|
+
if (!(0, import_node_fs21.existsSync)(bin)) return null;
|
|
8178
8363
|
return bin;
|
|
8179
8364
|
}
|
|
8180
8365
|
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
8181
8366
|
const dir = packagedCursorRuntimeDir();
|
|
8182
8367
|
if (!dir) return null;
|
|
8183
|
-
return (0,
|
|
8368
|
+
return (0, import_node_path23.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
8184
8369
|
}
|
|
8185
|
-
var
|
|
8370
|
+
var import_node_fs21, import_node_path23;
|
|
8186
8371
|
var init_packaged_runtime = __esm({
|
|
8187
8372
|
"src/agents/packaged-runtime.ts"() {
|
|
8188
8373
|
"use strict";
|
|
8189
|
-
|
|
8190
|
-
|
|
8374
|
+
import_node_fs21 = require("fs");
|
|
8375
|
+
import_node_path23 = require("path");
|
|
8191
8376
|
}
|
|
8192
8377
|
});
|
|
8193
8378
|
|
|
@@ -8221,7 +8406,7 @@ function unpackedAsarPath(filePath) {
|
|
|
8221
8406
|
if (!isAsarPath(filePath)) return null;
|
|
8222
8407
|
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
8223
8408
|
if (unpacked === filePath) return null;
|
|
8224
|
-
return (0,
|
|
8409
|
+
return (0, import_node_fs22.existsSync)(unpacked) ? unpacked : null;
|
|
8225
8410
|
}
|
|
8226
8411
|
function nodeReadableScriptPath(scriptPath) {
|
|
8227
8412
|
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
@@ -8261,37 +8446,37 @@ function pickPreferredNode(candidates) {
|
|
|
8261
8446
|
return best;
|
|
8262
8447
|
}
|
|
8263
8448
|
function versionDirNodeBins(root, toBin) {
|
|
8264
|
-
if (!(0,
|
|
8449
|
+
if (!(0, import_node_fs22.existsSync)(root)) return [];
|
|
8265
8450
|
try {
|
|
8266
|
-
return (0,
|
|
8451
|
+
return (0, import_node_fs22.readdirSync)(root).map(toBin);
|
|
8267
8452
|
} catch {
|
|
8268
8453
|
return [];
|
|
8269
8454
|
}
|
|
8270
8455
|
}
|
|
8271
|
-
function defaultNodeBinCandidates(home = (0,
|
|
8456
|
+
function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
|
|
8272
8457
|
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
8273
|
-
(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"))
|
|
8274
8459
|
);
|
|
8275
8460
|
return [
|
|
8276
8461
|
...kegs,
|
|
8277
8462
|
"/opt/homebrew/bin/node",
|
|
8278
8463
|
"/usr/local/bin/node",
|
|
8279
|
-
(0,
|
|
8280
|
-
(0,
|
|
8281
|
-
(0,
|
|
8282
|
-
(0,
|
|
8283
|
-
(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"),
|
|
8284
8469
|
...versionDirNodeBins(
|
|
8285
|
-
(0,
|
|
8286
|
-
(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")
|
|
8287
8472
|
),
|
|
8288
8473
|
...versionDirNodeBins(
|
|
8289
|
-
(0,
|
|
8290
|
-
(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")
|
|
8291
8476
|
),
|
|
8292
8477
|
...versionDirNodeBins(
|
|
8293
|
-
(0,
|
|
8294
|
-
(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")
|
|
8295
8480
|
)
|
|
8296
8481
|
];
|
|
8297
8482
|
}
|
|
@@ -8300,10 +8485,10 @@ function uniqueExistingNodeBins(paths) {
|
|
|
8300
8485
|
const out = [];
|
|
8301
8486
|
for (const raw of paths) {
|
|
8302
8487
|
const p = raw.trim();
|
|
8303
|
-
if (!p || !(0,
|
|
8488
|
+
if (!p || !(0, import_node_fs22.existsSync)(p) || isElectronLikeCommand(p)) continue;
|
|
8304
8489
|
let key = p;
|
|
8305
8490
|
try {
|
|
8306
|
-
key = (0,
|
|
8491
|
+
key = (0, import_node_fs22.realpathSync)(p);
|
|
8307
8492
|
} catch {
|
|
8308
8493
|
continue;
|
|
8309
8494
|
}
|
|
@@ -8383,13 +8568,13 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
8383
8568
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
8384
8569
|
};
|
|
8385
8570
|
}
|
|
8386
|
-
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;
|
|
8387
8572
|
var init_node_launch = __esm({
|
|
8388
8573
|
"src/agents/node-launch.ts"() {
|
|
8389
8574
|
"use strict";
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8575
|
+
import_node_fs22 = require("fs");
|
|
8576
|
+
import_node_os8 = require("os");
|
|
8577
|
+
import_node_path24 = require("path");
|
|
8393
8578
|
init_nested_electron_env();
|
|
8394
8579
|
init_run();
|
|
8395
8580
|
init_packaged_runtime();
|
|
@@ -8483,37 +8668,37 @@ function corePackageDir() {
|
|
|
8483
8668
|
try {
|
|
8484
8669
|
const url = import_meta.url;
|
|
8485
8670
|
if (typeof url === "string" && url.length > 0) {
|
|
8486
|
-
return (0,
|
|
8671
|
+
return (0, import_node_path25.dirname)((0, import_node_url.fileURLToPath)(url));
|
|
8487
8672
|
}
|
|
8488
8673
|
} catch {
|
|
8489
8674
|
}
|
|
8490
8675
|
try {
|
|
8491
|
-
const req = (0, import_node_module.createRequire)((0,
|
|
8492
|
-
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"));
|
|
8493
8678
|
} catch {
|
|
8494
8679
|
return process.cwd();
|
|
8495
8680
|
}
|
|
8496
8681
|
}
|
|
8497
8682
|
function findSideboardMcpJsEntry() {
|
|
8498
8683
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
8499
|
-
if (override && (0,
|
|
8684
|
+
if (override && (0, import_node_fs23.existsSync)(override)) return override;
|
|
8500
8685
|
const packaged = packagedMcpStdioPath();
|
|
8501
8686
|
if (packaged) return packaged;
|
|
8502
8687
|
let dir = corePackageDir();
|
|
8503
8688
|
for (let i = 0; i < 10; i++) {
|
|
8504
8689
|
const candidates = [
|
|
8505
|
-
(0,
|
|
8506
|
-
(0,
|
|
8507
|
-
(0,
|
|
8508
|
-
(0,
|
|
8509
|
-
(0,
|
|
8510
|
-
(0,
|
|
8511
|
-
(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")
|
|
8512
8697
|
];
|
|
8513
8698
|
for (const p of candidates) {
|
|
8514
|
-
if ((0,
|
|
8699
|
+
if ((0, import_node_fs23.existsSync)(p) && !isAsarPath(p)) return p;
|
|
8515
8700
|
}
|
|
8516
|
-
const parent = (0,
|
|
8701
|
+
const parent = (0, import_node_path25.dirname)(dir);
|
|
8517
8702
|
if (parent === dir) break;
|
|
8518
8703
|
dir = parent;
|
|
8519
8704
|
}
|
|
@@ -8655,19 +8840,19 @@ function writeMcpServersConfig(servers) {
|
|
|
8655
8840
|
...env ? { env } : {}
|
|
8656
8841
|
};
|
|
8657
8842
|
}
|
|
8658
|
-
const dir = (0,
|
|
8659
|
-
const cfgPath = (0,
|
|
8660
|
-
(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));
|
|
8661
8846
|
return cfgPath;
|
|
8662
8847
|
}
|
|
8663
|
-
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;
|
|
8664
8849
|
var init_injected_mcp = __esm({
|
|
8665
8850
|
"src/agents/injected-mcp.ts"() {
|
|
8666
8851
|
"use strict";
|
|
8667
|
-
|
|
8852
|
+
import_node_fs23 = require("fs");
|
|
8668
8853
|
import_node_module = require("module");
|
|
8669
|
-
|
|
8670
|
-
|
|
8854
|
+
import_node_os9 = require("os");
|
|
8855
|
+
import_node_path25 = require("path");
|
|
8671
8856
|
import_node_url = require("url");
|
|
8672
8857
|
init_run();
|
|
8673
8858
|
init_config();
|
|
@@ -9006,11 +9191,11 @@ function parseIssuesJson(raw) {
|
|
|
9006
9191
|
}
|
|
9007
9192
|
return [];
|
|
9008
9193
|
}
|
|
9009
|
-
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;
|
|
9010
9195
|
var init_claude = __esm({
|
|
9011
9196
|
"src/agents/claude.ts"() {
|
|
9012
9197
|
"use strict";
|
|
9013
|
-
|
|
9198
|
+
import_node_fs24 = require("fs");
|
|
9014
9199
|
init_run();
|
|
9015
9200
|
init_app_settings();
|
|
9016
9201
|
init_claude_mcp();
|
|
@@ -9050,7 +9235,7 @@ var init_claude = __esm({
|
|
|
9050
9235
|
async detect() {
|
|
9051
9236
|
const claude = resolveClaudeExecutable();
|
|
9052
9237
|
if (claude !== "claude") {
|
|
9053
|
-
if (!(0,
|
|
9238
|
+
if (!(0, import_node_fs24.existsSync)(claude)) {
|
|
9054
9239
|
return {
|
|
9055
9240
|
agent: "claude",
|
|
9056
9241
|
installed: false,
|
|
@@ -9305,7 +9490,7 @@ async function listCodexModels() {
|
|
|
9305
9490
|
if (codex === "codex") {
|
|
9306
9491
|
const which = await run("which", ["codex"], { reject: false });
|
|
9307
9492
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
9308
|
-
} else if (!(0,
|
|
9493
|
+
} else if (!(0, import_node_fs25.existsSync)(codex)) {
|
|
9309
9494
|
return FALLBACK_CODEX_MODELS;
|
|
9310
9495
|
}
|
|
9311
9496
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -9340,12 +9525,12 @@ function usageFromCodex(usage) {
|
|
|
9340
9525
|
}
|
|
9341
9526
|
function codexConfigHasNetworkAccess() {
|
|
9342
9527
|
const candidates = [
|
|
9343
|
-
(0,
|
|
9344
|
-
(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")
|
|
9345
9530
|
];
|
|
9346
9531
|
for (const path of candidates) {
|
|
9347
|
-
if (!(0,
|
|
9348
|
-
const text5 = (0,
|
|
9532
|
+
if (!(0, import_node_fs25.existsSync)(path)) continue;
|
|
9533
|
+
const text5 = (0, import_node_fs25.readFileSync)(path, "utf8");
|
|
9349
9534
|
if (/network_access\s*=\s*true/.test(text5)) return true;
|
|
9350
9535
|
}
|
|
9351
9536
|
return false;
|
|
@@ -9377,21 +9562,21 @@ function asRecord2(value) {
|
|
|
9377
9562
|
return void 0;
|
|
9378
9563
|
}
|
|
9379
9564
|
function codexLooksAuthenticated() {
|
|
9380
|
-
const authPath = (0,
|
|
9381
|
-
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;
|
|
9382
9567
|
try {
|
|
9383
|
-
return (0,
|
|
9568
|
+
return (0, import_node_fs25.statSync)(authPath).size > 2;
|
|
9384
9569
|
} catch {
|
|
9385
9570
|
return false;
|
|
9386
9571
|
}
|
|
9387
9572
|
}
|
|
9388
|
-
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;
|
|
9389
9574
|
var init_codex = __esm({
|
|
9390
9575
|
"src/agents/codex.ts"() {
|
|
9391
9576
|
"use strict";
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9577
|
+
import_node_fs25 = require("fs");
|
|
9578
|
+
import_node_os10 = require("os");
|
|
9579
|
+
import_node_path26 = require("path");
|
|
9395
9580
|
init_run();
|
|
9396
9581
|
init_app_settings();
|
|
9397
9582
|
init_global_workspace();
|
|
@@ -9416,7 +9601,7 @@ var init_codex = __esm({
|
|
|
9416
9601
|
async detect() {
|
|
9417
9602
|
const codex = resolveAgentExecutable("codex");
|
|
9418
9603
|
if (codex !== "codex") {
|
|
9419
|
-
if (!(0,
|
|
9604
|
+
if (!(0, import_node_fs25.existsSync)(codex)) {
|
|
9420
9605
|
return {
|
|
9421
9606
|
agent: "codex",
|
|
9422
9607
|
installed: false,
|
|
@@ -9903,21 +10088,21 @@ function platformRipgrepPackage() {
|
|
|
9903
10088
|
}
|
|
9904
10089
|
function usableRipgrepPath(candidate) {
|
|
9905
10090
|
const raw = candidate?.trim();
|
|
9906
|
-
if (!raw || !(0,
|
|
10091
|
+
if (!raw || !(0, import_node_path27.isAbsolute)(raw)) return null;
|
|
9907
10092
|
const readable = nodeReadableScriptPath(raw);
|
|
9908
|
-
if (!(0,
|
|
10093
|
+
if (!(0, import_node_fs26.existsSync)(readable) || isAsarPath(readable)) return null;
|
|
9909
10094
|
return readable;
|
|
9910
10095
|
}
|
|
9911
10096
|
function walkForBundledRipgrep(startFile) {
|
|
9912
10097
|
if (!startFile) return null;
|
|
9913
10098
|
const pkg = platformRipgrepPackage();
|
|
9914
10099
|
const name = rgBinaryName();
|
|
9915
|
-
let dir = (0,
|
|
9916
|
-
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;
|
|
9917
10102
|
while (dir !== root) {
|
|
9918
|
-
const hit = usableRipgrepPath((0,
|
|
10103
|
+
const hit = usableRipgrepPath((0, import_node_path27.join)(dir, "node_modules", pkg, "bin", name));
|
|
9919
10104
|
if (hit) return hit;
|
|
9920
|
-
const next = (0,
|
|
10105
|
+
const next = (0, import_node_path27.dirname)(dir);
|
|
9921
10106
|
if (next === dir) break;
|
|
9922
10107
|
dir = next;
|
|
9923
10108
|
}
|
|
@@ -9927,7 +10112,7 @@ function requireResolveBundledRipgrep(fromFile) {
|
|
|
9927
10112
|
try {
|
|
9928
10113
|
const req = (0, import_node_module2.createRequire)(fromFile);
|
|
9929
10114
|
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
9930
|
-
return usableRipgrepPath((0,
|
|
10115
|
+
return usableRipgrepPath((0, import_node_path27.join)((0, import_node_path27.dirname)(pkgJson), "bin", rgBinaryName()));
|
|
9931
10116
|
} catch {
|
|
9932
10117
|
return null;
|
|
9933
10118
|
}
|
|
@@ -9949,13 +10134,13 @@ function cursorRipgrepEnv(opts) {
|
|
|
9949
10134
|
const path = resolveCursorRipgrepPath(opts);
|
|
9950
10135
|
return path ? { [RIPGREP_ENV]: path } : {};
|
|
9951
10136
|
}
|
|
9952
|
-
var
|
|
10137
|
+
var import_node_fs26, import_node_module2, import_node_path27, RIPGREP_ENV;
|
|
9953
10138
|
var init_cursor_ripgrep = __esm({
|
|
9954
10139
|
"src/agents/cursor-ripgrep.ts"() {
|
|
9955
10140
|
"use strict";
|
|
9956
|
-
|
|
10141
|
+
import_node_fs26 = require("fs");
|
|
9957
10142
|
import_node_module2 = require("module");
|
|
9958
|
-
|
|
10143
|
+
import_node_path27 = require("path");
|
|
9959
10144
|
init_node_launch();
|
|
9960
10145
|
init_packaged_runtime();
|
|
9961
10146
|
RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
@@ -10001,11 +10186,11 @@ function entryDir() {
|
|
|
10001
10186
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
10002
10187
|
if (cjsDir) return cjsDir;
|
|
10003
10188
|
try {
|
|
10004
|
-
return (0,
|
|
10189
|
+
return (0, import_node_path28.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
|
|
10005
10190
|
} catch {
|
|
10006
10191
|
try {
|
|
10007
10192
|
const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
|
|
10008
|
-
return (0,
|
|
10193
|
+
return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
|
|
10009
10194
|
} catch {
|
|
10010
10195
|
return process.cwd();
|
|
10011
10196
|
}
|
|
@@ -10016,27 +10201,27 @@ function cursorRunnerPath() {
|
|
|
10016
10201
|
if (packaged) return packaged;
|
|
10017
10202
|
const root = entryDir();
|
|
10018
10203
|
const candidates = [
|
|
10019
|
-
(0,
|
|
10020
|
-
(0,
|
|
10204
|
+
(0, import_node_path28.join)(root, "agents", "cursor-runner.js"),
|
|
10205
|
+
(0, import_node_path28.join)(root, "agents", "cursor-runner.cjs"),
|
|
10021
10206
|
// If somehow resolved from package root instead of dist/
|
|
10022
|
-
(0,
|
|
10023
|
-
(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"),
|
|
10024
10209
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
10025
|
-
(0,
|
|
10026
|
-
(0,
|
|
10210
|
+
(0, import_node_path28.join)(root, "cursor-runner.ts"),
|
|
10211
|
+
(0, import_node_path28.join)(root, "src", "agents", "cursor-runner.ts")
|
|
10027
10212
|
];
|
|
10028
10213
|
for (const candidate of candidates) {
|
|
10029
|
-
if ((0,
|
|
10214
|
+
if ((0, import_node_fs27.existsSync)(candidate)) return candidate;
|
|
10030
10215
|
}
|
|
10031
10216
|
return candidates[0];
|
|
10032
10217
|
}
|
|
10033
|
-
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;
|
|
10034
10219
|
var init_cursor = __esm({
|
|
10035
10220
|
"src/agents/cursor.ts"() {
|
|
10036
10221
|
"use strict";
|
|
10037
|
-
|
|
10222
|
+
import_node_fs27 = require("fs");
|
|
10038
10223
|
import_node_module3 = require("module");
|
|
10039
|
-
|
|
10224
|
+
import_node_path28 = require("path");
|
|
10040
10225
|
import_node_url2 = require("url");
|
|
10041
10226
|
import_sdk = require("@cursor/sdk");
|
|
10042
10227
|
init_run();
|
|
@@ -10187,7 +10372,7 @@ async function listOpencodeModels() {
|
|
|
10187
10372
|
if (opencode === "opencode") {
|
|
10188
10373
|
const which = await run("which", ["opencode"], { reject: false });
|
|
10189
10374
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
10190
|
-
} else if (!(0,
|
|
10375
|
+
} else if (!(0, import_node_fs28.existsSync)(opencode)) {
|
|
10191
10376
|
return FALLBACK_OPENCODE_MODELS;
|
|
10192
10377
|
}
|
|
10193
10378
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -10217,11 +10402,11 @@ function usageFromOpencode(tokens) {
|
|
|
10217
10402
|
cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
|
|
10218
10403
|
};
|
|
10219
10404
|
}
|
|
10220
|
-
var
|
|
10405
|
+
var import_node_fs28, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
|
|
10221
10406
|
var init_opencode = __esm({
|
|
10222
10407
|
"src/agents/opencode.ts"() {
|
|
10223
10408
|
"use strict";
|
|
10224
|
-
|
|
10409
|
+
import_node_fs28 = require("fs");
|
|
10225
10410
|
init_run();
|
|
10226
10411
|
init_app_settings();
|
|
10227
10412
|
init_global_workspace();
|
|
@@ -10248,7 +10433,7 @@ var init_opencode = __esm({
|
|
|
10248
10433
|
async detect() {
|
|
10249
10434
|
const opencode = resolveAgentExecutable("opencode");
|
|
10250
10435
|
if (opencode !== "opencode") {
|
|
10251
|
-
if (!(0,
|
|
10436
|
+
if (!(0, import_node_fs28.existsSync)(opencode)) {
|
|
10252
10437
|
return {
|
|
10253
10438
|
agent: "opencode",
|
|
10254
10439
|
installed: false,
|
|
@@ -11849,7 +12034,7 @@ function forkMessageSlice(from, throughIndex) {
|
|
|
11849
12034
|
function buildForkTranscriptAttachment(baseTitle, messages) {
|
|
11850
12035
|
const title = baseTitle || "Chat";
|
|
11851
12036
|
return {
|
|
11852
|
-
id: (0,
|
|
12037
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
11853
12038
|
name: `Transcript of ${title}.md`,
|
|
11854
12039
|
kind: "transcript",
|
|
11855
12040
|
content: formatTranscriptMarkdown(title, messages)
|
|
@@ -11906,11 +12091,11 @@ function forkChatTab(input) {
|
|
|
11906
12091
|
}
|
|
11907
12092
|
return tab;
|
|
11908
12093
|
}
|
|
11909
|
-
var
|
|
12094
|
+
var import_node_crypto6;
|
|
11910
12095
|
var init_chat_tabs = __esm({
|
|
11911
12096
|
"src/threads/chat-tabs.ts"() {
|
|
11912
12097
|
"use strict";
|
|
11913
|
-
|
|
12098
|
+
import_node_crypto6 = require("crypto");
|
|
11914
12099
|
init_context_compact();
|
|
11915
12100
|
init_teams();
|
|
11916
12101
|
init_worktree_labels();
|
|
@@ -12080,21 +12265,21 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
12080
12265
|
return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
|
|
12081
12266
|
}
|
|
12082
12267
|
function readTextIfPresent(abs) {
|
|
12083
|
-
if (!(0,
|
|
12268
|
+
if (!(0, import_node_fs29.existsSync)(abs)) return null;
|
|
12084
12269
|
try {
|
|
12085
|
-
const content = (0,
|
|
12270
|
+
const content = (0, import_node_fs29.readFileSync)(abs, "utf8");
|
|
12086
12271
|
return content.trim() ? content : null;
|
|
12087
12272
|
} catch {
|
|
12088
12273
|
return null;
|
|
12089
12274
|
}
|
|
12090
12275
|
}
|
|
12091
12276
|
function readLocalGuidelines(worktreePath) {
|
|
12092
|
-
const localAbs = (0,
|
|
12277
|
+
const localAbs = (0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
12093
12278
|
const localContent = readTextIfPresent(localAbs);
|
|
12094
12279
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
12095
12280
|
return { path: REVIEW_REQUEST_PATH, content: localContent };
|
|
12096
12281
|
}
|
|
12097
|
-
const legacyAbs = (0,
|
|
12282
|
+
const legacyAbs = (0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
12098
12283
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
12099
12284
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
12100
12285
|
return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
|
|
@@ -12110,20 +12295,20 @@ function skillGuidelines(content, source) {
|
|
|
12110
12295
|
};
|
|
12111
12296
|
}
|
|
12112
12297
|
function ensureReviewSkillFile(worktreePath) {
|
|
12113
|
-
const abs = (0,
|
|
12298
|
+
const abs = (0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH);
|
|
12114
12299
|
const existing = readTextIfPresent(abs);
|
|
12115
12300
|
if (existing) {
|
|
12116
12301
|
return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
|
|
12117
12302
|
}
|
|
12118
|
-
const fromRepo = readTextIfPresent((0,
|
|
12303
|
+
const fromRepo = readTextIfPresent((0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH));
|
|
12119
12304
|
const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
|
|
12120
12305
|
const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
|
|
12121
|
-
(0,
|
|
12122
|
-
(0,
|
|
12306
|
+
(0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(abs), { recursive: true });
|
|
12307
|
+
(0, import_node_fs29.writeFileSync)(abs, content, "utf8");
|
|
12123
12308
|
return { path: REVIEW_SKILL_PATH, content, wrote: true };
|
|
12124
12309
|
}
|
|
12125
12310
|
function resolveReviewGuidelines(worktreePath) {
|
|
12126
|
-
const skillContent = readTextIfPresent((0,
|
|
12311
|
+
const skillContent = readTextIfPresent((0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH));
|
|
12127
12312
|
if (skillContent) return skillGuidelines(skillContent, "skill");
|
|
12128
12313
|
const local = readLocalGuidelines(worktreePath);
|
|
12129
12314
|
if (local) {
|
|
@@ -12141,7 +12326,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
12141
12326
|
const path = opts?.path ?? REVIEW_SKILL_PATH;
|
|
12142
12327
|
const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
12143
12328
|
return {
|
|
12144
|
-
id: (0,
|
|
12329
|
+
id: (0, import_node_crypto7.randomUUID)(),
|
|
12145
12330
|
name,
|
|
12146
12331
|
kind: "file",
|
|
12147
12332
|
path,
|
|
@@ -12173,13 +12358,13 @@ async function requestReview(threadRef, send) {
|
|
|
12173
12358
|
const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
|
|
12174
12359
|
return { tab: started, from };
|
|
12175
12360
|
}
|
|
12176
|
-
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;
|
|
12177
12362
|
var init_request_review = __esm({
|
|
12178
12363
|
"src/review/request-review.ts"() {
|
|
12179
12364
|
"use strict";
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12365
|
+
import_node_crypto7 = require("crypto");
|
|
12366
|
+
import_node_fs29 = require("fs");
|
|
12367
|
+
import_node_path29 = require("path");
|
|
12183
12368
|
init_global_workspace();
|
|
12184
12369
|
init_chat_tabs();
|
|
12185
12370
|
init_thread_store();
|
|
@@ -12204,9 +12389,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
12204
12389
|
return new RegExp(`^${escaped}$`).test(name);
|
|
12205
12390
|
}
|
|
12206
12391
|
function readWorktreeInclude(repoPath) {
|
|
12207
|
-
const path = (0,
|
|
12208
|
-
if (!(0,
|
|
12209
|
-
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("#"));
|
|
12210
12395
|
}
|
|
12211
12396
|
function resolveFilesToCopy(repoPath) {
|
|
12212
12397
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -12216,10 +12401,10 @@ function resolveFilesToCopy(repoPath) {
|
|
|
12216
12401
|
if (settings?.fileIncludeGlobs?.length) {
|
|
12217
12402
|
const matched = [];
|
|
12218
12403
|
try {
|
|
12219
|
-
for (const entry of (0,
|
|
12404
|
+
for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
12220
12405
|
if (!entry.isFile()) continue;
|
|
12221
12406
|
for (const glob of settings.fileIncludeGlobs) {
|
|
12222
|
-
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0,
|
|
12407
|
+
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path30.basename)(glob), entry.name)) {
|
|
12223
12408
|
matched.push(entry.name);
|
|
12224
12409
|
break;
|
|
12225
12410
|
}
|
|
@@ -12231,7 +12416,7 @@ function resolveFilesToCopy(repoPath) {
|
|
|
12231
12416
|
}
|
|
12232
12417
|
const defaults = [];
|
|
12233
12418
|
try {
|
|
12234
|
-
for (const entry of (0,
|
|
12419
|
+
for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
12235
12420
|
if (entry.isFile() && entry.name.startsWith(".env")) {
|
|
12236
12421
|
defaults.push(entry.name);
|
|
12237
12422
|
}
|
|
@@ -12245,11 +12430,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
|
|
|
12245
12430
|
const patterns = resolveFilesToCopy(repoPath);
|
|
12246
12431
|
const copied = [];
|
|
12247
12432
|
for (const rel of patterns) {
|
|
12248
|
-
const src = (0,
|
|
12249
|
-
if (!(0,
|
|
12250
|
-
const dest = (0,
|
|
12251
|
-
(0,
|
|
12252
|
-
(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);
|
|
12253
12438
|
copied.push(rel);
|
|
12254
12439
|
}
|
|
12255
12440
|
return copied;
|
|
@@ -12284,7 +12469,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
|
12284
12469
|
const env = stripNestedElectronEnv({
|
|
12285
12470
|
...baseEnv ?? process.env
|
|
12286
12471
|
});
|
|
12287
|
-
const name = opts.workspaceName ?? (0,
|
|
12472
|
+
const name = opts.workspaceName ?? (0, import_node_path30.basename)(opts.worktreePath);
|
|
12288
12473
|
const ports = opts.ports ?? [];
|
|
12289
12474
|
const primary = ports[0];
|
|
12290
12475
|
env.SIDEBOARD_WORKSPACE_NAME = name;
|
|
@@ -12439,6 +12624,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
|
|
|
12439
12624
|
};
|
|
12440
12625
|
}
|
|
12441
12626
|
async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
|
|
12627
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
12442
12628
|
const reviewSkill = ensureReviewSkillFile(worktreePath);
|
|
12443
12629
|
if (reviewSkill.wrote) {
|
|
12444
12630
|
onLine?.(
|
|
@@ -12545,13 +12731,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
|
|
|
12545
12731
|
done: handle.done
|
|
12546
12732
|
};
|
|
12547
12733
|
}
|
|
12548
|
-
var
|
|
12734
|
+
var import_node_fs30, import_node_net, import_node_path30, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
|
|
12549
12735
|
var init_conductor = __esm({
|
|
12550
12736
|
"src/hook/conductor.ts"() {
|
|
12551
12737
|
"use strict";
|
|
12552
|
-
|
|
12738
|
+
import_node_fs30 = require("fs");
|
|
12553
12739
|
import_node_net = require("net");
|
|
12554
|
-
|
|
12740
|
+
import_node_path30 = require("path");
|
|
12555
12741
|
import_execa4 = require("execa");
|
|
12556
12742
|
import_node_readline3 = require("readline");
|
|
12557
12743
|
init_settings();
|
|
@@ -12560,6 +12746,7 @@ var init_conductor = __esm({
|
|
|
12560
12746
|
init_cursor_worktrees();
|
|
12561
12747
|
init_git_auth_mode();
|
|
12562
12748
|
init_request_review();
|
|
12749
|
+
init_worktree_exclude();
|
|
12563
12750
|
init_nested_electron_env();
|
|
12564
12751
|
PORT_RANGE_SIZE = 10;
|
|
12565
12752
|
cachedLoginEnv = null;
|
|
@@ -12577,9 +12764,9 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
12577
12764
|
repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
|
|
12578
12765
|
);
|
|
12579
12766
|
const homeRoot = sideboardWorkspacesDir();
|
|
12580
|
-
if ((0,
|
|
12767
|
+
if ((0, import_node_fs31.existsSync)(homeRoot)) {
|
|
12581
12768
|
try {
|
|
12582
|
-
for (const entry of (0,
|
|
12769
|
+
for (const entry of (0, import_node_fs31.readdirSync)(homeRoot, { withFileTypes: true })) {
|
|
12583
12770
|
if (!entry.isDirectory()) continue;
|
|
12584
12771
|
void entry;
|
|
12585
12772
|
}
|
|
@@ -12589,7 +12776,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
12589
12776
|
const orphans = [];
|
|
12590
12777
|
const seen = /* @__PURE__ */ new Set();
|
|
12591
12778
|
for (const repoPath of repos) {
|
|
12592
|
-
if (!repoPath || !(0,
|
|
12779
|
+
if (!repoPath || !(0, import_node_fs31.existsSync)(repoPath)) continue;
|
|
12593
12780
|
try {
|
|
12594
12781
|
const wts = await listWorktrees(repoPath);
|
|
12595
12782
|
for (const wt of wts) {
|
|
@@ -12600,7 +12787,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
12600
12787
|
seen.add(path);
|
|
12601
12788
|
let mtimeMs = 0;
|
|
12602
12789
|
try {
|
|
12603
|
-
mtimeMs = (0,
|
|
12790
|
+
mtimeMs = (0, import_node_fs31.statSync)(path).mtimeMs;
|
|
12604
12791
|
} catch {
|
|
12605
12792
|
mtimeMs = 0;
|
|
12606
12793
|
}
|
|
@@ -12610,16 +12797,16 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
12610
12797
|
}
|
|
12611
12798
|
try {
|
|
12612
12799
|
const root = worktreesRoot(repoPath);
|
|
12613
|
-
if ((0,
|
|
12614
|
-
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 })) {
|
|
12615
12802
|
if (!entry.isDirectory()) continue;
|
|
12616
|
-
const path = (0,
|
|
12803
|
+
const path = (0, import_node_path31.join)(root, entry.name).replace(/\/$/, "");
|
|
12617
12804
|
if (known.has(path) || seen.has(path)) continue;
|
|
12618
|
-
if (!(0,
|
|
12805
|
+
if (!(0, import_node_fs31.existsSync)((0, import_node_path31.join)(path, ".git"))) continue;
|
|
12619
12806
|
seen.add(path);
|
|
12620
12807
|
let mtimeMs = 0;
|
|
12621
12808
|
try {
|
|
12622
|
-
mtimeMs = (0,
|
|
12809
|
+
mtimeMs = (0, import_node_fs31.statSync)(path).mtimeMs;
|
|
12623
12810
|
} catch {
|
|
12624
12811
|
mtimeMs = Date.now();
|
|
12625
12812
|
}
|
|
@@ -12671,12 +12858,12 @@ function shouldRunWorktreeCleanup(settings = loadAppSettings()) {
|
|
|
12671
12858
|
const elapsed = Date.now() - Date.parse(last);
|
|
12672
12859
|
return elapsed >= intervalHours * 36e5;
|
|
12673
12860
|
}
|
|
12674
|
-
var
|
|
12861
|
+
var import_node_fs31, import_node_path31;
|
|
12675
12862
|
var init_orphan_cleanup = __esm({
|
|
12676
12863
|
"src/git/orphan-cleanup.ts"() {
|
|
12677
12864
|
"use strict";
|
|
12678
|
-
|
|
12679
|
-
|
|
12865
|
+
import_node_fs31 = require("fs");
|
|
12866
|
+
import_node_path31 = require("path");
|
|
12680
12867
|
init_worktree();
|
|
12681
12868
|
init_thread_store();
|
|
12682
12869
|
init_paths();
|
|
@@ -12783,38 +12970,38 @@ __export(workspaces_exports, {
|
|
|
12783
12970
|
syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
|
|
12784
12971
|
});
|
|
12785
12972
|
function workspacesFile() {
|
|
12786
|
-
return (0,
|
|
12973
|
+
return (0, import_node_path32.join)(appDataDir(), "workspaces.json");
|
|
12787
12974
|
}
|
|
12788
12975
|
function removedWorkspacesFile() {
|
|
12789
|
-
return (0,
|
|
12976
|
+
return (0, import_node_path32.join)(appDataDir(), "removed-workspaces.json");
|
|
12790
12977
|
}
|
|
12791
12978
|
function readAll() {
|
|
12792
12979
|
const path = workspacesFile();
|
|
12793
|
-
if (!(0,
|
|
12980
|
+
if (!(0, import_node_fs32.existsSync)(path)) return [];
|
|
12794
12981
|
try {
|
|
12795
|
-
const raw = JSON.parse((0,
|
|
12982
|
+
const raw = JSON.parse((0, import_node_fs32.readFileSync)(path, "utf8"));
|
|
12796
12983
|
return Array.isArray(raw) ? raw : [];
|
|
12797
12984
|
} catch {
|
|
12798
12985
|
return [];
|
|
12799
12986
|
}
|
|
12800
12987
|
}
|
|
12801
12988
|
function writeAll(list) {
|
|
12802
|
-
(0,
|
|
12803
|
-
(0,
|
|
12989
|
+
(0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
|
|
12990
|
+
(0, import_node_fs32.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
|
|
12804
12991
|
}
|
|
12805
12992
|
function readRemoved() {
|
|
12806
12993
|
const path = removedWorkspacesFile();
|
|
12807
|
-
if (!(0,
|
|
12994
|
+
if (!(0, import_node_fs32.existsSync)(path)) return /* @__PURE__ */ new Set();
|
|
12808
12995
|
try {
|
|
12809
|
-
const raw = JSON.parse((0,
|
|
12996
|
+
const raw = JSON.parse((0, import_node_fs32.readFileSync)(path, "utf8"));
|
|
12810
12997
|
return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
|
|
12811
12998
|
} catch {
|
|
12812
12999
|
return /* @__PURE__ */ new Set();
|
|
12813
13000
|
}
|
|
12814
13001
|
}
|
|
12815
13002
|
function writeRemoved(paths) {
|
|
12816
|
-
(0,
|
|
12817
|
-
(0,
|
|
13003
|
+
(0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
|
|
13004
|
+
(0, import_node_fs32.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
|
|
12818
13005
|
}
|
|
12819
13006
|
function rememberRemoved(repoPath) {
|
|
12820
13007
|
const next = readRemoved();
|
|
@@ -12837,7 +13024,7 @@ function listWorkspaces() {
|
|
|
12837
13024
|
async function addWorkspace(repoPath) {
|
|
12838
13025
|
const root = await resolveRepoRoot(repoPath);
|
|
12839
13026
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
12840
|
-
if (!(0,
|
|
13027
|
+
if (!(0, import_node_fs32.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
|
|
12841
13028
|
forgetRemoved(root);
|
|
12842
13029
|
await ensureGhPreferOrigin(root);
|
|
12843
13030
|
const current = readAll();
|
|
@@ -12845,7 +13032,7 @@ async function addWorkspace(repoPath) {
|
|
|
12845
13032
|
if (existing) return existing;
|
|
12846
13033
|
const next = {
|
|
12847
13034
|
path: root,
|
|
12848
|
-
name: (0,
|
|
13035
|
+
name: (0, import_node_path32.basename)(root),
|
|
12849
13036
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12850
13037
|
};
|
|
12851
13038
|
writeAll([...current, next]);
|
|
@@ -12867,10 +13054,10 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
12867
13054
|
if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
|
|
12868
13055
|
continue;
|
|
12869
13056
|
}
|
|
12870
|
-
if (!(0,
|
|
13057
|
+
if (!(0, import_node_fs32.existsSync)(path)) continue;
|
|
12871
13058
|
const ws = {
|
|
12872
13059
|
path,
|
|
12873
|
-
name: (0,
|
|
13060
|
+
name: (0, import_node_path32.basename)(path),
|
|
12874
13061
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12875
13062
|
};
|
|
12876
13063
|
byPath.set(path, ws);
|
|
@@ -12880,12 +13067,12 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
12880
13067
|
if (dirty) writeAll(next);
|
|
12881
13068
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
12882
13069
|
}
|
|
12883
|
-
var
|
|
13070
|
+
var import_node_fs32, import_node_path32;
|
|
12884
13071
|
var init_workspaces2 = __esm({
|
|
12885
13072
|
"src/store/workspaces.ts"() {
|
|
12886
13073
|
"use strict";
|
|
12887
|
-
|
|
12888
|
-
|
|
13074
|
+
import_node_fs32 = require("fs");
|
|
13075
|
+
import_node_path32 = require("path");
|
|
12889
13076
|
init_paths();
|
|
12890
13077
|
init_global_workspace();
|
|
12891
13078
|
init_worktree();
|
|
@@ -12898,12 +13085,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
12898
13085
|
if (!url) throw new Error("Clone URL is required");
|
|
12899
13086
|
let name = opts.name?.trim();
|
|
12900
13087
|
if (!name) {
|
|
12901
|
-
const leaf = (0,
|
|
13088
|
+
const leaf = (0, import_node_path33.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
|
|
12902
13089
|
name = leaf || "repo";
|
|
12903
13090
|
}
|
|
12904
13091
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
12905
|
-
const dest = (0,
|
|
12906
|
-
if ((0,
|
|
13092
|
+
const dest = (0, import_node_path33.join)(sideboardReposDir(), name);
|
|
13093
|
+
if ((0, import_node_fs33.existsSync)(dest)) {
|
|
12907
13094
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
12908
13095
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
12909
13096
|
return { repoPath: repoPath2, workspace: workspace2 };
|
|
@@ -12918,12 +13105,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
12918
13105
|
const workspace = await ensureWorkspace(repoPath);
|
|
12919
13106
|
return { repoPath, workspace };
|
|
12920
13107
|
}
|
|
12921
|
-
var
|
|
13108
|
+
var import_node_fs33, import_node_path33, import_execa6;
|
|
12922
13109
|
var init_clone_repo = __esm({
|
|
12923
13110
|
"src/git/clone-repo.ts"() {
|
|
12924
13111
|
"use strict";
|
|
12925
|
-
|
|
12926
|
-
|
|
13112
|
+
import_node_fs33 = require("fs");
|
|
13113
|
+
import_node_path33 = require("path");
|
|
12927
13114
|
import_execa6 = require("execa");
|
|
12928
13115
|
init_paths();
|
|
12929
13116
|
init_workspaces2();
|
|
@@ -12933,11 +13120,11 @@ var init_clone_repo = __esm({
|
|
|
12933
13120
|
|
|
12934
13121
|
// src/store/desktop-host.ts
|
|
12935
13122
|
function desktopHostPidPath() {
|
|
12936
|
-
return (0,
|
|
13123
|
+
return (0, import_node_path34.join)(appDataDir(), "desktop-host.pid");
|
|
12937
13124
|
}
|
|
12938
13125
|
function readDesktopHostPid() {
|
|
12939
13126
|
try {
|
|
12940
|
-
const pid = Number.parseInt((0,
|
|
13127
|
+
const pid = Number.parseInt((0, import_node_fs34.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
|
|
12941
13128
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
12942
13129
|
return pid;
|
|
12943
13130
|
} catch {
|
|
@@ -12963,12 +13150,12 @@ function thisProcessShouldDrainAgentQueues() {
|
|
|
12963
13150
|
if (isThisProcessDesktopHost()) return true;
|
|
12964
13151
|
return !isDesktopHostAlive();
|
|
12965
13152
|
}
|
|
12966
|
-
var
|
|
13153
|
+
var import_node_fs34, import_node_path34;
|
|
12967
13154
|
var init_desktop_host = __esm({
|
|
12968
13155
|
"src/store/desktop-host.ts"() {
|
|
12969
13156
|
"use strict";
|
|
12970
|
-
|
|
12971
|
-
|
|
13157
|
+
import_node_fs34 = require("fs");
|
|
13158
|
+
import_node_path34 = require("path");
|
|
12972
13159
|
init_paths();
|
|
12973
13160
|
}
|
|
12974
13161
|
});
|
|
@@ -13970,7 +14157,7 @@ function persistCreateAttachments(worktreePath, attachments) {
|
|
|
13970
14157
|
}
|
|
13971
14158
|
async function createThread(input, _onSetupLine) {
|
|
13972
14159
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
13973
|
-
if (!(0,
|
|
14160
|
+
if (!(0, import_node_fs35.existsSync)(repoPath)) {
|
|
13974
14161
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
13975
14162
|
}
|
|
13976
14163
|
if (input.reuseExisting !== false) {
|
|
@@ -14145,11 +14332,11 @@ async function listLinearIssues(agent, repoPath) {
|
|
|
14145
14332
|
}
|
|
14146
14333
|
return adapter.listLinearIssues(repoPath);
|
|
14147
14334
|
}
|
|
14148
|
-
var
|
|
14335
|
+
var import_node_fs35;
|
|
14149
14336
|
var init_create = __esm({
|
|
14150
14337
|
"src/threads/create.ts"() {
|
|
14151
14338
|
"use strict";
|
|
14152
|
-
|
|
14339
|
+
import_node_fs35 = require("fs");
|
|
14153
14340
|
init_detect();
|
|
14154
14341
|
init_worktree();
|
|
14155
14342
|
init_home_board();
|
|
@@ -14252,20 +14439,20 @@ function writeTurnLive(threadId, progress) {
|
|
|
14252
14439
|
const path = threadLivePath(threadId);
|
|
14253
14440
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
14254
14441
|
try {
|
|
14255
|
-
(0,
|
|
14256
|
-
(0,
|
|
14442
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
|
|
14443
|
+
(0, import_node_fs36.renameSync)(tmp, path);
|
|
14257
14444
|
} catch {
|
|
14258
14445
|
try {
|
|
14259
|
-
(0,
|
|
14446
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
14260
14447
|
} catch {
|
|
14261
14448
|
}
|
|
14262
14449
|
}
|
|
14263
14450
|
}
|
|
14264
14451
|
function readTurnLive(threadId) {
|
|
14265
14452
|
const path = threadLivePath(threadId);
|
|
14266
|
-
if (!(0,
|
|
14453
|
+
if (!(0, import_node_fs36.existsSync)(path)) return null;
|
|
14267
14454
|
try {
|
|
14268
|
-
const raw = JSON.parse((0,
|
|
14455
|
+
const raw = JSON.parse((0, import_node_fs36.readFileSync)(path, "utf8"));
|
|
14269
14456
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
14270
14457
|
return raw;
|
|
14271
14458
|
} catch {
|
|
@@ -14277,17 +14464,17 @@ function clearTurnLive(threadId) {
|
|
|
14277
14464
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
14278
14465
|
buffers.delete(threadId);
|
|
14279
14466
|
const path = threadLivePath(threadId);
|
|
14280
|
-
if (!(0,
|
|
14467
|
+
if (!(0, import_node_fs36.existsSync)(path)) return;
|
|
14281
14468
|
try {
|
|
14282
|
-
(0,
|
|
14469
|
+
(0, import_node_fs36.unlinkSync)(path);
|
|
14283
14470
|
} catch {
|
|
14284
14471
|
}
|
|
14285
14472
|
}
|
|
14286
|
-
var
|
|
14473
|
+
var import_node_fs36, buffers, FLUSH_MS, MAX_PARTS;
|
|
14287
14474
|
var init_turn_live = __esm({
|
|
14288
14475
|
"src/store/turn-live.ts"() {
|
|
14289
14476
|
"use strict";
|
|
14290
|
-
|
|
14477
|
+
import_node_fs36 = require("fs");
|
|
14291
14478
|
init_message_parts();
|
|
14292
14479
|
init_paths();
|
|
14293
14480
|
buffers = /* @__PURE__ */ new Map();
|
|
@@ -14461,7 +14648,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
14461
14648
|
`- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
|
|
14462
14649
|
].join("\n");
|
|
14463
14650
|
return {
|
|
14464
|
-
id: (0,
|
|
14651
|
+
id: (0, import_node_crypto8.randomUUID)(),
|
|
14465
14652
|
name: "Orchestration quota handoff.md",
|
|
14466
14653
|
kind: "transcript",
|
|
14467
14654
|
content: body
|
|
@@ -14482,11 +14669,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
14482
14669
|
sourceType: "orchestration"
|
|
14483
14670
|
});
|
|
14484
14671
|
}
|
|
14485
|
-
var
|
|
14672
|
+
var import_node_crypto8, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
|
|
14486
14673
|
var init_quota_failover = __esm({
|
|
14487
14674
|
"src/orchestrator/quota-failover.ts"() {
|
|
14488
14675
|
"use strict";
|
|
14489
|
-
|
|
14676
|
+
import_node_crypto8 = require("crypto");
|
|
14490
14677
|
init_session_quota();
|
|
14491
14678
|
init_app_settings();
|
|
14492
14679
|
init_global_workspace();
|
|
@@ -14503,7 +14690,7 @@ var init_quota_failover = __esm({
|
|
|
14503
14690
|
// src/threads/adopt.ts
|
|
14504
14691
|
function thisModuleFile() {
|
|
14505
14692
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
14506
|
-
return cjsFile || process.argv[1] || (0,
|
|
14693
|
+
return cjsFile || process.argv[1] || (0, import_node_path35.join)(process.cwd(), "package.json");
|
|
14507
14694
|
}
|
|
14508
14695
|
function openReadonlySqlite(file) {
|
|
14509
14696
|
const req = (0, import_node_module4.createRequire)(thisModuleFile());
|
|
@@ -14521,21 +14708,21 @@ function mapAgentType(raw) {
|
|
|
14521
14708
|
return null;
|
|
14522
14709
|
}
|
|
14523
14710
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
14524
|
-
if (!workspacePath || !(0,
|
|
14711
|
+
if (!workspacePath || !(0, import_node_fs37.existsSync)(CURSOR_SDK_STORE)) return null;
|
|
14525
14712
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
14526
14713
|
let best = null;
|
|
14527
14714
|
let hashes;
|
|
14528
14715
|
try {
|
|
14529
|
-
hashes = (0,
|
|
14716
|
+
hashes = (0, import_node_fs37.readdirSync)(CURSOR_SDK_STORE);
|
|
14530
14717
|
} catch {
|
|
14531
14718
|
return null;
|
|
14532
14719
|
}
|
|
14533
14720
|
for (const hash of hashes) {
|
|
14534
|
-
const agentsFile = (0,
|
|
14535
|
-
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;
|
|
14536
14723
|
let text5;
|
|
14537
14724
|
try {
|
|
14538
|
-
text5 = (0,
|
|
14725
|
+
text5 = (0, import_node_fs37.readFileSync)(agentsFile, "utf8");
|
|
14539
14726
|
} catch {
|
|
14540
14727
|
continue;
|
|
14541
14728
|
}
|
|
@@ -14559,7 +14746,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
14559
14746
|
return best?.agentId ?? null;
|
|
14560
14747
|
}
|
|
14561
14748
|
async function adoptThread(input) {
|
|
14562
|
-
if (!(0,
|
|
14749
|
+
if (!(0, import_node_fs37.existsSync)(input.worktreePath)) {
|
|
14563
14750
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
14564
14751
|
}
|
|
14565
14752
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -14580,21 +14767,23 @@ async function adoptThread(input) {
|
|
|
14580
14767
|
writeThread(thread);
|
|
14581
14768
|
const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
|
|
14582
14769
|
await ensureWorkspace2(repoPath);
|
|
14770
|
+
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
|
|
14771
|
+
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
14583
14772
|
return thread;
|
|
14584
14773
|
}
|
|
14585
14774
|
function listConductorWorkspaces() {
|
|
14586
|
-
if (!(0,
|
|
14775
|
+
if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
|
|
14587
14776
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
14588
14777
|
}
|
|
14589
|
-
const tmp = (0,
|
|
14590
|
-
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");
|
|
14591
14780
|
try {
|
|
14592
|
-
(0,
|
|
14781
|
+
(0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
14593
14782
|
for (const suffix of ["-wal", "-shm"]) {
|
|
14594
14783
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
14595
|
-
if ((0,
|
|
14784
|
+
if ((0, import_node_fs37.existsSync)(src)) {
|
|
14596
14785
|
try {
|
|
14597
|
-
(0,
|
|
14786
|
+
(0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
14598
14787
|
} catch {
|
|
14599
14788
|
}
|
|
14600
14789
|
}
|
|
@@ -14670,22 +14859,22 @@ function listConductorWorkspaces() {
|
|
|
14670
14859
|
db.close();
|
|
14671
14860
|
}
|
|
14672
14861
|
} finally {
|
|
14673
|
-
(0,
|
|
14862
|
+
(0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
|
|
14674
14863
|
}
|
|
14675
14864
|
}
|
|
14676
14865
|
function importConductorWorkspace(workspaceId) {
|
|
14677
|
-
if (!(0,
|
|
14866
|
+
if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
|
|
14678
14867
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
14679
14868
|
}
|
|
14680
|
-
const tmp = (0,
|
|
14681
|
-
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");
|
|
14682
14871
|
try {
|
|
14683
|
-
(0,
|
|
14872
|
+
(0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
14684
14873
|
for (const suffix of ["-wal", "-shm"]) {
|
|
14685
14874
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
14686
|
-
if ((0,
|
|
14875
|
+
if ((0, import_node_fs37.existsSync)(src)) {
|
|
14687
14876
|
try {
|
|
14688
|
-
(0,
|
|
14877
|
+
(0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
14689
14878
|
} catch {
|
|
14690
14879
|
}
|
|
14691
14880
|
}
|
|
@@ -14703,7 +14892,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
14703
14892
|
).get(workspaceId);
|
|
14704
14893
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
14705
14894
|
const worktreePath = String(row.workspacePath);
|
|
14706
|
-
if (!(0,
|
|
14895
|
+
if (!(0, import_node_fs37.existsSync)(worktreePath)) {
|
|
14707
14896
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
14708
14897
|
}
|
|
14709
14898
|
let sessionId = null;
|
|
@@ -14766,31 +14955,31 @@ function importConductorWorkspace(workspaceId) {
|
|
|
14766
14955
|
db.close();
|
|
14767
14956
|
}
|
|
14768
14957
|
} finally {
|
|
14769
|
-
(0,
|
|
14958
|
+
(0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
|
|
14770
14959
|
}
|
|
14771
14960
|
}
|
|
14772
14961
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
14773
14962
|
return importConductorWorkspace(workspaceId);
|
|
14774
14963
|
}
|
|
14775
|
-
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;
|
|
14776
14965
|
var init_adopt = __esm({
|
|
14777
14966
|
"src/threads/adopt.ts"() {
|
|
14778
14967
|
"use strict";
|
|
14779
14968
|
import_node_child_process3 = require("child_process");
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
|
|
14969
|
+
import_node_fs37 = require("fs");
|
|
14970
|
+
import_node_os11 = require("os");
|
|
14971
|
+
import_node_path35 = require("path");
|
|
14783
14972
|
import_node_module4 = require("module");
|
|
14784
14973
|
init_worktree();
|
|
14785
14974
|
init_thread_store();
|
|
14786
|
-
CONDUCTOR_APP_SUPPORT = (0,
|
|
14975
|
+
CONDUCTOR_APP_SUPPORT = (0, import_node_path35.join)(
|
|
14787
14976
|
process.env.HOME ?? "",
|
|
14788
14977
|
"Library",
|
|
14789
14978
|
"Application Support",
|
|
14790
14979
|
"com.conductor.app"
|
|
14791
14980
|
);
|
|
14792
|
-
CONDUCTOR_DB = (0,
|
|
14793
|
-
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");
|
|
14794
14983
|
}
|
|
14795
14984
|
});
|
|
14796
14985
|
|
|
@@ -14857,7 +15046,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
14857
15046
|
let createdWorktree = false;
|
|
14858
15047
|
const trees = await listWorktrees(repoPath);
|
|
14859
15048
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
14860
|
-
if (checkedOut?.path && (0,
|
|
15049
|
+
if (checkedOut?.path && (0, import_node_fs38.existsSync)(checkedOut.path)) {
|
|
14861
15050
|
if (input.reuseExistingWorktree !== false) {
|
|
14862
15051
|
worktreePath = checkedOut.path;
|
|
14863
15052
|
} else {
|
|
@@ -14999,7 +15188,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
14999
15188
|
async function createPrStack(input, onSetupLine) {
|
|
15000
15189
|
await requireAgent(input.agent);
|
|
15001
15190
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
15002
|
-
if (!(0,
|
|
15191
|
+
if (!(0, import_node_fs38.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
15003
15192
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
15004
15193
|
const status = await detectGhStack(repoPath);
|
|
15005
15194
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -15066,7 +15255,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
15066
15255
|
}
|
|
15067
15256
|
}
|
|
15068
15257
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
15069
|
-
if (!claimed.has(bootstrap.worktreePath) && (0,
|
|
15258
|
+
if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs38.existsSync)(bootstrap.worktreePath)) {
|
|
15070
15259
|
try {
|
|
15071
15260
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
15072
15261
|
deleteBranch: bootstrap.branchName
|
|
@@ -15076,11 +15265,11 @@ async function createPrStack(input, onSetupLine) {
|
|
|
15076
15265
|
}
|
|
15077
15266
|
return { stack, threads, createdThreadIds };
|
|
15078
15267
|
}
|
|
15079
|
-
var
|
|
15268
|
+
var import_node_fs38;
|
|
15080
15269
|
var init_stack_layers = __esm({
|
|
15081
15270
|
"src/threads/stack-layers.ts"() {
|
|
15082
15271
|
"use strict";
|
|
15083
|
-
|
|
15272
|
+
import_node_fs38 = require("fs");
|
|
15084
15273
|
init_detect();
|
|
15085
15274
|
init_run();
|
|
15086
15275
|
init_stack();
|
|
@@ -15093,7 +15282,7 @@ var init_stack_layers = __esm({
|
|
|
15093
15282
|
|
|
15094
15283
|
// src/diff/diff.ts
|
|
15095
15284
|
async function inspectGitWorktree(worktreePath) {
|
|
15096
|
-
if (!worktreePath || !(0,
|
|
15285
|
+
if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) return "missing_worktree";
|
|
15097
15286
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
15098
15287
|
reject: false
|
|
15099
15288
|
});
|
|
@@ -15101,7 +15290,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
15101
15290
|
return "ok";
|
|
15102
15291
|
}
|
|
15103
15292
|
async function initializeGitRepository(worktreePath) {
|
|
15104
|
-
if (!worktreePath || !(0,
|
|
15293
|
+
if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) {
|
|
15105
15294
|
throw new Error("Worktree not found");
|
|
15106
15295
|
}
|
|
15107
15296
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -15235,11 +15424,11 @@ new file mode 100644
|
|
|
15235
15424
|
};
|
|
15236
15425
|
}
|
|
15237
15426
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
15238
|
-
const abs = (0,
|
|
15427
|
+
const abs = (0, import_node_path36.join)(worktreePath, path);
|
|
15239
15428
|
try {
|
|
15240
|
-
const st = (0,
|
|
15429
|
+
const st = (0, import_node_fs39.statSync)(abs);
|
|
15241
15430
|
if (st.isFile() && st.size > maxHunk) {
|
|
15242
|
-
const buf = (0,
|
|
15431
|
+
const buf = (0, import_node_fs39.readFileSync)(abs).subarray(0, maxHunk);
|
|
15243
15432
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
15244
15433
|
}
|
|
15245
15434
|
} catch {
|
|
@@ -15728,8 +15917,8 @@ function isImageRelativePath(relativePath) {
|
|
|
15728
15917
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
15729
15918
|
assertSafeRelativePath(relativePath);
|
|
15730
15919
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
15731
|
-
const abs = (0,
|
|
15732
|
-
const st = (0,
|
|
15920
|
+
const abs = (0, import_node_path36.join)(worktreePath, relativePath);
|
|
15921
|
+
const st = (0, import_node_fs39.statSync)(abs);
|
|
15733
15922
|
if (!st.isFile()) {
|
|
15734
15923
|
throw new Error(`Not a file: ${relativePath}`);
|
|
15735
15924
|
}
|
|
@@ -15738,7 +15927,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
15738
15927
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
15739
15928
|
);
|
|
15740
15929
|
}
|
|
15741
|
-
const buf = (0,
|
|
15930
|
+
const buf = (0, import_node_fs39.readFileSync)(abs);
|
|
15742
15931
|
return {
|
|
15743
15932
|
path: relativePath,
|
|
15744
15933
|
contentBase64: buf.toString("base64"),
|
|
@@ -15748,12 +15937,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
15748
15937
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
15749
15938
|
assertSafeRelativePath(relativePath);
|
|
15750
15939
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
15751
|
-
const abs = (0,
|
|
15752
|
-
const st = (0,
|
|
15940
|
+
const abs = (0, import_node_path36.join)(worktreePath, relativePath);
|
|
15941
|
+
const st = (0, import_node_fs39.statSync)(abs);
|
|
15753
15942
|
if (!st.isFile()) {
|
|
15754
15943
|
throw new Error(`Not a file: ${relativePath}`);
|
|
15755
15944
|
}
|
|
15756
|
-
const buf = (0,
|
|
15945
|
+
const buf = (0, import_node_fs39.readFileSync)(abs);
|
|
15757
15946
|
if (isImageRelativePath(relativePath)) {
|
|
15758
15947
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
15759
15948
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -15796,9 +15985,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
15796
15985
|
}
|
|
15797
15986
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
15798
15987
|
assertSafeRelativePath(relativePath);
|
|
15799
|
-
const abs = (0,
|
|
15800
|
-
(0,
|
|
15801
|
-
(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");
|
|
15802
15991
|
return { path: relativePath };
|
|
15803
15992
|
}
|
|
15804
15993
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -15815,12 +16004,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
15815
16004
|
truncated: full.files.length > maxFiles
|
|
15816
16005
|
};
|
|
15817
16006
|
}
|
|
15818
|
-
var
|
|
16007
|
+
var import_node_fs39, import_node_path36, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
|
|
15819
16008
|
var init_diff = __esm({
|
|
15820
16009
|
"src/diff/diff.ts"() {
|
|
15821
16010
|
"use strict";
|
|
15822
|
-
|
|
15823
|
-
|
|
16011
|
+
import_node_fs39 = require("fs");
|
|
16012
|
+
import_node_path36 = require("path");
|
|
15824
16013
|
init_run();
|
|
15825
16014
|
init_worktree();
|
|
15826
16015
|
mergeBaseCache = /* @__PURE__ */ new Map();
|
|
@@ -16078,7 +16267,7 @@ function parseFrontmatter(content) {
|
|
|
16078
16267
|
}
|
|
16079
16268
|
function readSkill(skillMd, source) {
|
|
16080
16269
|
try {
|
|
16081
|
-
const content = (0,
|
|
16270
|
+
const content = (0, import_node_fs40.readFileSync)(skillMd, "utf8");
|
|
16082
16271
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
16083
16272
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
16084
16273
|
const name = fmName || dirName;
|
|
@@ -16097,19 +16286,19 @@ function readSkill(skillMd, source) {
|
|
|
16097
16286
|
}
|
|
16098
16287
|
}
|
|
16099
16288
|
function scanSkillsDir(dir, source, out) {
|
|
16100
|
-
if (!(0,
|
|
16289
|
+
if (!(0, import_node_fs40.existsSync)(dir)) return;
|
|
16101
16290
|
let entries;
|
|
16102
16291
|
try {
|
|
16103
|
-
entries = (0,
|
|
16292
|
+
entries = (0, import_node_fs40.readdirSync)(dir);
|
|
16104
16293
|
} catch {
|
|
16105
16294
|
return;
|
|
16106
16295
|
}
|
|
16107
16296
|
for (const entry of entries) {
|
|
16108
16297
|
if (entry.startsWith(".")) continue;
|
|
16109
|
-
const skillMd = (0,
|
|
16110
|
-
if (!(0,
|
|
16298
|
+
const skillMd = (0, import_node_path37.join)(dir, entry, "SKILL.md");
|
|
16299
|
+
if (!(0, import_node_fs40.existsSync)(skillMd)) continue;
|
|
16111
16300
|
try {
|
|
16112
|
-
if (!(0,
|
|
16301
|
+
if (!(0, import_node_fs40.statSync)(skillMd).isFile()) continue;
|
|
16113
16302
|
} catch {
|
|
16114
16303
|
continue;
|
|
16115
16304
|
}
|
|
@@ -16118,24 +16307,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
16118
16307
|
}
|
|
16119
16308
|
}
|
|
16120
16309
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
16121
|
-
if (!(0,
|
|
16310
|
+
if (!(0, import_node_fs40.existsSync)(pluginsRoot)) return;
|
|
16122
16311
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
16123
16312
|
if (depth > 7) return;
|
|
16124
16313
|
let entries;
|
|
16125
16314
|
try {
|
|
16126
|
-
entries = (0,
|
|
16315
|
+
entries = (0, import_node_fs40.readdirSync)(dir);
|
|
16127
16316
|
} catch {
|
|
16128
16317
|
return;
|
|
16129
16318
|
}
|
|
16130
16319
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
16131
|
-
const skill = readSkill((0,
|
|
16320
|
+
const skill = readSkill((0, import_node_path37.join)(dir, "SKILL.md"), "cli");
|
|
16132
16321
|
if (skill) out.push(skill);
|
|
16133
16322
|
}
|
|
16134
16323
|
for (const entry of entries) {
|
|
16135
16324
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
16136
|
-
const full = (0,
|
|
16325
|
+
const full = (0, import_node_path37.join)(dir, entry);
|
|
16137
16326
|
try {
|
|
16138
|
-
if (!(0,
|
|
16327
|
+
if (!(0, import_node_fs40.statSync)(full).isDirectory()) continue;
|
|
16139
16328
|
} catch {
|
|
16140
16329
|
continue;
|
|
16141
16330
|
}
|
|
@@ -16150,20 +16339,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
16150
16339
|
walk(pluginsRoot, 0, false);
|
|
16151
16340
|
}
|
|
16152
16341
|
function discoverSkills(worktreePath) {
|
|
16153
|
-
const home = (0,
|
|
16342
|
+
const home = (0, import_node_os12.homedir)();
|
|
16154
16343
|
const collected = [];
|
|
16155
16344
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
16156
|
-
scanSkillsDir((0,
|
|
16345
|
+
scanSkillsDir((0, import_node_path37.join)(worktreePath, rel), "workspace", collected);
|
|
16157
16346
|
}
|
|
16158
16347
|
for (const abs of [
|
|
16159
|
-
(0,
|
|
16160
|
-
(0,
|
|
16161
|
-
(0,
|
|
16162
|
-
(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")
|
|
16163
16352
|
]) {
|
|
16164
16353
|
scanSkillsDir(abs, "user", collected);
|
|
16165
16354
|
}
|
|
16166
|
-
scanClaudePluginSkills((0,
|
|
16355
|
+
scanClaudePluginSkills((0, import_node_path37.join)(home, ".claude/plugins"), collected);
|
|
16167
16356
|
collected.push(...bundledSkills());
|
|
16168
16357
|
const rank = {
|
|
16169
16358
|
workspace: 0,
|
|
@@ -16189,7 +16378,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
16189
16378
|
\u2026(truncated)` : body;
|
|
16190
16379
|
}
|
|
16191
16380
|
}
|
|
16192
|
-
const raw = (0,
|
|
16381
|
+
const raw = (0, import_node_fs40.readFileSync)(skillPath, "utf8");
|
|
16193
16382
|
if (raw.startsWith("---")) {
|
|
16194
16383
|
const end = raw.indexOf("\n---", 3);
|
|
16195
16384
|
if (end >= 0) {
|
|
@@ -16203,13 +16392,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
16203
16392
|
|
|
16204
16393
|
\u2026(truncated)` : raw;
|
|
16205
16394
|
}
|
|
16206
|
-
var
|
|
16395
|
+
var import_node_fs40, import_node_os12, import_node_path37, BUNDLED_SKILL_PREFIX;
|
|
16207
16396
|
var init_discover = __esm({
|
|
16208
16397
|
"src/skills/discover.ts"() {
|
|
16209
16398
|
"use strict";
|
|
16210
|
-
|
|
16211
|
-
|
|
16212
|
-
|
|
16399
|
+
import_node_fs40 = require("fs");
|
|
16400
|
+
import_node_os12 = require("os");
|
|
16401
|
+
import_node_path37 = require("path");
|
|
16213
16402
|
init_long_running();
|
|
16214
16403
|
BUNDLED_SKILL_PREFIX = "bundled:";
|
|
16215
16404
|
}
|
|
@@ -16304,17 +16493,17 @@ var init_expand = __esm({
|
|
|
16304
16493
|
function packagedDetachedJobPath() {
|
|
16305
16494
|
const dir = packagedMcpDir();
|
|
16306
16495
|
if (!dir) return null;
|
|
16307
|
-
const script = (0,
|
|
16308
|
-
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;
|
|
16309
16498
|
}
|
|
16310
16499
|
function resolveDetachedJobScript() {
|
|
16311
16500
|
const packaged = packagedDetachedJobPath();
|
|
16312
16501
|
if (packaged) return packaged;
|
|
16313
|
-
let dir = (0,
|
|
16502
|
+
let dir = (0, import_node_path38.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
|
|
16314
16503
|
for (let i = 0; i < 8; i++) {
|
|
16315
|
-
const candidate = (0,
|
|
16316
|
-
if ((0,
|
|
16317
|
-
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);
|
|
16318
16507
|
if (parent === dir) break;
|
|
16319
16508
|
dir = parent;
|
|
16320
16509
|
}
|
|
@@ -16325,12 +16514,12 @@ function formatDetachedJobInvoke(scriptPath) {
|
|
|
16325
16514
|
if (resolved) return `node ${JSON.stringify(resolved)}`;
|
|
16326
16515
|
return "node scripts/detached-job.js";
|
|
16327
16516
|
}
|
|
16328
|
-
var
|
|
16517
|
+
var import_node_fs41, import_node_path38, import_node_url3, import_meta3;
|
|
16329
16518
|
var init_detached_job_path = __esm({
|
|
16330
16519
|
"src/skills/detached-job-path.ts"() {
|
|
16331
16520
|
"use strict";
|
|
16332
|
-
|
|
16333
|
-
|
|
16521
|
+
import_node_fs41 = require("fs");
|
|
16522
|
+
import_node_path38 = require("path");
|
|
16334
16523
|
import_node_url3 = require("url");
|
|
16335
16524
|
init_packaged_runtime();
|
|
16336
16525
|
import_meta3 = {};
|
|
@@ -16403,11 +16592,11 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
16403
16592
|
);
|
|
16404
16593
|
} else if (opts?.githubSlug) {
|
|
16405
16594
|
lines.push(
|
|
16406
|
-
`- 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\`.`
|
|
16407
16596
|
);
|
|
16408
16597
|
} else {
|
|
16409
16598
|
lines.push(
|
|
16410
|
-
"- 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`."
|
|
16411
16600
|
);
|
|
16412
16601
|
}
|
|
16413
16602
|
lines.push("");
|
|
@@ -16498,12 +16687,12 @@ function formatArtifactDirective() {
|
|
|
16498
16687
|
function formatUiReminder() {
|
|
16499
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.";
|
|
16500
16689
|
}
|
|
16501
|
-
var
|
|
16690
|
+
var import_node_fs42, import_node_path39;
|
|
16502
16691
|
var init_instructions = __esm({
|
|
16503
16692
|
"src/agents/instructions.ts"() {
|
|
16504
16693
|
"use strict";
|
|
16505
|
-
|
|
16506
|
-
|
|
16694
|
+
import_node_fs42 = require("fs");
|
|
16695
|
+
import_node_path39 = require("path");
|
|
16507
16696
|
init_git_auth_mode();
|
|
16508
16697
|
init_worktree_labels();
|
|
16509
16698
|
init_detached_job_path();
|
|
@@ -16673,40 +16862,40 @@ __export(plan_file_exports, {
|
|
|
16673
16862
|
writePlanFile: () => writePlanFile
|
|
16674
16863
|
});
|
|
16675
16864
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
16676
|
-
const gitignoreAbs = (0,
|
|
16677
|
-
if ((0,
|
|
16678
|
-
(0,
|
|
16679
|
-
(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");
|
|
16680
16869
|
}
|
|
16681
16870
|
function planFileAbs(worktreePath) {
|
|
16682
|
-
return (0,
|
|
16871
|
+
return (0, import_node_path40.join)(worktreePath, PLAN_FILE_REL);
|
|
16683
16872
|
}
|
|
16684
16873
|
function readTextIfPresent2(abs) {
|
|
16685
|
-
if (!(0,
|
|
16874
|
+
if (!(0, import_node_fs43.existsSync)(abs)) return null;
|
|
16686
16875
|
try {
|
|
16687
|
-
const content = (0,
|
|
16876
|
+
const content = (0, import_node_fs43.readFileSync)(abs, "utf8");
|
|
16688
16877
|
return content.trim() ? content : null;
|
|
16689
16878
|
} catch {
|
|
16690
16879
|
return null;
|
|
16691
16880
|
}
|
|
16692
16881
|
}
|
|
16693
16882
|
function readPlanFile(worktreePath) {
|
|
16694
|
-
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));
|
|
16695
16884
|
}
|
|
16696
16885
|
function writePlanFile(worktreePath, content) {
|
|
16697
16886
|
ensureAttachmentsGitignore(worktreePath);
|
|
16698
16887
|
const abs = planFileAbs(worktreePath);
|
|
16699
|
-
(0,
|
|
16888
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(abs), { recursive: true });
|
|
16700
16889
|
const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
|
|
16701
|
-
(0,
|
|
16890
|
+
(0, import_node_fs43.writeFileSync)(abs, body, "utf8");
|
|
16702
16891
|
return PLAN_FILE_REL;
|
|
16703
16892
|
}
|
|
16704
|
-
var
|
|
16893
|
+
var import_node_fs43, import_node_path40;
|
|
16705
16894
|
var init_plan_file = __esm({
|
|
16706
16895
|
"src/plan/plan-file.ts"() {
|
|
16707
16896
|
"use strict";
|
|
16708
|
-
|
|
16709
|
-
|
|
16897
|
+
import_node_fs43 = require("fs");
|
|
16898
|
+
import_node_path40 = require("path");
|
|
16710
16899
|
init_workspace_scratch();
|
|
16711
16900
|
init_plan_present();
|
|
16712
16901
|
init_plan_present();
|
|
@@ -16766,7 +16955,7 @@ function setCaffeinateHoldHooks(next) {
|
|
|
16766
16955
|
hooks = next;
|
|
16767
16956
|
}
|
|
16768
16957
|
function caffeinateHoldPath() {
|
|
16769
|
-
return (0,
|
|
16958
|
+
return (0, import_node_path41.join)(appDataDir(), "caffeinate-hold.json");
|
|
16770
16959
|
}
|
|
16771
16960
|
function processAlive(pid) {
|
|
16772
16961
|
if (hooks.processAlive) return hooks.processAlive(pid);
|
|
@@ -16800,9 +16989,9 @@ function uniqueIds(ids) {
|
|
|
16800
16989
|
}
|
|
16801
16990
|
function readHold() {
|
|
16802
16991
|
const path = caffeinateHoldPath();
|
|
16803
|
-
if (!(0,
|
|
16992
|
+
if (!(0, import_node_fs44.existsSync)(path)) return null;
|
|
16804
16993
|
try {
|
|
16805
|
-
const parsed = JSON.parse((0,
|
|
16994
|
+
const parsed = JSON.parse((0, import_node_fs44.readFileSync)(path, "utf8"));
|
|
16806
16995
|
if (typeof parsed?.pid === "number" && parsed.pid > 0) {
|
|
16807
16996
|
return {
|
|
16808
16997
|
pid: parsed.pid,
|
|
@@ -16824,7 +17013,7 @@ function writeHold(pid, threadIds) {
|
|
|
16824
17013
|
}
|
|
16825
17014
|
function clearHold() {
|
|
16826
17015
|
try {
|
|
16827
|
-
(0,
|
|
17016
|
+
(0, import_node_fs44.unlinkSync)(caffeinateHoldPath());
|
|
16828
17017
|
} catch {
|
|
16829
17018
|
}
|
|
16830
17019
|
}
|
|
@@ -16909,13 +17098,13 @@ function releaseCaffeinateHoldForThread(threadId) {
|
|
|
16909
17098
|
}
|
|
16910
17099
|
return setCaffeinateHold(false, { threadId: id });
|
|
16911
17100
|
}
|
|
16912
|
-
var import_node_child_process4,
|
|
17101
|
+
var import_node_child_process4, import_node_fs44, import_node_path41, hooks;
|
|
16913
17102
|
var init_caffeinate_hold = __esm({
|
|
16914
17103
|
"src/store/caffeinate-hold.ts"() {
|
|
16915
17104
|
"use strict";
|
|
16916
17105
|
import_node_child_process4 = require("child_process");
|
|
16917
|
-
|
|
16918
|
-
|
|
17106
|
+
import_node_fs44 = require("fs");
|
|
17107
|
+
import_node_path41 = require("path");
|
|
16919
17108
|
init_paths();
|
|
16920
17109
|
init_private_file();
|
|
16921
17110
|
hooks = {};
|
|
@@ -16924,7 +17113,7 @@ var init_caffeinate_hold = __esm({
|
|
|
16924
17113
|
|
|
16925
17114
|
// src/store/schedules.ts
|
|
16926
17115
|
function schedulesPath() {
|
|
16927
|
-
return (0,
|
|
17116
|
+
return (0, import_node_path42.join)(appDataDir(), "schedules.json");
|
|
16928
17117
|
}
|
|
16929
17118
|
function parseDurationMs(every) {
|
|
16930
17119
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -17024,9 +17213,9 @@ function normalizeTask(raw) {
|
|
|
17024
17213
|
}
|
|
17025
17214
|
function readAll2() {
|
|
17026
17215
|
const path = schedulesPath();
|
|
17027
|
-
if (!(0,
|
|
17216
|
+
if (!(0, import_node_fs45.existsSync)(path)) return [];
|
|
17028
17217
|
try {
|
|
17029
|
-
const parsed = JSON.parse((0,
|
|
17218
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)(path, "utf8"));
|
|
17030
17219
|
if (!Array.isArray(parsed)) return [];
|
|
17031
17220
|
return parsed.map((row) => {
|
|
17032
17221
|
try {
|
|
@@ -17051,7 +17240,7 @@ function buildTask(input, now) {
|
|
|
17051
17240
|
const ts = nowIso2(now);
|
|
17052
17241
|
const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
|
|
17053
17242
|
return {
|
|
17054
|
-
id: (0,
|
|
17243
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
17055
17244
|
name: input.name?.trim() || defaultScheduleName(prompt),
|
|
17056
17245
|
prompt,
|
|
17057
17246
|
enabled: input.enabled !== false,
|
|
@@ -17138,13 +17327,13 @@ function recordScheduleRun(id, result) {
|
|
|
17138
17327
|
writeAll2(rows);
|
|
17139
17328
|
return next;
|
|
17140
17329
|
}
|
|
17141
|
-
var
|
|
17330
|
+
var import_node_crypto9, import_node_fs45, import_node_path42, import_croner, DURATION_RE, UNIT_MS;
|
|
17142
17331
|
var init_schedules = __esm({
|
|
17143
17332
|
"src/store/schedules.ts"() {
|
|
17144
17333
|
"use strict";
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17334
|
+
import_node_crypto9 = require("crypto");
|
|
17335
|
+
import_node_fs45 = require("fs");
|
|
17336
|
+
import_node_path42 = require("path");
|
|
17148
17337
|
import_croner = require("croner");
|
|
17149
17338
|
init_orchestrator_capable();
|
|
17150
17339
|
init_paths();
|
|
@@ -17286,13 +17475,13 @@ var init_schedule_runner = __esm({
|
|
|
17286
17475
|
|
|
17287
17476
|
// src/agents/cursor-store.ts
|
|
17288
17477
|
function cursorSdkStoreDir(threadId) {
|
|
17289
|
-
const root = (0,
|
|
17478
|
+
const root = (0, import_node_path43.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
|
|
17290
17479
|
const id = sanitizeCursorStoreSegment(threadId);
|
|
17291
17480
|
if (!id) return root;
|
|
17292
|
-
return (0,
|
|
17481
|
+
return (0, import_node_path43.join)(root, "threads", id);
|
|
17293
17482
|
}
|
|
17294
17483
|
function cursorSdkRunsNdjsonPath(threadId) {
|
|
17295
|
-
return (0,
|
|
17484
|
+
return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
|
|
17296
17485
|
}
|
|
17297
17486
|
function cursorSdkRunsNdjsonSearchPaths(threadId) {
|
|
17298
17487
|
const scoped = cursorSdkRunsNdjsonPath(threadId);
|
|
@@ -17305,11 +17494,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
|
|
|
17305
17494
|
function sanitizeCursorStoreSegment(threadId) {
|
|
17306
17495
|
return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
17307
17496
|
}
|
|
17308
|
-
var
|
|
17497
|
+
var import_node_path43, CURSOR_SDK_STORE_DIR;
|
|
17309
17498
|
var init_cursor_store = __esm({
|
|
17310
17499
|
"src/agents/cursor-store.ts"() {
|
|
17311
17500
|
"use strict";
|
|
17312
|
-
|
|
17501
|
+
import_node_path43 = require("path");
|
|
17313
17502
|
init_paths();
|
|
17314
17503
|
CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
|
|
17315
17504
|
}
|
|
@@ -17331,9 +17520,9 @@ function recoverFinishedCursorRun(opts) {
|
|
|
17331
17520
|
return best;
|
|
17332
17521
|
}
|
|
17333
17522
|
function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
17334
|
-
if (!(0,
|
|
17523
|
+
if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
|
|
17335
17524
|
try {
|
|
17336
|
-
const lines = (0,
|
|
17525
|
+
const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
|
|
17337
17526
|
let best = null;
|
|
17338
17527
|
for (const line of lines) {
|
|
17339
17528
|
const trimmed = line.trim();
|
|
@@ -17359,11 +17548,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
|
17359
17548
|
return null;
|
|
17360
17549
|
}
|
|
17361
17550
|
}
|
|
17362
|
-
var
|
|
17551
|
+
var import_node_fs46;
|
|
17363
17552
|
var init_cursor_recover = __esm({
|
|
17364
17553
|
"src/agents/cursor-recover.ts"() {
|
|
17365
17554
|
"use strict";
|
|
17366
|
-
|
|
17555
|
+
import_node_fs46 = require("fs");
|
|
17367
17556
|
init_cursor_store();
|
|
17368
17557
|
}
|
|
17369
17558
|
});
|
|
@@ -17402,6 +17591,7 @@ var init_title = __esm({
|
|
|
17402
17591
|
// src/orchestrator/orchestrator.ts
|
|
17403
17592
|
var orchestrator_exports = {};
|
|
17404
17593
|
__export(orchestrator_exports, {
|
|
17594
|
+
LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
|
|
17405
17595
|
Orchestrator: () => Orchestrator,
|
|
17406
17596
|
getOrchestrator: () => getOrchestrator,
|
|
17407
17597
|
isPidAlive: () => isPidAlive,
|
|
@@ -17494,13 +17684,13 @@ async function startOrchestration(opts) {
|
|
|
17494
17684
|
}
|
|
17495
17685
|
return updated;
|
|
17496
17686
|
}
|
|
17497
|
-
var import_node_events,
|
|
17687
|
+
var import_node_events, import_node_fs47, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
|
|
17498
17688
|
var init_orchestrator = __esm({
|
|
17499
17689
|
"src/orchestrator/orchestrator.ts"() {
|
|
17500
17690
|
"use strict";
|
|
17501
17691
|
import_node_events = require("events");
|
|
17502
17692
|
init_outbound_watch();
|
|
17503
|
-
|
|
17693
|
+
import_node_fs47 = require("fs");
|
|
17504
17694
|
init_error_detail();
|
|
17505
17695
|
init_run();
|
|
17506
17696
|
init_stale_lock();
|
|
@@ -17515,6 +17705,7 @@ var init_orchestrator = __esm({
|
|
|
17515
17705
|
init_orphan_cleanup();
|
|
17516
17706
|
init_apply_into_main();
|
|
17517
17707
|
init_clone_repo();
|
|
17708
|
+
init_message_parts();
|
|
17518
17709
|
init_usage();
|
|
17519
17710
|
init_thread_store();
|
|
17520
17711
|
init_desktop_host();
|
|
@@ -17552,6 +17743,7 @@ var init_orchestrator = __esm({
|
|
|
17552
17743
|
init_caffeinate_hold();
|
|
17553
17744
|
init_schedule_runner();
|
|
17554
17745
|
init_coordinator_prompt();
|
|
17746
|
+
LIVE_TURN_SPAWN_GRACE_MS = 15e3;
|
|
17555
17747
|
STALE_AGENT_PID_WAIT_MS = 2500;
|
|
17556
17748
|
Orchestrator = class {
|
|
17557
17749
|
events = new import_node_events.EventEmitter();
|
|
@@ -17608,6 +17800,39 @@ var init_orchestrator = __esm({
|
|
|
17608
17800
|
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
|
|
17609
17801
|
return true;
|
|
17610
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
|
+
}
|
|
17611
17836
|
async reconcile(repoPath, opts) {
|
|
17612
17837
|
const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
|
|
17613
17838
|
const drainQueues = opts?.drainQueues !== false;
|
|
@@ -17632,7 +17857,7 @@ var init_orchestrator = __esm({
|
|
|
17632
17857
|
}
|
|
17633
17858
|
continue;
|
|
17634
17859
|
}
|
|
17635
|
-
if (!(0,
|
|
17860
|
+
if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
|
|
17636
17861
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
17637
17862
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
17638
17863
|
continue;
|
|
@@ -17942,12 +18167,14 @@ var init_orchestrator = __esm({
|
|
|
17942
18167
|
this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
|
|
17943
18168
|
return thread;
|
|
17944
18169
|
}
|
|
17945
|
-
async send(threadRef, prompt) {
|
|
18170
|
+
async send(threadRef, prompt, opts) {
|
|
17946
18171
|
const thread = this.requireThread(threadRef);
|
|
17947
18172
|
if (thread.status === "archived") {
|
|
17948
18173
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
17949
18174
|
}
|
|
17950
|
-
|
|
18175
|
+
const followUp = opts?.followUp === "steer" ? "steer" : "queue";
|
|
18176
|
+
let shouldSteer = false;
|
|
18177
|
+
const sent = await withThreadLock(thread.id, async () => {
|
|
17951
18178
|
const current = this.requireThread(thread.id);
|
|
17952
18179
|
if (current.status === "archived") {
|
|
17953
18180
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
@@ -17956,6 +18183,7 @@ var init_orchestrator = __esm({
|
|
|
17956
18183
|
this.crashContinued.delete(thread.id);
|
|
17957
18184
|
this.haltDrain.delete(thread.id);
|
|
17958
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);
|
|
17959
18187
|
const patch = { queue };
|
|
17960
18188
|
if (!inFlight) patch.status = "queued";
|
|
17961
18189
|
const pid = current.agentPid;
|
|
@@ -17967,16 +18195,20 @@ var init_orchestrator = __esm({
|
|
|
17967
18195
|
if (!inFlight) {
|
|
17968
18196
|
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
17969
18197
|
}
|
|
17970
|
-
if (thisProcessShouldDrainAgentQueues()) {
|
|
18198
|
+
if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
|
|
17971
18199
|
void this.drainQueue(thread.id);
|
|
17972
18200
|
}
|
|
17973
18201
|
return this.requireThread(thread.id);
|
|
17974
18202
|
});
|
|
18203
|
+
if (shouldSteer && sent.queue.length > 0) {
|
|
18204
|
+
return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
|
|
18205
|
+
}
|
|
18206
|
+
return sent;
|
|
17975
18207
|
}
|
|
17976
|
-
async fanOut(threadRefs, prompt) {
|
|
18208
|
+
async fanOut(threadRefs, prompt, opts) {
|
|
17977
18209
|
const results = [];
|
|
17978
18210
|
for (const ref of threadRefs) {
|
|
17979
|
-
results.push(await this.send(ref, prompt));
|
|
18211
|
+
results.push(await this.send(ref, prompt, opts));
|
|
17980
18212
|
}
|
|
17981
18213
|
return results;
|
|
17982
18214
|
}
|
|
@@ -18780,8 +19012,8 @@ var init_orchestrator = __esm({
|
|
|
18780
19012
|
return created;
|
|
18781
19013
|
}
|
|
18782
19014
|
async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
|
|
18783
|
-
const thread = this.requireThread(threadRef);
|
|
18784
|
-
if (!
|
|
19015
|
+
const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
|
|
19016
|
+
if (!this.threadLooksLive(thread)) {
|
|
18785
19017
|
return thread;
|
|
18786
19018
|
}
|
|
18787
19019
|
const start = Date.now();
|
|
@@ -18818,12 +19050,13 @@ var init_orchestrator = __esm({
|
|
|
18818
19050
|
}
|
|
18819
19051
|
});
|
|
18820
19052
|
timer = setInterval(() => {
|
|
18821
|
-
const
|
|
18822
|
-
if (!
|
|
19053
|
+
const raw = readThread(thread.id);
|
|
19054
|
+
if (!raw) {
|
|
18823
19055
|
finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
|
|
18824
19056
|
return;
|
|
18825
19057
|
}
|
|
18826
|
-
|
|
19058
|
+
const current = this.healStaleReportedActivity(raw);
|
|
19059
|
+
if (!this.threadLooksLive(current)) {
|
|
18827
19060
|
finish(() => resolve(current));
|
|
18828
19061
|
return;
|
|
18829
19062
|
}
|
|
@@ -18846,20 +19079,22 @@ var init_orchestrator = __esm({
|
|
|
18846
19079
|
};
|
|
18847
19080
|
}
|
|
18848
19081
|
getTurnResult(threadRef) {
|
|
18849
|
-
const thread = this.requireThread(threadRef);
|
|
19082
|
+
const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
|
|
18850
19083
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
18851
19084
|
const lastError = thread.lastError ?? null;
|
|
18852
|
-
const
|
|
18853
|
-
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);
|
|
18854
19088
|
const live = stillRunning ? readTurnLive(thread.id) : null;
|
|
18855
|
-
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;
|
|
18856
19091
|
return {
|
|
18857
19092
|
text: text5,
|
|
18858
19093
|
status: thread.status,
|
|
18859
19094
|
sessionId: thread.sessionId,
|
|
18860
19095
|
lastError,
|
|
18861
19096
|
stillRunning,
|
|
18862
|
-
progress:
|
|
19097
|
+
progress: liveSummary ?? queuedHint,
|
|
18863
19098
|
lastActivityAt: live?.updatedAt ?? null,
|
|
18864
19099
|
usage: lastAgent?.usage ?? null
|
|
18865
19100
|
};
|
|
@@ -19207,7 +19442,14 @@ var init_orchestrator = __esm({
|
|
|
19207
19442
|
);
|
|
19208
19443
|
}
|
|
19209
19444
|
if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
|
|
19210
|
-
|
|
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
|
+
}
|
|
19211
19453
|
return this.requireThread(threadRef);
|
|
19212
19454
|
}
|
|
19213
19455
|
let prBase;
|
|
@@ -19410,7 +19652,7 @@ var init_orchestrator = __esm({
|
|
|
19410
19652
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
19411
19653
|
return restored2;
|
|
19412
19654
|
}
|
|
19413
|
-
if (!(0,
|
|
19655
|
+
if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
|
|
19414
19656
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
19415
19657
|
throw new Error(
|
|
19416
19658
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
@@ -19422,6 +19664,8 @@ var init_orchestrator = __esm({
|
|
|
19422
19664
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
19423
19665
|
await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
|
|
19424
19666
|
});
|
|
19667
|
+
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
|
|
19668
|
+
await ensureWorktreeSideboardIgnored2(dest);
|
|
19425
19669
|
void createThreadWorktree2;
|
|
19426
19670
|
void slug;
|
|
19427
19671
|
}
|
|
@@ -19490,8 +19734,8 @@ init_nested_electron_env();
|
|
|
19490
19734
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
19491
19735
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
19492
19736
|
var import_zod5 = require("zod");
|
|
19493
|
-
var
|
|
19494
|
-
var
|
|
19737
|
+
var import_node_crypto12 = require("crypto");
|
|
19738
|
+
var import_node_path46 = require("path");
|
|
19495
19739
|
init_orchestrator();
|
|
19496
19740
|
init_worktree();
|
|
19497
19741
|
|
|
@@ -19505,7 +19749,7 @@ init_abletime();
|
|
|
19505
19749
|
init_fetch();
|
|
19506
19750
|
|
|
19507
19751
|
// src/integrations/linear-oauth.ts
|
|
19508
|
-
var
|
|
19752
|
+
var import_node_crypto10 = require("crypto");
|
|
19509
19753
|
var import_node_http = require("http");
|
|
19510
19754
|
init_app_settings();
|
|
19511
19755
|
init_fetch();
|
|
@@ -19683,6 +19927,22 @@ query SideboardAssignedIssues($first: Int!) {
|
|
|
19683
19927
|
}
|
|
19684
19928
|
}
|
|
19685
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
|
+
`;
|
|
19686
19946
|
var TEAMS_QUERY = `
|
|
19687
19947
|
query SideboardTeams {
|
|
19688
19948
|
viewer { id name }
|
|
@@ -19966,19 +20226,73 @@ function normalizePriority(priority) {
|
|
|
19966
20226
|
}
|
|
19967
20227
|
return priority;
|
|
19968
20228
|
}
|
|
19969
|
-
|
|
19970
|
-
|
|
19971
|
-
|
|
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) {
|
|
19972
20260
|
return {
|
|
19973
20261
|
viewer: {
|
|
19974
20262
|
id: String(json.viewer?.id ?? ""),
|
|
19975
20263
|
name: String(json.viewer?.name ?? "")
|
|
19976
20264
|
},
|
|
19977
|
-
issues: (
|
|
19978
|
-
(node) => toIssueInfo(mapIssue(node))
|
|
19979
|
-
)
|
|
20265
|
+
issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
|
|
19980
20266
|
};
|
|
19981
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
|
+
}
|
|
19982
20296
|
async function listLinearTeams(opts) {
|
|
19983
20297
|
const json = await linearGraphql(TEAMS_QUERY, void 0, opts);
|
|
19984
20298
|
return {
|
|
@@ -20085,6 +20399,22 @@ async function commentLinearIssue(input, opts) {
|
|
|
20085
20399
|
}
|
|
20086
20400
|
|
|
20087
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
|
+
}
|
|
20088
20418
|
async function listGitHubIssues(repoPath, opts) {
|
|
20089
20419
|
const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
|
|
20090
20420
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
@@ -20098,6 +20428,17 @@ async function listGitHubIssues(repoPath, opts) {
|
|
|
20098
20428
|
"--state",
|
|
20099
20429
|
"open"
|
|
20100
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(" "));
|
|
20101
20442
|
if (slug) args.push("--repo", slug);
|
|
20102
20443
|
const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
|
|
20103
20444
|
if (exitCode !== 0 || !stdout.trim()) return [];
|
|
@@ -20135,14 +20476,20 @@ async function githubViewerLogin(repoPath) {
|
|
|
20135
20476
|
if (exitCode !== 0) return "";
|
|
20136
20477
|
return stdout.trim();
|
|
20137
20478
|
}
|
|
20138
|
-
async function listIssues(repoPath) {
|
|
20479
|
+
async function listIssues(repoPath, opts) {
|
|
20139
20480
|
const settings = loadAppSettings();
|
|
20140
20481
|
const preferredSource = settings.integrations.issueSource ?? "github";
|
|
20141
20482
|
const linearConnected = isLinearConnected(settings);
|
|
20142
20483
|
const abletimeConnected = isAbleTimeConnected(settings);
|
|
20143
20484
|
const source = resolveEffectiveIssueSource(settings);
|
|
20485
|
+
const query = opts?.query?.trim() || void 0;
|
|
20486
|
+
const assignee = opts?.assignee?.trim() || void 0;
|
|
20144
20487
|
if (source === "linear") {
|
|
20145
|
-
const listed = await
|
|
20488
|
+
const listed = await listLinearIssuesFiltered({
|
|
20489
|
+
assignee,
|
|
20490
|
+
query,
|
|
20491
|
+
limit: opts?.limit
|
|
20492
|
+
});
|
|
20146
20493
|
return {
|
|
20147
20494
|
source,
|
|
20148
20495
|
preferredSource,
|
|
@@ -20156,13 +20503,20 @@ async function listIssues(repoPath) {
|
|
|
20156
20503
|
};
|
|
20157
20504
|
}
|
|
20158
20505
|
if (source === "abletime") {
|
|
20159
|
-
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
|
+
);
|
|
20160
20514
|
return {
|
|
20161
20515
|
source,
|
|
20162
20516
|
preferredSource,
|
|
20163
20517
|
linearConnected,
|
|
20164
20518
|
abletimeConnected,
|
|
20165
|
-
issues:
|
|
20519
|
+
issues: issues2,
|
|
20166
20520
|
viewer: {
|
|
20167
20521
|
login: listed.viewer.name,
|
|
20168
20522
|
name: listed.viewer.name
|
|
@@ -20170,7 +20524,7 @@ async function listIssues(repoPath) {
|
|
|
20170
20524
|
};
|
|
20171
20525
|
}
|
|
20172
20526
|
const [issues, login] = await Promise.all([
|
|
20173
|
-
listGitHubIssues(repoPath),
|
|
20527
|
+
listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
|
|
20174
20528
|
githubViewerLogin(repoPath)
|
|
20175
20529
|
]);
|
|
20176
20530
|
return {
|
|
@@ -20223,14 +20577,16 @@ function mcpWaitFinishedHint(status) {
|
|
|
20223
20577
|
}
|
|
20224
20578
|
|
|
20225
20579
|
// src/mcp/server.ts
|
|
20580
|
+
init_message_parts();
|
|
20226
20581
|
init_turn_live();
|
|
20227
20582
|
|
|
20228
20583
|
// src/mcp/thread-visibility.ts
|
|
20584
|
+
init_message_parts();
|
|
20229
20585
|
function lastMessagePreview(messages, max = 160) {
|
|
20230
20586
|
if (!messages?.length) return null;
|
|
20231
20587
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
20232
20588
|
const text5 = messages[i]?.text?.trim();
|
|
20233
|
-
if (!text5) continue;
|
|
20589
|
+
if (!text5 || isInternalAgentStatusText(text5)) continue;
|
|
20234
20590
|
const flat = text5.replace(/\s+/g, " ");
|
|
20235
20591
|
return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
|
|
20236
20592
|
}
|
|
@@ -20900,6 +21256,22 @@ function registerLinearTools(server) {
|
|
|
20900
21256
|
}
|
|
20901
21257
|
}
|
|
20902
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
|
+
);
|
|
20903
21275
|
server.tool(
|
|
20904
21276
|
"linear_get_issue",
|
|
20905
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.",
|
|
@@ -21134,30 +21506,31 @@ function registerScheduleTools(server) {
|
|
|
21134
21506
|
|
|
21135
21507
|
// src/mcp/server.ts
|
|
21136
21508
|
init_agent_git_actions();
|
|
21509
|
+
init_gh_errors();
|
|
21137
21510
|
init_git_auth_mode();
|
|
21138
21511
|
|
|
21139
21512
|
// src/board/load-home-board.ts
|
|
21140
|
-
var
|
|
21141
|
-
var
|
|
21513
|
+
var import_node_fs49 = require("fs");
|
|
21514
|
+
var import_node_path45 = require("path");
|
|
21142
21515
|
init_worktree();
|
|
21143
21516
|
init_paths();
|
|
21144
21517
|
|
|
21145
21518
|
// src/board/board-pins.ts
|
|
21146
|
-
var
|
|
21147
|
-
var
|
|
21148
|
-
var
|
|
21519
|
+
var import_node_crypto11 = require("crypto");
|
|
21520
|
+
var import_node_fs48 = require("fs");
|
|
21521
|
+
var import_node_path44 = require("path");
|
|
21149
21522
|
init_paths();
|
|
21150
21523
|
init_home_board();
|
|
21151
21524
|
var FILE = "home-board-pins.json";
|
|
21152
21525
|
var VERSION = 1;
|
|
21153
21526
|
function pinsFile() {
|
|
21154
|
-
return (0,
|
|
21527
|
+
return (0, import_node_path44.join)(appDataDir(), FILE);
|
|
21155
21528
|
}
|
|
21156
21529
|
function readDisk() {
|
|
21157
21530
|
const path = pinsFile();
|
|
21158
|
-
if (!(0,
|
|
21531
|
+
if (!(0, import_node_fs48.existsSync)(path)) return [];
|
|
21159
21532
|
try {
|
|
21160
|
-
const raw = JSON.parse((0,
|
|
21533
|
+
const raw = JSON.parse((0, import_node_fs48.readFileSync)(path, "utf8"));
|
|
21161
21534
|
if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
|
|
21162
21535
|
return raw.items.filter((item) => item?.id && item.kind && item.ref);
|
|
21163
21536
|
} catch {
|
|
@@ -21165,8 +21538,8 @@ function readDisk() {
|
|
|
21165
21538
|
}
|
|
21166
21539
|
}
|
|
21167
21540
|
function writeDisk(items) {
|
|
21168
|
-
(0,
|
|
21169
|
-
(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");
|
|
21170
21543
|
}
|
|
21171
21544
|
function listBoardPins() {
|
|
21172
21545
|
return readDisk();
|
|
@@ -21187,7 +21560,7 @@ function homeBoardWorkspaceKey(workspaces) {
|
|
|
21187
21560
|
return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
|
|
21188
21561
|
}
|
|
21189
21562
|
function cacheFile() {
|
|
21190
|
-
return (0,
|
|
21563
|
+
return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
|
|
21191
21564
|
}
|
|
21192
21565
|
function emptyInputs() {
|
|
21193
21566
|
return {
|
|
@@ -21213,9 +21586,9 @@ function shouldCacheHomeBoardInputs(inputs) {
|
|
|
21213
21586
|
}
|
|
21214
21587
|
function readDiskCache() {
|
|
21215
21588
|
const path = cacheFile();
|
|
21216
|
-
if (!(0,
|
|
21589
|
+
if (!(0, import_node_fs49.existsSync)(path)) return null;
|
|
21217
21590
|
try {
|
|
21218
|
-
const raw = JSON.parse((0,
|
|
21591
|
+
const raw = JSON.parse((0, import_node_fs49.readFileSync)(path, "utf8"));
|
|
21219
21592
|
if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
|
|
21220
21593
|
return null;
|
|
21221
21594
|
}
|
|
@@ -21229,8 +21602,8 @@ function readDiskCache() {
|
|
|
21229
21602
|
}
|
|
21230
21603
|
function writeDiskCache(entry) {
|
|
21231
21604
|
try {
|
|
21232
|
-
(0,
|
|
21233
|
-
(0,
|
|
21605
|
+
(0, import_node_fs49.mkdirSync)(appDataDir(), { recursive: true });
|
|
21606
|
+
(0, import_node_fs49.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
|
|
21234
21607
|
} catch {
|
|
21235
21608
|
}
|
|
21236
21609
|
}
|
|
@@ -21519,13 +21892,13 @@ async function startMcpServer() {
|
|
|
21519
21892
|
async () => {
|
|
21520
21893
|
const threads = orch.getThreads(true);
|
|
21521
21894
|
const lines = threads.map((t) => {
|
|
21522
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
21523
|
-
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;
|
|
21524
21897
|
const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
|
|
21525
21898
|
const preview = lastMessagePreview(t.messages, 80);
|
|
21526
21899
|
const previewBit = preview ? ` ${preview}` : "";
|
|
21527
21900
|
const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
|
|
21528
|
-
const progress = live?.summary ? ` ${live.summary}` : "";
|
|
21901
|
+
const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
|
|
21529
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}`;
|
|
21530
21903
|
});
|
|
21531
21904
|
return {
|
|
@@ -21587,7 +21960,9 @@ async function startMcpServer() {
|
|
|
21587
21960
|
if (!t) {
|
|
21588
21961
|
return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
|
|
21589
21962
|
}
|
|
21590
|
-
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;
|
|
21591
21966
|
const spend = orch.getThreadUsage(t.id);
|
|
21592
21967
|
const summary = {
|
|
21593
21968
|
id: t.id,
|
|
@@ -21607,8 +21982,8 @@ async function startMcpServer() {
|
|
|
21607
21982
|
devPort: t.devPort,
|
|
21608
21983
|
prUrl: t.prUrl,
|
|
21609
21984
|
lastError: t.lastError ?? null,
|
|
21610
|
-
stillRunning
|
|
21611
|
-
progress:
|
|
21985
|
+
stillRunning,
|
|
21986
|
+
progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
|
|
21612
21987
|
lastActivityAt: live?.updatedAt ?? null,
|
|
21613
21988
|
usage: spend.usage,
|
|
21614
21989
|
lastTurnUsage: spend.lastTurnUsage
|
|
@@ -21889,7 +22264,7 @@ async function startMcpServer() {
|
|
|
21889
22264
|
const ident = issue?.identifier ?? ref.trim();
|
|
21890
22265
|
const attachments = issue ? [
|
|
21891
22266
|
{
|
|
21892
|
-
id: (0,
|
|
22267
|
+
id: (0, import_node_crypto12.randomUUID)(),
|
|
21893
22268
|
name: issue.identifier,
|
|
21894
22269
|
kind: "issue",
|
|
21895
22270
|
content: [
|
|
@@ -21965,7 +22340,7 @@ async function startMcpServer() {
|
|
|
21965
22340
|
);
|
|
21966
22341
|
server.tool(
|
|
21967
22342
|
"wait_for_turn",
|
|
21968
|
-
"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).",
|
|
21969
22344
|
{
|
|
21970
22345
|
ref: import_zod5.z.string(),
|
|
21971
22346
|
timeoutMs: import_zod5.z.number().optional()
|
|
@@ -22157,7 +22532,7 @@ async function startMcpServer() {
|
|
|
22157
22532
|
);
|
|
22158
22533
|
server.tool(
|
|
22159
22534
|
"ask_git",
|
|
22160
|
-
"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.",
|
|
22161
22536
|
{
|
|
22162
22537
|
ref: import_zod5.z.string().describe("Worktree thread id/ref"),
|
|
22163
22538
|
action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
|
|
@@ -22182,8 +22557,26 @@ async function startMcpServer() {
|
|
|
22182
22557
|
]
|
|
22183
22558
|
};
|
|
22184
22559
|
} catch (err) {
|
|
22185
|
-
const
|
|
22186
|
-
|
|
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
|
+
};
|
|
22187
22580
|
}
|
|
22188
22581
|
}
|
|
22189
22582
|
);
|
|
@@ -22578,11 +22971,15 @@ async function startMcpServer() {
|
|
|
22578
22971
|
);
|
|
22579
22972
|
server.tool(
|
|
22580
22973
|
"list_issues",
|
|
22581
|
-
"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.",
|
|
22582
|
-
{
|
|
22583
|
-
|
|
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 }) => {
|
|
22584
22981
|
const root = await resolveRepoRoot(repoPath);
|
|
22585
|
-
const result = await listIssues(root);
|
|
22982
|
+
const result = await listIssues(root, { query, assignee });
|
|
22586
22983
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22587
22984
|
}
|
|
22588
22985
|
);
|