@sideboard-ai/core 0.1.88 → 0.1.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/cursor-runner.cjs +176 -15
- package/dist/agents/cursor-runner.js +11 -2
- package/dist/{agents-LMUFTGKF.js → agents-JXQ5QHDU.js} +4 -4
- package/dist/{agents-ODBP7J6E.js → agents-TUV4NH7S.js} +5 -5
- package/dist/{chunk-RJLBSYUO.js → chunk-35LKGGOC.js} +45 -77
- package/dist/{chunk-WANQFU3S.js → chunk-6XBXVXX2.js} +2 -2
- package/dist/{chunk-7D27DD2X.js → chunk-CIRXAYWS.js} +260 -61
- package/dist/{chunk-B2KIO2SD.js → chunk-CLGO7TLO.js} +2 -2
- package/dist/{chunk-JE75QW2I.js → chunk-GJ2HJQIU.js} +236 -96
- package/dist/{chunk-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
- package/dist/chunk-MMI4RJ5I.js +46 -0
- package/dist/{chunk-UHTNJKZX.js → chunk-NR6APJLD.js} +2 -2
- package/dist/{chunk-6EZRSCIT.js → chunk-QKYO6BHB.js} +2 -2
- package/dist/{chunk-ZXYWWSHZ.js → chunk-R7BQBSDT.js} +254 -61
- package/dist/{chunk-OB6IRIFV.js → chunk-XH2GS2LO.js} +2 -2
- package/dist/{chunk-VZ2L4AEJ.js → chunk-XUWDLRAE.js} +2 -2
- package/dist/{coordinator-prompt-UK5LYFN5.js → coordinator-prompt-AKEY4WSO.js} +2 -2
- package/dist/{coordinator-prompt-CI5SHONJ.js → coordinator-prompt-OQOOD5ET.js} +2 -2
- package/dist/{global-workspace-2YZ2V4I5.js → global-workspace-3GNPQCLE.js} +3 -3
- package/dist/{global-workspace-JQQLPJM5.js → global-workspace-M3OMVDDH.js} +3 -3
- package/dist/index.cjs +998 -463
- package/dist/index.d.cts +77 -19
- package/dist/index.d.ts +77 -19
- package/dist/index.js +181 -50
- package/dist/mcp/run-stdio.cjs +872 -436
- package/dist/mcp/run-stdio.js +132 -48
- package/dist/{workspaces-YWCC3WV4.js → workspaces-ERZC7ULY.js} +4 -4
- package/dist/{workspaces-FDO5L4NI.js → workspaces-J4WG6UFR.js} +4 -4
- package/dist/{worktree-7YNSJ224.js → worktree-DA4BOV7G.js} +7 -1
- package/dist/{worktree-4555QBQ7.js → worktree-EO5QAGJU.js} +7 -1
- package/package.json +1 -1
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -858,17 +858,27 @@ function extractJsonErrorMessage(obj) {
|
|
|
858
858
|
}
|
|
859
859
|
return null;
|
|
860
860
|
}
|
|
861
|
+
function isPinnedStderrLine(line) {
|
|
862
|
+
if (/^\s*at\s/.test(line)) return false;
|
|
863
|
+
return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:/i.test(
|
|
864
|
+
line
|
|
865
|
+
);
|
|
866
|
+
}
|
|
861
867
|
function pushTurnStderr(tail, line, maxLines = 12) {
|
|
862
868
|
const trimmed = line.trim();
|
|
863
869
|
if (!trimmed) return;
|
|
864
870
|
if (NODE_VERSION_FOOTER.test(trimmed)) return;
|
|
865
871
|
if (/^reconnecting\.\.\./i.test(trimmed)) return;
|
|
866
872
|
tail.push(trimmed);
|
|
867
|
-
while (tail.length > maxLines)
|
|
873
|
+
while (tail.length > maxLines) {
|
|
874
|
+
const dropIdx = tail.findIndex((l) => !isPinnedStderrLine(l));
|
|
875
|
+
if (dropIdx === -1) tail.shift();
|
|
876
|
+
else tail.splice(dropIdx, 1);
|
|
877
|
+
}
|
|
868
878
|
}
|
|
869
879
|
function looksLikeMinifiedJsDump(line) {
|
|
870
880
|
if (line.length < 200) return false;
|
|
871
|
-
return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line);
|
|
881
|
+
return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line) || /findFilesWithRipgrep/.test(line) || /@cursor\/sdk\/dist\//.test(line);
|
|
872
882
|
}
|
|
873
883
|
function looksLikeNestedElectronCrash(line) {
|
|
874
884
|
return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
|
|
@@ -883,7 +893,15 @@ function summarizeTurnStderr(tail, maxChars = 500) {
|
|
|
883
893
|
const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
|
|
884
894
|
if (cursorStartup) return clipStderr(cursorStartup, maxChars);
|
|
885
895
|
if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
|
|
886
|
-
|
|
896
|
+
if (tail.some(
|
|
897
|
+
(line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
|
|
898
|
+
)) {
|
|
899
|
+
return clipStderr(
|
|
900
|
+
"Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.",
|
|
901
|
+
maxChars
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
const moduleMissing = [...tail].reverse().find((line) => /cannot find (?:package|module)/i.test(line));
|
|
887
905
|
if (moduleMissing) return clipStderr(moduleMissing, maxChars);
|
|
888
906
|
const useful = tail.filter((line) => !looksLikeMinifiedJsDump(line));
|
|
889
907
|
if (useful.length === 0 && tail.some(looksLikeMinifiedJsDump)) {
|
|
@@ -902,7 +920,7 @@ function looksLikeAgentFailureMessage(text3) {
|
|
|
902
920
|
if (!lower) return false;
|
|
903
921
|
return /you've hit your|hit your (session|weekly|opus) limit|usage limit/.test(lower) || /credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded/.test(lower) || /invalid user api key|invalid api key|not logged in|not authenticated|unauthorized/.test(
|
|
904
922
|
lower
|
|
905
|
-
) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower);
|
|
923
|
+
) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower) || /\[resource_exhausted\]|resource_exhausted/.test(lower) || /findFilesWithRipgrep/.test(text3);
|
|
906
924
|
}
|
|
907
925
|
function fallbackTurnFailDetail(assistantText) {
|
|
908
926
|
const t = assistantText.trim();
|
|
@@ -924,6 +942,9 @@ function humanizeAgentFailDetail(detail) {
|
|
|
924
942
|
if (/\b429\b|rate.?limit|too many requests/.test(lower)) {
|
|
925
943
|
return `${raw} \u2014 wait a moment and retry.`;
|
|
926
944
|
}
|
|
945
|
+
if (/\[resource_exhausted\]|resource_exhausted|findfileswithripgrep/.test(lower)) {
|
|
946
|
+
return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
|
|
947
|
+
}
|
|
927
948
|
if (/invalid user api key|invalid api key|not logged in|not authenticated|unauthorized|authentication|please run.*login|codex login|claude auth|cursor api/.test(
|
|
928
949
|
lower
|
|
929
950
|
)) {
|
|
@@ -2880,42 +2901,124 @@ var init_app_settings = __esm({
|
|
|
2880
2901
|
}
|
|
2881
2902
|
});
|
|
2882
2903
|
|
|
2904
|
+
// src/git/github-agent-auth.ts
|
|
2905
|
+
function githubAgentAuthDir() {
|
|
2906
|
+
const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
|
|
2907
|
+
if (override) return override;
|
|
2908
|
+
return (0, import_node_path12.join)((0, import_node_os4.homedir)(), ".sideboard-git-auth");
|
|
2909
|
+
}
|
|
2910
|
+
function githubCredentialStorePath() {
|
|
2911
|
+
return (0, import_node_path12.join)(githubAgentAuthDir(), "git-credentials");
|
|
2912
|
+
}
|
|
2913
|
+
function githubGhConfigDir() {
|
|
2914
|
+
return (0, import_node_path12.join)(githubAgentAuthDir(), "gh");
|
|
2915
|
+
}
|
|
2916
|
+
function writePrivateFile2(file, body) {
|
|
2917
|
+
(0, import_node_fs11.mkdirSync)((0, import_node_path12.dirname)(file), { recursive: true, mode: 448 });
|
|
2918
|
+
try {
|
|
2919
|
+
(0, import_node_fs11.chmodSync)((0, import_node_path12.dirname)(file), 448);
|
|
2920
|
+
} catch {
|
|
2921
|
+
}
|
|
2922
|
+
(0, import_node_fs11.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
2923
|
+
try {
|
|
2924
|
+
(0, import_node_fs11.chmodSync)(file, 384);
|
|
2925
|
+
} catch {
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
function gitCredentialStoreContents(token) {
|
|
2929
|
+
return `https://x-access-token:${encodeURIComponent(token)}@github.com
|
|
2930
|
+
`;
|
|
2931
|
+
}
|
|
2932
|
+
function ghHostsYml(token, user = "x-access-token") {
|
|
2933
|
+
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
2934
|
+
return [
|
|
2935
|
+
"github.com:",
|
|
2936
|
+
" git_protocol: https",
|
|
2937
|
+
` user: ${u}`,
|
|
2938
|
+
` oauth_token: ${token}`,
|
|
2939
|
+
" users:",
|
|
2940
|
+
` ${u}:`,
|
|
2941
|
+
` oauth_token: ${token}`,
|
|
2942
|
+
""
|
|
2943
|
+
].join("\n");
|
|
2944
|
+
}
|
|
2945
|
+
function materializeGithubAgentAuth(token, user) {
|
|
2946
|
+
const trimmed = token.trim();
|
|
2947
|
+
if (!trimmed) return;
|
|
2948
|
+
const root = githubAgentAuthDir();
|
|
2949
|
+
(0, import_node_fs11.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
2950
|
+
try {
|
|
2951
|
+
(0, import_node_fs11.chmodSync)(root, 448);
|
|
2952
|
+
} catch {
|
|
2953
|
+
}
|
|
2954
|
+
writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
|
|
2955
|
+
const ghDir = githubGhConfigDir();
|
|
2956
|
+
(0, import_node_fs11.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
2957
|
+
writePrivateFile2((0, import_node_path12.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
2958
|
+
writePrivateFile2((0, import_node_path12.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
2959
|
+
}
|
|
2960
|
+
function githubAgentAuthReady() {
|
|
2961
|
+
return (0, import_node_fs11.existsSync)(githubCredentialStorePath()) && (0, import_node_fs11.existsSync)((0, import_node_path12.join)(githubGhConfigDir(), "hosts.yml"));
|
|
2962
|
+
}
|
|
2963
|
+
function githubCredentialHelperGitConfig() {
|
|
2964
|
+
const file = githubCredentialStorePath();
|
|
2965
|
+
return [
|
|
2966
|
+
{ key: "credential.helper", value: "" },
|
|
2967
|
+
{ key: "credential.helper", value: `store --file=${file}` }
|
|
2968
|
+
];
|
|
2969
|
+
}
|
|
2970
|
+
function githubGhConfigEnv() {
|
|
2971
|
+
return {
|
|
2972
|
+
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
2973
|
+
GH_PROMPT_DISABLED: "1"
|
|
2974
|
+
};
|
|
2975
|
+
}
|
|
2976
|
+
var import_node_fs11, import_node_os4, import_node_path12;
|
|
2977
|
+
var init_github_agent_auth = __esm({
|
|
2978
|
+
"src/git/github-agent-auth.ts"() {
|
|
2979
|
+
"use strict";
|
|
2980
|
+
import_node_fs11 = require("fs");
|
|
2981
|
+
import_node_os4 = require("os");
|
|
2982
|
+
import_node_path12 = require("path");
|
|
2983
|
+
}
|
|
2984
|
+
});
|
|
2985
|
+
|
|
2883
2986
|
// src/agents/path.ts
|
|
2884
2987
|
function prependPathDir(env, dir) {
|
|
2885
|
-
if (!dir || !(0,
|
|
2988
|
+
if (!dir || !(0, import_node_fs12.existsSync)(dir)) return;
|
|
2886
2989
|
const current = env.PATH ?? "";
|
|
2887
|
-
const parts = current.split(
|
|
2990
|
+
const parts = current.split(import_node_path13.delimiter).filter(Boolean);
|
|
2888
2991
|
if (parts.includes(dir)) {
|
|
2889
2992
|
env.PATH = current;
|
|
2890
2993
|
return;
|
|
2891
2994
|
}
|
|
2892
|
-
env.PATH = [dir, ...parts].join(
|
|
2995
|
+
env.PATH = [dir, ...parts].join(import_node_path13.delimiter);
|
|
2893
2996
|
}
|
|
2894
|
-
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0,
|
|
2895
|
-
return (0,
|
|
2997
|
+
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os5.homedir)()) {
|
|
2998
|
+
return (0, import_node_path13.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
|
|
2896
2999
|
}
|
|
2897
3000
|
function isConductorBundledCli(filePath) {
|
|
2898
3001
|
const p = (filePath ?? "").replace(/\\/g, "/");
|
|
2899
3002
|
return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
|
|
2900
3003
|
}
|
|
2901
3004
|
function ensureAgentPath(env = process.env) {
|
|
2902
|
-
const home = env.HOME || env.USERPROFILE || (0,
|
|
3005
|
+
const home = env.HOME || env.USERPROFILE || (0, import_node_os5.homedir)();
|
|
2903
3006
|
const current = env.PATH ?? "";
|
|
2904
|
-
const parts = current.split(
|
|
3007
|
+
const parts = current.split(import_node_path13.delimiter).filter(Boolean);
|
|
2905
3008
|
const seen = new Set(parts);
|
|
2906
3009
|
const extras = [
|
|
2907
|
-
...EXTRA_BIN_DIRS.map((rel) => (0,
|
|
3010
|
+
...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path13.join)(home, rel)),
|
|
2908
3011
|
"/opt/homebrew/bin",
|
|
2909
3012
|
"/usr/local/bin",
|
|
2910
3013
|
// Keep after Homebrew/npm so a user-installed CLI still wins.
|
|
2911
3014
|
conductorBundledBinDir(home)
|
|
2912
3015
|
];
|
|
2913
3016
|
for (const dir of extras.reverse()) {
|
|
2914
|
-
if (!dir || seen.has(dir) || !(0,
|
|
3017
|
+
if (!dir || seen.has(dir) || !(0, import_node_fs12.existsSync)(dir)) continue;
|
|
2915
3018
|
parts.unshift(dir);
|
|
2916
3019
|
seen.add(dir);
|
|
2917
3020
|
}
|
|
2918
|
-
const next = parts.join(
|
|
3021
|
+
const next = parts.join(import_node_path13.delimiter);
|
|
2919
3022
|
env.PATH = next;
|
|
2920
3023
|
return next;
|
|
2921
3024
|
}
|
|
@@ -2929,7 +3032,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
|
|
|
2929
3032
|
stdio: ["ignore", "pipe", "ignore"]
|
|
2930
3033
|
}).trim().split(/\r?\n/).find(Boolean);
|
|
2931
3034
|
if (prefix) {
|
|
2932
|
-
const binDir = process.platform === "win32" ? prefix : (0,
|
|
3035
|
+
const binDir = process.platform === "win32" ? prefix : (0, import_node_path13.join)(prefix, "bin");
|
|
2933
3036
|
prependPathDir(env, binDir);
|
|
2934
3037
|
}
|
|
2935
3038
|
} catch {
|
|
@@ -2957,14 +3060,14 @@ function withExportedPath(command, pathValue) {
|
|
|
2957
3060
|
if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
|
|
2958
3061
|
return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
|
|
2959
3062
|
}
|
|
2960
|
-
var
|
|
3063
|
+
var import_node_fs12, import_node_child_process2, import_node_os5, import_node_path13, EXTRA_BIN_DIRS;
|
|
2961
3064
|
var init_path = __esm({
|
|
2962
3065
|
"src/agents/path.ts"() {
|
|
2963
3066
|
"use strict";
|
|
2964
|
-
|
|
3067
|
+
import_node_fs12 = require("fs");
|
|
2965
3068
|
import_node_child_process2 = require("child_process");
|
|
2966
|
-
|
|
2967
|
-
|
|
3069
|
+
import_node_os5 = require("os");
|
|
3070
|
+
import_node_path13 = require("path");
|
|
2968
3071
|
EXTRA_BIN_DIRS = [
|
|
2969
3072
|
".local/bin",
|
|
2970
3073
|
".cargo/bin",
|
|
@@ -3089,42 +3192,43 @@ function appendIndexedGitConfig(existing, entries) {
|
|
|
3089
3192
|
return out;
|
|
3090
3193
|
}
|
|
3091
3194
|
function githubAgentGitEnv(existing) {
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
function githubHttpsBearerEnv(existing, token) {
|
|
3095
|
-
const rewrite = githubAgentGitEnv(existing);
|
|
3096
|
-
const header = appendIndexedGitConfig(
|
|
3097
|
-
{ ...existing, ...rewrite },
|
|
3098
|
-
[
|
|
3099
|
-
{
|
|
3100
|
-
key: "http.https://github.com/.extraHeader",
|
|
3101
|
-
value: `AUTHORIZATION: bearer ${token}`
|
|
3102
|
-
}
|
|
3103
|
-
]
|
|
3104
|
-
);
|
|
3105
|
-
return { ...rewrite, ...header };
|
|
3195
|
+
const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
|
|
3196
|
+
return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
|
|
3106
3197
|
}
|
|
3107
3198
|
function applyGithubGitAuthEnv(existing, opts) {
|
|
3108
3199
|
const out = { ...nonInteractiveGitProcessEnv() };
|
|
3200
|
+
const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
|
|
3201
|
+
if (token) materializeGithubAgentAuth(token);
|
|
3202
|
+
Object.assign(out, githubGhConfigEnv());
|
|
3109
3203
|
if (opts.mode === "ssh") return out;
|
|
3110
|
-
|
|
3111
|
-
const provided = existingToken ? "" : opts.token?.trim() || "";
|
|
3112
|
-
const token = existingToken || provided;
|
|
3113
|
-
Object.assign(
|
|
3114
|
-
out,
|
|
3115
|
-
token ? githubHttpsBearerEnv(existing, token) : githubAgentGitEnv(existing)
|
|
3116
|
-
);
|
|
3117
|
-
if (provided) out.GH_TOKEN = provided;
|
|
3204
|
+
Object.assign(out, githubAgentGitEnv(existing));
|
|
3118
3205
|
return out;
|
|
3119
3206
|
}
|
|
3207
|
+
function scrubGithubTokensFromChildEnv(env) {
|
|
3208
|
+
for (const key of GITHUB_CHILD_TOKEN_KEYS) {
|
|
3209
|
+
delete env[key];
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
function mergeAgentGitAuthEnv(env, gitEnv) {
|
|
3213
|
+
Object.assign(env, gitEnv);
|
|
3214
|
+
scrubGithubTokensFromChildEnv(env);
|
|
3215
|
+
}
|
|
3120
3216
|
async function resolveGithubAgentToken(mode, cwd) {
|
|
3121
|
-
if (mode ===
|
|
3122
|
-
|
|
3123
|
-
try {
|
|
3124
|
-
return await resolveGhAuthToken(cwd);
|
|
3125
|
-
} catch {
|
|
3126
|
-
return null;
|
|
3217
|
+
if (tokenMemo && tokenMemo.mode === mode && Date.now() - tokenMemo.at < TOKEN_TTL_MS) {
|
|
3218
|
+
return tokenMemo.value;
|
|
3127
3219
|
}
|
|
3220
|
+
let value = null;
|
|
3221
|
+
if (mode === "token") {
|
|
3222
|
+
value = getGithubPat();
|
|
3223
|
+
} else {
|
|
3224
|
+
try {
|
|
3225
|
+
value = await resolveGhAuthToken(cwd);
|
|
3226
|
+
} catch {
|
|
3227
|
+
value = null;
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
tokenMemo = { mode, value, at: Date.now() };
|
|
3231
|
+
return value;
|
|
3128
3232
|
}
|
|
3129
3233
|
async function resolveAgentGitAuthEnv(existing, opts) {
|
|
3130
3234
|
let mode = "auto";
|
|
@@ -3146,7 +3250,40 @@ async function resolveAgentGitAuthEnv(existing, opts) {
|
|
|
3146
3250
|
}
|
|
3147
3251
|
return applyGithubGitAuthEnv(existing, { mode, token });
|
|
3148
3252
|
}
|
|
3149
|
-
function
|
|
3253
|
+
async function warmGithubAgentAuth(opts) {
|
|
3254
|
+
if (!opts?.force && githubAgentAuthReady()) return;
|
|
3255
|
+
await resolveAgentGitAuthEnv(void 0, opts);
|
|
3256
|
+
}
|
|
3257
|
+
function normalizeWritableRoot(raw) {
|
|
3258
|
+
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
3259
|
+
return trimmed && (0, import_node_path14.isAbsolute)(trimmed) ? trimmed : null;
|
|
3260
|
+
}
|
|
3261
|
+
async function resolveCodexGitWritableRoots(cwd) {
|
|
3262
|
+
const roots = /* @__PURE__ */ new Set();
|
|
3263
|
+
const authDir = normalizeWritableRoot(githubAgentAuthDir());
|
|
3264
|
+
if (authDir) roots.add(authDir);
|
|
3265
|
+
try {
|
|
3266
|
+
const [gitDir, commonDir] = await Promise.all([
|
|
3267
|
+
git(["rev-parse", "--absolute-git-dir"], cwd, { reject: false, timeoutMs: 5e3 }),
|
|
3268
|
+
git(["rev-parse", "--path-format=absolute", "--git-common-dir"], cwd, {
|
|
3269
|
+
reject: false,
|
|
3270
|
+
timeoutMs: 5e3
|
|
3271
|
+
})
|
|
3272
|
+
]);
|
|
3273
|
+
const gitDirPath = gitDir.exitCode === 0 ? normalizeWritableRoot(gitDir.stdout) : null;
|
|
3274
|
+
const commonPath = commonDir.exitCode === 0 ? normalizeWritableRoot(commonDir.stdout) : null;
|
|
3275
|
+
if (gitDirPath) roots.add(gitDirPath);
|
|
3276
|
+
if (commonPath) roots.add(commonPath);
|
|
3277
|
+
} catch {
|
|
3278
|
+
}
|
|
3279
|
+
return [...roots];
|
|
3280
|
+
}
|
|
3281
|
+
function codexSandboxWritableRootsArgs(roots) {
|
|
3282
|
+
const abs = [...new Set(roots.map(normalizeWritableRoot).filter(Boolean))];
|
|
3283
|
+
if (abs.length === 0) return [];
|
|
3284
|
+
return ["-c", `sandbox_workspace_write.writable_roots=${JSON.stringify(abs)}`];
|
|
3285
|
+
}
|
|
3286
|
+
function codexUnattendedGitConfigArgs(sandbox, opts) {
|
|
3150
3287
|
const args = [
|
|
3151
3288
|
"-c",
|
|
3152
3289
|
'shell_environment_policy.inherit="all"',
|
|
@@ -3155,54 +3292,65 @@ function codexUnattendedGitConfigArgs(sandbox) {
|
|
|
3155
3292
|
];
|
|
3156
3293
|
if (sandbox === "workspace-write") {
|
|
3157
3294
|
args.push("-c", "sandbox_workspace_write.network_access=true");
|
|
3295
|
+
args.push(...codexSandboxWritableRootsArgs(opts?.writableRoots ?? []));
|
|
3158
3296
|
}
|
|
3159
3297
|
return args;
|
|
3160
3298
|
}
|
|
3161
3299
|
function formatGitAuthModeDirective(mode) {
|
|
3300
|
+
const shared = [
|
|
3301
|
+
"- `git` and `gh` already authenticate in this process. Do not look for tokens in the environment, paste credentials into commands, or switch remotes to SSH.",
|
|
3302
|
+
"- Do not set GitHub token environment variables, pass `--with-token`, or run `gh auth login` from this turn.",
|
|
3303
|
+
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below.",
|
|
3304
|
+
"- If git/gh fail with auth errors, tell the user to run `gh auth login` on this Mac (or set a PAT in Account \u2192 GitHub). Do not wait for a Keychain dialog."
|
|
3305
|
+
];
|
|
3162
3306
|
switch (mode) {
|
|
3163
3307
|
case "gh":
|
|
3164
3308
|
return [
|
|
3165
3309
|
"Git authentication (Account \u2192 GitHub mode: gh CLI):",
|
|
3166
3310
|
"- This process rewrites `git@github.com:` and `ssh://git@github.com/` to HTTPS.",
|
|
3167
|
-
|
|
3168
|
-
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
3311
|
+
...shared
|
|
3169
3312
|
].join("\n");
|
|
3170
3313
|
case "ssh":
|
|
3171
3314
|
return [
|
|
3172
3315
|
"Git authentication (Account \u2192 GitHub mode: SSH):",
|
|
3173
3316
|
"- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
|
|
3174
3317
|
"- SSH is batch-mode: it will not prompt for a Keychain password. If push fails with `Permission denied (publickey)`, tell the user to unlock ssh-agent or switch Account \u2192 GitHub to Auto / gh CLI \u2014 do not rewrite remotes yourself.",
|
|
3175
|
-
"-
|
|
3318
|
+
"- `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.",
|
|
3319
|
+
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
3176
3320
|
].join("\n");
|
|
3177
3321
|
case "token":
|
|
3178
3322
|
return [
|
|
3179
3323
|
"Git authentication (Account \u2192 GitHub mode: personal access token):",
|
|
3180
3324
|
"- This process rewrites GitHub SSH remotes to HTTPS.",
|
|
3181
|
-
|
|
3182
|
-
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
3325
|
+
...shared
|
|
3183
3326
|
].join("\n");
|
|
3184
3327
|
case "auto":
|
|
3185
3328
|
default:
|
|
3186
3329
|
return [
|
|
3187
3330
|
"Git authentication (Account \u2192 GitHub mode: auto):",
|
|
3188
|
-
"- This process rewrites GitHub SSH remotes to HTTPS
|
|
3189
|
-
|
|
3190
|
-
"- If HTTPS auth fails, tell the user to run `gh auth login` on this Mac or set Account \u2192 GitHub to a PAT \u2014 do not wait for a Keychain dialog."
|
|
3331
|
+
"- This process rewrites GitHub SSH remotes to HTTPS so git/ssh never prompt the macOS Keychain (required for unattended orchestrator turns).",
|
|
3332
|
+
...shared
|
|
3191
3333
|
].join("\n");
|
|
3192
3334
|
}
|
|
3193
3335
|
}
|
|
3194
|
-
var HTTPS_REWRITE;
|
|
3336
|
+
var import_node_path14, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
|
|
3195
3337
|
var init_git_auth_mode = __esm({
|
|
3196
3338
|
"src/git/git-auth-mode.ts"() {
|
|
3197
3339
|
"use strict";
|
|
3340
|
+
import_node_path14 = require("path");
|
|
3198
3341
|
init_app_settings();
|
|
3342
|
+
init_github_agent_auth();
|
|
3199
3343
|
init_run();
|
|
3200
3344
|
HTTPS_REWRITE = [
|
|
3201
3345
|
{ key: "url.https://github.com/.insteadOf", value: "git@github.com:" },
|
|
3202
|
-
{ key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" }
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3346
|
+
{ key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" }
|
|
3347
|
+
];
|
|
3348
|
+
TOKEN_TTL_MS = 12 * 60 * 60 * 1e3;
|
|
3349
|
+
tokenMemo = null;
|
|
3350
|
+
GITHUB_CHILD_TOKEN_KEYS = [
|
|
3351
|
+
"GH_TOKEN",
|
|
3352
|
+
"GITHUB_TOKEN",
|
|
3353
|
+
"GH_ENTERPRISE_TOKEN"
|
|
3206
3354
|
];
|
|
3207
3355
|
}
|
|
3208
3356
|
});
|
|
@@ -3535,10 +3683,12 @@ __export(worktree_exports, {
|
|
|
3535
3683
|
getPr: () => getPr,
|
|
3536
3684
|
getPrChecks: () => getPrChecks,
|
|
3537
3685
|
getPrDetails: () => getPrDetails,
|
|
3686
|
+
getPrForHeadBranch: () => getPrForHeadBranch,
|
|
3538
3687
|
getPrMeta: () => getPrMeta,
|
|
3539
3688
|
ghHeadRef: () => ghHeadRef,
|
|
3540
3689
|
ghRepoSelectArgs: () => ghRepoSelectArgs,
|
|
3541
3690
|
githubAgentGitEnv: () => githubAgentGitEnv,
|
|
3691
|
+
isDefaultishSourceRef: () => isDefaultishSourceRef,
|
|
3542
3692
|
isDirty: () => isDirty,
|
|
3543
3693
|
isPlaceholderBranch: () => isPlaceholderBranch,
|
|
3544
3694
|
isSideboardScratchPath: () => isSideboardScratchPath,
|
|
@@ -3556,6 +3706,7 @@ __export(worktree_exports, {
|
|
|
3556
3706
|
resolveDiffBaseRef: () => resolveDiffBaseRef,
|
|
3557
3707
|
resolveGithubRepoSlug: () => resolveGithubRepoSlug,
|
|
3558
3708
|
resolvePrSelector: () => resolvePrSelector,
|
|
3709
|
+
resolvePrSelectors: () => resolvePrSelectors,
|
|
3559
3710
|
resolveRepoRoot: () => resolveRepoRoot,
|
|
3560
3711
|
resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
|
|
3561
3712
|
slugify: () => slugify,
|
|
@@ -3664,7 +3815,7 @@ async function originGhRepoEnv(cwd, opts) {
|
|
|
3664
3815
|
await ensureGhPreferOrigin(cwd);
|
|
3665
3816
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
3666
3817
|
const mode = opts?.mode ?? getGithubGitAuthMode();
|
|
3667
|
-
const token =
|
|
3818
|
+
const token = await resolveGithubAgentToken(mode, cwd);
|
|
3668
3819
|
return {
|
|
3669
3820
|
...applyGithubGitAuthEnv(opts?.env, { mode, token }),
|
|
3670
3821
|
...slug ? { GH_REPO: slug } : {}
|
|
@@ -3804,13 +3955,78 @@ async function getPr(repoPath, number) {
|
|
|
3804
3955
|
if (exitCode !== 0 || !stdout.trim()) return null;
|
|
3805
3956
|
return JSON.parse(stdout);
|
|
3806
3957
|
}
|
|
3807
|
-
function
|
|
3808
|
-
|
|
3958
|
+
function normalizeGitBranchName(ref) {
|
|
3959
|
+
return ref.trim().replace(/^refs\/heads\//, "").replace(/^origin\//, "");
|
|
3960
|
+
}
|
|
3961
|
+
function isDefaultishSourceRef(ref) {
|
|
3962
|
+
const n = normalizeGitBranchName(ref ?? "").toLowerCase();
|
|
3963
|
+
return !n || n === "head" || n === "default" || n === "main" || n === "master" || n === "develop" || n === "trunk";
|
|
3964
|
+
}
|
|
3965
|
+
function resolvePrSelectors(thread) {
|
|
3966
|
+
const out = [];
|
|
3967
|
+
const push = (value) => {
|
|
3968
|
+
const v = value?.trim();
|
|
3969
|
+
if (!v || out.includes(v)) return;
|
|
3970
|
+
out.push(v);
|
|
3971
|
+
};
|
|
3972
|
+
push(thread.prUrl);
|
|
3809
3973
|
if (thread.sourceType === "pr" && thread.sourceRef?.trim()) {
|
|
3810
|
-
|
|
3974
|
+
push(thread.sourceRef.replace(/^#/, "").trim());
|
|
3975
|
+
}
|
|
3976
|
+
push(thread.branchName);
|
|
3977
|
+
if (thread.sourceType === "branch") {
|
|
3978
|
+
const source = normalizeGitBranchName(thread.sourceRef ?? "");
|
|
3979
|
+
if (source && !isDefaultishSourceRef(source) && source !== thread.branchName?.trim()) {
|
|
3980
|
+
push(source);
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
return out;
|
|
3984
|
+
}
|
|
3985
|
+
function resolvePrSelector(thread) {
|
|
3986
|
+
return resolvePrSelectors(thread)[0] ?? null;
|
|
3987
|
+
}
|
|
3988
|
+
async function getPrForHeadBranch(repoPath, branch) {
|
|
3989
|
+
const head = normalizeGitBranchName(branch);
|
|
3990
|
+
if (!head || isDefaultishSourceRef(head)) return null;
|
|
3991
|
+
const slug = await resolveGithubRepoSlug(repoPath);
|
|
3992
|
+
const viewArgs = [
|
|
3993
|
+
"pr",
|
|
3994
|
+
"view",
|
|
3995
|
+
head,
|
|
3996
|
+
"--json",
|
|
3997
|
+
"number,title,headRefName,url,isCrossRepository"
|
|
3998
|
+
];
|
|
3999
|
+
if (slug) viewArgs.push("--repo", slug);
|
|
4000
|
+
const viewed = await gh(viewArgs, repoPath, { reject: false });
|
|
4001
|
+
if (viewed.exitCode === 0 && viewed.stdout.trim()) {
|
|
4002
|
+
try {
|
|
4003
|
+
return JSON.parse(viewed.stdout);
|
|
4004
|
+
} catch {
|
|
4005
|
+
return null;
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
const listHead = slug ? ghHeadRef(slug, head) : head;
|
|
4009
|
+
const listArgs = [
|
|
4010
|
+
"pr",
|
|
4011
|
+
"list",
|
|
4012
|
+
"--head",
|
|
4013
|
+
listHead,
|
|
4014
|
+
"--json",
|
|
4015
|
+
"number,title,headRefName,url,isCrossRepository",
|
|
4016
|
+
"--limit",
|
|
4017
|
+
"1",
|
|
4018
|
+
"--state",
|
|
4019
|
+
"open"
|
|
4020
|
+
];
|
|
4021
|
+
if (slug) listArgs.push("--repo", slug);
|
|
4022
|
+
const listed = await gh(listArgs, repoPath, { reject: false });
|
|
4023
|
+
if (listed.exitCode !== 0 || !listed.stdout.trim()) return null;
|
|
4024
|
+
try {
|
|
4025
|
+
const rows = JSON.parse(listed.stdout);
|
|
4026
|
+
return rows[0] ?? null;
|
|
4027
|
+
} catch {
|
|
4028
|
+
return null;
|
|
3811
4029
|
}
|
|
3812
|
-
if (thread.branchName?.trim()) return thread.branchName.trim();
|
|
3813
|
-
return null;
|
|
3814
4030
|
}
|
|
3815
4031
|
function normalizeGhTime(value) {
|
|
3816
4032
|
if (typeof value !== "string" || !value.trim()) return null;
|
|
@@ -4136,7 +4352,7 @@ async function fetchPrHead(repoPath, number, localBranch) {
|
|
|
4136
4352
|
const label = opts?.ghAuth ? `${remote} (gh auth)` : remote;
|
|
4137
4353
|
const gitOpts = { reject: false };
|
|
4138
4354
|
if (opts?.ghAuth) {
|
|
4139
|
-
const token = await
|
|
4355
|
+
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), repoPath);
|
|
4140
4356
|
if (!token) {
|
|
4141
4357
|
errors.push(`${label}: gh auth token unavailable`);
|
|
4142
4358
|
return false;
|
|
@@ -4187,7 +4403,7 @@ async function fetchPrHead(repoPath, number, localBranch) {
|
|
|
4187
4403
|
const ensureOid = async (remote, opts) => {
|
|
4188
4404
|
const gitOpts = { reject: false };
|
|
4189
4405
|
if (opts?.ghAuth) {
|
|
4190
|
-
const token = await
|
|
4406
|
+
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), repoPath);
|
|
4191
4407
|
if (!token) return false;
|
|
4192
4408
|
gitOpts.env = { GIT_TERMINAL_PROMPT: "0" };
|
|
4193
4409
|
gitOpts.config = {
|
|
@@ -4255,8 +4471,8 @@ function isLocalPrFetchBranch(ref) {
|
|
|
4255
4471
|
}
|
|
4256
4472
|
async function createThreadWorktree(opts) {
|
|
4257
4473
|
let branchName = `thread/${opts.slug}`;
|
|
4258
|
-
const worktreePath = (0,
|
|
4259
|
-
if ((0,
|
|
4474
|
+
const worktreePath = (0, import_node_path15.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
4475
|
+
if ((0, import_node_fs13.existsSync)(worktreePath)) {
|
|
4260
4476
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
4261
4477
|
}
|
|
4262
4478
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -4325,8 +4541,8 @@ ${add.stdout}`;
|
|
|
4325
4541
|
async function createExistingBranchWorktree(opts) {
|
|
4326
4542
|
const branchName = opts.branchName.trim();
|
|
4327
4543
|
if (!branchName) throw new Error("branch name required");
|
|
4328
|
-
const worktreePath = (0,
|
|
4329
|
-
if ((0,
|
|
4544
|
+
const worktreePath = (0, import_node_path15.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
4545
|
+
if ((0, import_node_fs13.existsSync)(worktreePath)) {
|
|
4330
4546
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
4331
4547
|
}
|
|
4332
4548
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -4437,7 +4653,7 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
4437
4653
|
if (ssh.exitCode === 0) return;
|
|
4438
4654
|
const sshErr = (ssh.stderr || ssh.stdout).trim();
|
|
4439
4655
|
const slug = await resolveGithubRepoSlug(worktreePath);
|
|
4440
|
-
const token = await
|
|
4656
|
+
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
|
|
4441
4657
|
if (!slug || !token) {
|
|
4442
4658
|
throw new Error(
|
|
4443
4659
|
sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
|
|
@@ -4614,10 +4830,10 @@ function sameRepoPath(a, b) {
|
|
|
4614
4830
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
4615
4831
|
}
|
|
4616
4832
|
function listLocalThreadBranchSlugs(repoPath) {
|
|
4617
|
-
const refsDir = (0,
|
|
4618
|
-
if (!(0,
|
|
4833
|
+
const refsDir = (0, import_node_path15.join)(repoPath, ".git", "refs", "heads", "thread");
|
|
4834
|
+
if (!(0, import_node_fs13.existsSync)(refsDir)) return [];
|
|
4619
4835
|
try {
|
|
4620
|
-
return (0,
|
|
4836
|
+
return (0, import_node_fs13.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
|
|
4621
4837
|
} catch {
|
|
4622
4838
|
return [];
|
|
4623
4839
|
}
|
|
@@ -4625,8 +4841,8 @@ function listLocalThreadBranchSlugs(repoPath) {
|
|
|
4625
4841
|
function collectTakenTeamSlugs(repoPath) {
|
|
4626
4842
|
const taken = /* @__PURE__ */ new Set();
|
|
4627
4843
|
const root = worktreesRoot(repoPath);
|
|
4628
|
-
if ((0,
|
|
4629
|
-
for (const entry of (0,
|
|
4844
|
+
if ((0, import_node_fs13.existsSync)(root)) {
|
|
4845
|
+
for (const entry of (0, import_node_fs13.readdirSync)(root, { withFileTypes: true })) {
|
|
4630
4846
|
if (entry.isDirectory() && entry.name !== ".DS_Store") {
|
|
4631
4847
|
taken.add(normalizeTakenSlug(entry.name));
|
|
4632
4848
|
}
|
|
@@ -4647,18 +4863,18 @@ function allocateTeamSlug(repoPath) {
|
|
|
4647
4863
|
const taken = collectTakenTeamSlugs(repoPath);
|
|
4648
4864
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
4649
4865
|
const team = allocateTeamName(taken);
|
|
4650
|
-
const path = (0,
|
|
4651
|
-
if (!(0,
|
|
4866
|
+
const path = (0, import_node_path15.join)(worktreesRoot(repoPath), team.slug);
|
|
4867
|
+
if (!(0, import_node_fs13.existsSync)(path)) return team;
|
|
4652
4868
|
taken.add(team.slug);
|
|
4653
4869
|
}
|
|
4654
4870
|
throw new Error("No available soccer team worktree directories left");
|
|
4655
4871
|
}
|
|
4656
|
-
var
|
|
4872
|
+
var import_node_fs13, import_node_path15;
|
|
4657
4873
|
var init_worktree = __esm({
|
|
4658
4874
|
"src/git/worktree.ts"() {
|
|
4659
4875
|
"use strict";
|
|
4660
|
-
|
|
4661
|
-
|
|
4876
|
+
import_node_fs13 = require("fs");
|
|
4877
|
+
import_node_path15 = require("path");
|
|
4662
4878
|
init_paths();
|
|
4663
4879
|
init_thread_store();
|
|
4664
4880
|
init_teams();
|
|
@@ -4800,7 +5016,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
4800
5016
|
function ensureGlobalCoordinatorCwd(opts) {
|
|
4801
5017
|
const dir = globalAgentCwd();
|
|
4802
5018
|
try {
|
|
4803
|
-
(0,
|
|
5019
|
+
(0, import_node_fs14.mkdirSync)(dir, { recursive: true });
|
|
4804
5020
|
} catch {
|
|
4805
5021
|
return dir;
|
|
4806
5022
|
}
|
|
@@ -4808,7 +5024,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
4808
5024
|
let orchId = opts?.orchestratorThreadId?.trim() || "";
|
|
4809
5025
|
if (!orchId) {
|
|
4810
5026
|
try {
|
|
4811
|
-
const existing = (0,
|
|
5027
|
+
const existing = (0, import_node_fs14.readFileSync)((0, import_node_path16.join)(dir, "AGENTS.md"), "utf8");
|
|
4812
5028
|
const m = existing.match(
|
|
4813
5029
|
/YOUR orchestration thread id is `([0-9a-f-]{36})`/i
|
|
4814
5030
|
);
|
|
@@ -4850,9 +5066,9 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
4850
5066
|
"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."
|
|
4851
5067
|
].join("\n");
|
|
4852
5068
|
try {
|
|
4853
|
-
(0,
|
|
5069
|
+
(0, import_node_fs14.writeFileSync)((0, import_node_path16.join)(dir, "CLAUDE.md"), `${body}
|
|
4854
5070
|
`, "utf8");
|
|
4855
|
-
(0,
|
|
5071
|
+
(0, import_node_fs14.writeFileSync)((0, import_node_path16.join)(dir, "AGENTS.md"), `${body}
|
|
4856
5072
|
`, "utf8");
|
|
4857
5073
|
} catch {
|
|
4858
5074
|
}
|
|
@@ -4884,12 +5100,12 @@ function coordinatorSystemPrompt(opts) {
|
|
|
4884
5100
|
formatWorkspaceInventory(opts.workspaces)
|
|
4885
5101
|
].join("\n");
|
|
4886
5102
|
}
|
|
4887
|
-
var
|
|
5103
|
+
var import_node_fs14, import_node_path16, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
|
|
4888
5104
|
var init_coordinator_prompt = __esm({
|
|
4889
5105
|
"src/orchestrator/coordinator-prompt.ts"() {
|
|
4890
5106
|
"use strict";
|
|
4891
|
-
|
|
4892
|
-
|
|
5107
|
+
import_node_fs14 = require("fs");
|
|
5108
|
+
import_node_path16 = require("path");
|
|
4893
5109
|
init_worktree();
|
|
4894
5110
|
init_app_settings();
|
|
4895
5111
|
init_paths();
|
|
@@ -4905,7 +5121,7 @@ var init_coordinator_prompt = __esm({
|
|
|
4905
5121
|
"- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
|
|
4906
5122
|
"- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
|
|
4907
5123
|
"- list_threads / get_thread \u2014 fleet status (what is going on)",
|
|
4908
|
-
"- ask_user \u2014 multiple-choice
|
|
5124
|
+
"- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API). Never for hellos, check-ins, or invented \u201Cwhat should we do?\u201D menus \u2014 reply in chat. Explain options first, description on every option, then wait.",
|
|
4909
5125
|
"- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
|
|
4910
5126
|
"Workspaces:",
|
|
4911
5127
|
"- add_workspace / remove_workspace \u2014 register or unregister a git repo",
|
|
@@ -5187,32 +5403,32 @@ var init_global_workspace = __esm({
|
|
|
5187
5403
|
|
|
5188
5404
|
// src/brightsy/config.ts
|
|
5189
5405
|
function brightsyConfigPath() {
|
|
5190
|
-
return (0,
|
|
5406
|
+
return (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
|
|
5191
5407
|
}
|
|
5192
5408
|
function loadBrightsyConfig() {
|
|
5193
5409
|
const path = brightsyConfigPath();
|
|
5194
|
-
if (!(0,
|
|
5410
|
+
if (!(0, import_node_fs15.existsSync)(path)) {
|
|
5195
5411
|
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
5196
5412
|
}
|
|
5197
|
-
const raw = JSON.parse((0,
|
|
5413
|
+
const raw = JSON.parse((0, import_node_fs15.readFileSync)(path, "utf8"));
|
|
5198
5414
|
if (!raw.access_token || !raw.account_id) {
|
|
5199
5415
|
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
5200
5416
|
}
|
|
5201
5417
|
return raw;
|
|
5202
5418
|
}
|
|
5203
5419
|
function saveBrightsyConfig(cfg) {
|
|
5204
|
-
(0,
|
|
5420
|
+
(0, import_node_fs15.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
5205
5421
|
`, {
|
|
5206
5422
|
mode: 384
|
|
5207
5423
|
});
|
|
5208
5424
|
}
|
|
5209
|
-
var
|
|
5425
|
+
var import_node_fs15, import_node_os6, import_node_path17;
|
|
5210
5426
|
var init_config = __esm({
|
|
5211
5427
|
"src/brightsy/config.ts"() {
|
|
5212
5428
|
"use strict";
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5429
|
+
import_node_fs15 = require("fs");
|
|
5430
|
+
import_node_os6 = require("os");
|
|
5431
|
+
import_node_path17 = require("path");
|
|
5216
5432
|
}
|
|
5217
5433
|
});
|
|
5218
5434
|
|
|
@@ -5227,22 +5443,22 @@ var init_accounts = __esm({
|
|
|
5227
5443
|
|
|
5228
5444
|
// src/brightsy/connected-teams.ts
|
|
5229
5445
|
function storePath4() {
|
|
5230
|
-
return (0,
|
|
5446
|
+
return (0, import_node_path18.join)(appDataDir(), "brightsy-teams.json");
|
|
5231
5447
|
}
|
|
5232
5448
|
function readStore4() {
|
|
5233
5449
|
const path = storePath4();
|
|
5234
|
-
if (!(0,
|
|
5450
|
+
if (!(0, import_node_fs16.existsSync)(path)) return [];
|
|
5235
5451
|
try {
|
|
5236
|
-
const parsed = JSON.parse((0,
|
|
5452
|
+
const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path, "utf8"));
|
|
5237
5453
|
return Array.isArray(parsed.teams) ? parsed.teams : [];
|
|
5238
5454
|
} catch {
|
|
5239
5455
|
return [];
|
|
5240
5456
|
}
|
|
5241
5457
|
}
|
|
5242
5458
|
function writeStore2(teams) {
|
|
5243
|
-
(0,
|
|
5459
|
+
(0, import_node_fs16.mkdirSync)(appDataDir(), { recursive: true });
|
|
5244
5460
|
const path = storePath4();
|
|
5245
|
-
(0,
|
|
5461
|
+
(0, import_node_fs16.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
|
|
5246
5462
|
`, {
|
|
5247
5463
|
mode: 384
|
|
5248
5464
|
});
|
|
@@ -5354,12 +5570,12 @@ function brightsyMcpServerName(slug) {
|
|
|
5354
5570
|
const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
|
|
5355
5571
|
return `brightsy_${cleaned || "team"}`;
|
|
5356
5572
|
}
|
|
5357
|
-
var
|
|
5573
|
+
var import_node_fs16, import_node_path18;
|
|
5358
5574
|
var init_connected_teams = __esm({
|
|
5359
5575
|
"src/brightsy/connected-teams.ts"() {
|
|
5360
5576
|
"use strict";
|
|
5361
|
-
|
|
5362
|
-
|
|
5577
|
+
import_node_fs16 = require("fs");
|
|
5578
|
+
import_node_path18 = require("path");
|
|
5363
5579
|
init_paths();
|
|
5364
5580
|
init_accounts();
|
|
5365
5581
|
init_config();
|
|
@@ -5686,11 +5902,11 @@ async function syncCliForTarget(accountId) {
|
|
|
5686
5902
|
}
|
|
5687
5903
|
applyConnectedTeamToCli(team);
|
|
5688
5904
|
}
|
|
5689
|
-
var
|
|
5905
|
+
var import_node_fs17, brightsyAdapter;
|
|
5690
5906
|
var init_brightsy = __esm({
|
|
5691
5907
|
"src/agents/brightsy.ts"() {
|
|
5692
5908
|
"use strict";
|
|
5693
|
-
|
|
5909
|
+
import_node_fs17 = require("fs");
|
|
5694
5910
|
init_run();
|
|
5695
5911
|
init_connected_teams();
|
|
5696
5912
|
init_config();
|
|
@@ -5705,7 +5921,7 @@ var init_brightsy = __esm({
|
|
|
5705
5921
|
async detect() {
|
|
5706
5922
|
const brightsy = resolveAgentExecutable("brightsy");
|
|
5707
5923
|
if (brightsy !== "brightsy") {
|
|
5708
|
-
if (!(0,
|
|
5924
|
+
if (!(0, import_node_fs17.existsSync)(brightsy)) {
|
|
5709
5925
|
return {
|
|
5710
5926
|
agent: "brightsy",
|
|
5711
5927
|
installed: false,
|
|
@@ -5833,13 +6049,38 @@ var init_profile = __esm({
|
|
|
5833
6049
|
|
|
5834
6050
|
// src/agents/node-launch.ts
|
|
5835
6051
|
function isAsarPath(filePath) {
|
|
6052
|
+
if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
|
|
5836
6053
|
return /\.asar([/\\]|$)/.test(filePath);
|
|
5837
6054
|
}
|
|
6055
|
+
function unpackedAsarPath(filePath) {
|
|
6056
|
+
if (!isAsarPath(filePath)) return null;
|
|
6057
|
+
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
6058
|
+
if (unpacked === filePath) return null;
|
|
6059
|
+
return (0, import_node_fs18.existsSync)(unpacked) ? unpacked : null;
|
|
6060
|
+
}
|
|
6061
|
+
function nodeReadableScriptPath(scriptPath) {
|
|
6062
|
+
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
6063
|
+
}
|
|
6064
|
+
async function findSystemNode() {
|
|
6065
|
+
const whichNode = await run("which", ["node"], { reject: false });
|
|
6066
|
+
const fromWhich = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : "";
|
|
6067
|
+
if (fromWhich && !isElectronLikeCommand(fromWhich)) return fromWhich;
|
|
6068
|
+
const fallbacks = [
|
|
6069
|
+
...WELL_KNOWN_NODE_BINS,
|
|
6070
|
+
(0, import_node_path19.join)((0, import_node_os7.homedir)(), ".local/share/fnm/aliases/default/bin/node"),
|
|
6071
|
+
(0, import_node_path19.join)((0, import_node_os7.homedir)(), ".nvm/current/bin/node")
|
|
6072
|
+
];
|
|
6073
|
+
for (const bin of fallbacks) {
|
|
6074
|
+
if ((0, import_node_fs18.existsSync)(bin) && !isElectronLikeCommand(bin)) return bin;
|
|
6075
|
+
}
|
|
6076
|
+
return null;
|
|
6077
|
+
}
|
|
5838
6078
|
function applyNodeLaunch(launch, args) {
|
|
6079
|
+
const readableArgs = args.map(nodeReadableScriptPath);
|
|
5839
6080
|
if (!launch.env.ELECTRON_RUN_AS_NODE) {
|
|
5840
|
-
return { file: launch.file, args, env: launch.env };
|
|
6081
|
+
return { file: launch.file, args: readableArgs, env: launch.env };
|
|
5841
6082
|
}
|
|
5842
|
-
const wrapped = wrapElectronAsNodeLaunch(launch.file,
|
|
6083
|
+
const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
|
|
5843
6084
|
if (process.platform === "win32") {
|
|
5844
6085
|
return { file: wrapped.file, args: wrapped.args, env: launch.env };
|
|
5845
6086
|
}
|
|
@@ -5848,27 +6089,73 @@ function applyNodeLaunch(launch, args) {
|
|
|
5848
6089
|
return { file: wrapped.file, args: wrapped.args, env };
|
|
5849
6090
|
}
|
|
5850
6091
|
async function resolveNodeLaunch(scriptPath) {
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
const whichNode = await run("which", ["node"], { reject: false });
|
|
5858
|
-
const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
|
|
5859
|
-
if (nodeBin) {
|
|
5860
|
-
return { file: nodeBin, env: {} };
|
|
6092
|
+
const script = nodeReadableScriptPath(scriptPath);
|
|
6093
|
+
if (!isAsarPath(script)) {
|
|
6094
|
+
const nodeBin = await findSystemNode();
|
|
6095
|
+
if (nodeBin) {
|
|
6096
|
+
return { file: nodeBin, env: {} };
|
|
6097
|
+
}
|
|
5861
6098
|
}
|
|
5862
6099
|
return {
|
|
5863
6100
|
file: process.execPath,
|
|
5864
6101
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
5865
6102
|
};
|
|
5866
6103
|
}
|
|
6104
|
+
var import_node_fs18, import_node_os7, import_node_path19, WELL_KNOWN_NODE_BINS;
|
|
5867
6105
|
var init_node_launch = __esm({
|
|
5868
6106
|
"src/agents/node-launch.ts"() {
|
|
5869
6107
|
"use strict";
|
|
6108
|
+
import_node_fs18 = require("fs");
|
|
6109
|
+
import_node_os7 = require("os");
|
|
6110
|
+
import_node_path19 = require("path");
|
|
5870
6111
|
init_nested_electron_env();
|
|
5871
6112
|
init_run();
|
|
6113
|
+
WELL_KNOWN_NODE_BINS = [
|
|
6114
|
+
"/opt/homebrew/bin/node",
|
|
6115
|
+
"/usr/local/bin/node"
|
|
6116
|
+
];
|
|
6117
|
+
}
|
|
6118
|
+
});
|
|
6119
|
+
|
|
6120
|
+
// src/agents/packaged-runtime.ts
|
|
6121
|
+
function electronResourcesPath() {
|
|
6122
|
+
const resources = process.resourcesPath;
|
|
6123
|
+
if (typeof resources !== "string" || !resources) return null;
|
|
6124
|
+
return resources;
|
|
6125
|
+
}
|
|
6126
|
+
function packagedCursorRuntimeDir() {
|
|
6127
|
+
const resources = electronResourcesPath();
|
|
6128
|
+
if (!resources) return null;
|
|
6129
|
+
const dir = (0, import_node_path20.join)(resources, "cursor-runtime");
|
|
6130
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
6131
|
+
return dir;
|
|
6132
|
+
}
|
|
6133
|
+
function packagedCursorRunnerPath() {
|
|
6134
|
+
const dir = packagedCursorRuntimeDir();
|
|
6135
|
+
return dir ? (0, import_node_path20.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
6136
|
+
}
|
|
6137
|
+
function packagedMcpDir() {
|
|
6138
|
+
const resources = electronResourcesPath();
|
|
6139
|
+
if (!resources) return null;
|
|
6140
|
+
const dir = (0, import_node_path20.join)(resources, "sideboard-mcp");
|
|
6141
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
6142
|
+
return dir;
|
|
6143
|
+
}
|
|
6144
|
+
function packagedMcpStdioPath() {
|
|
6145
|
+
const dir = packagedMcpDir();
|
|
6146
|
+
return dir ? (0, import_node_path20.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
6147
|
+
}
|
|
6148
|
+
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
6149
|
+
const dir = packagedCursorRuntimeDir();
|
|
6150
|
+
if (!dir) return null;
|
|
6151
|
+
return (0, import_node_path20.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
6152
|
+
}
|
|
6153
|
+
var import_node_fs19, import_node_path20;
|
|
6154
|
+
var init_packaged_runtime = __esm({
|
|
6155
|
+
"src/agents/packaged-runtime.ts"() {
|
|
6156
|
+
"use strict";
|
|
6157
|
+
import_node_fs19 = require("fs");
|
|
6158
|
+
import_node_path20 = require("path");
|
|
5872
6159
|
}
|
|
5873
6160
|
});
|
|
5874
6161
|
|
|
@@ -5955,35 +6242,37 @@ function corePackageDir() {
|
|
|
5955
6242
|
try {
|
|
5956
6243
|
const url = import_meta.url;
|
|
5957
6244
|
if (typeof url === "string" && url.length > 0) {
|
|
5958
|
-
return (0,
|
|
6245
|
+
return (0, import_node_path21.dirname)((0, import_node_url.fileURLToPath)(url));
|
|
5959
6246
|
}
|
|
5960
6247
|
} catch {
|
|
5961
6248
|
}
|
|
5962
6249
|
try {
|
|
5963
|
-
const req = (0, import_node_module.createRequire)((0,
|
|
5964
|
-
return (0,
|
|
6250
|
+
const req = (0, import_node_module.createRequire)((0, import_node_path21.join)(process.cwd(), "package.json"));
|
|
6251
|
+
return (0, import_node_path21.dirname)(req.resolve("@sideboard-ai/core"));
|
|
5965
6252
|
} catch {
|
|
5966
6253
|
return process.cwd();
|
|
5967
6254
|
}
|
|
5968
6255
|
}
|
|
5969
6256
|
function findSideboardMcpJsEntry() {
|
|
5970
6257
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
5971
|
-
if (override && (0,
|
|
6258
|
+
if (override && (0, import_node_fs20.existsSync)(override)) return override;
|
|
6259
|
+
const packaged = packagedMcpStdioPath();
|
|
6260
|
+
if (packaged) return packaged;
|
|
5972
6261
|
let dir = corePackageDir();
|
|
5973
6262
|
for (let i = 0; i < 10; i++) {
|
|
5974
6263
|
const candidates = [
|
|
5975
|
-
(0,
|
|
5976
|
-
(0,
|
|
5977
|
-
(0,
|
|
5978
|
-
(0,
|
|
5979
|
-
(0,
|
|
5980
|
-
(0,
|
|
5981
|
-
(0,
|
|
6264
|
+
(0, import_node_path21.join)(dir, "mcp/run-stdio.js"),
|
|
6265
|
+
(0, import_node_path21.join)(dir, "mcp/run-stdio.cjs"),
|
|
6266
|
+
(0, import_node_path21.join)(dir, "dist/mcp/run-stdio.js"),
|
|
6267
|
+
(0, import_node_path21.join)(dir, "dist/mcp/run-stdio.cjs"),
|
|
6268
|
+
(0, import_node_path21.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
|
|
6269
|
+
(0, import_node_path21.join)(dir, "packages/cli/dist/index.js"),
|
|
6270
|
+
(0, import_node_path21.join)(dir, "cli/dist/index.js")
|
|
5982
6271
|
];
|
|
5983
6272
|
for (const p of candidates) {
|
|
5984
|
-
if ((0,
|
|
6273
|
+
if ((0, import_node_fs20.existsSync)(p) && !isAsarPath(p)) return p;
|
|
5985
6274
|
}
|
|
5986
|
-
const parent = (0,
|
|
6275
|
+
const parent = (0, import_node_path21.dirname)(dir);
|
|
5987
6276
|
if (parent === dir) break;
|
|
5988
6277
|
dir = parent;
|
|
5989
6278
|
}
|
|
@@ -5995,12 +6284,14 @@ async function resolveSideboardMcpServer() {
|
|
|
5995
6284
|
const isCli = /[/\\]cli[/\\]dist[/\\]index\.js$/.test(entry);
|
|
5996
6285
|
const scriptArgs = isCli ? [entry, "mcp"] : [entry];
|
|
5997
6286
|
const launch = applyNodeLaunch(await resolveNodeLaunch(entry), scriptArgs);
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6287
|
+
if (launch.file !== "/bin/sh" && !isElectronLikeCommand(launch.file)) {
|
|
6288
|
+
return {
|
|
6289
|
+
name: "sideboard",
|
|
6290
|
+
command: launch.file,
|
|
6291
|
+
args: launch.args,
|
|
6292
|
+
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
6293
|
+
};
|
|
6294
|
+
}
|
|
6004
6295
|
}
|
|
6005
6296
|
const which = await run("which", ["sideboard"], { reject: false });
|
|
6006
6297
|
if (which.exitCode === 0 && which.stdout.trim()) {
|
|
@@ -6023,7 +6314,10 @@ async function buildInjectedMcpServers(opts) {
|
|
|
6023
6314
|
sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
|
|
6024
6315
|
}
|
|
6025
6316
|
try {
|
|
6026
|
-
|
|
6317
|
+
mergeAgentGitAuthEnv(
|
|
6318
|
+
sideboard.env,
|
|
6319
|
+
await resolveAgentGitAuthEnv(sideboard.env)
|
|
6320
|
+
);
|
|
6027
6321
|
} catch {
|
|
6028
6322
|
}
|
|
6029
6323
|
servers.push(sideboard);
|
|
@@ -6045,9 +6339,6 @@ async function buildInjectedMcpServers(opts) {
|
|
|
6045
6339
|
}
|
|
6046
6340
|
return servers;
|
|
6047
6341
|
}
|
|
6048
|
-
function shSingleQuote(value) {
|
|
6049
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
6050
|
-
}
|
|
6051
6342
|
function cursorSafeMcpLaunch(command, args) {
|
|
6052
6343
|
if (process.platform === "win32") {
|
|
6053
6344
|
return args && args.length > 0 ? { command, args } : { command };
|
|
@@ -6055,31 +6346,13 @@ function cursorSafeMcpLaunch(command, args) {
|
|
|
6055
6346
|
const unwrapped = unwrapStrippedElectronLaunch(command, args);
|
|
6056
6347
|
const file = unwrapped?.file ?? command;
|
|
6057
6348
|
const fileArgs = unwrapped?.args ?? args ?? [];
|
|
6058
|
-
|
|
6059
|
-
return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
|
|
6060
|
-
}
|
|
6061
|
-
const dir = (0, import_node_path17.join)(appDataDir(), "mcp-launch");
|
|
6062
|
-
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
6063
|
-
const wrap = (0, import_node_path17.join)(dir, "cursor-electron-as-node.sh");
|
|
6064
|
-
const execLine = [file, ...fileArgs].map(shSingleQuote).join(" ");
|
|
6065
|
-
(0, import_node_fs17.writeFileSync)(
|
|
6066
|
-
wrap,
|
|
6067
|
-
[
|
|
6068
|
-
"#!/bin/sh",
|
|
6069
|
-
"vars=`printenv | awk -F= '/^(ELECTRON_|CHROME_)/{print $1}'`",
|
|
6070
|
-
'[ -n "$vars" ] && unset $vars',
|
|
6071
|
-
"export ELECTRON_RUN_AS_NODE=1",
|
|
6072
|
-
`exec ${execLine} "$@"`,
|
|
6073
|
-
""
|
|
6074
|
-
].join("\n"),
|
|
6075
|
-
{ mode: 493 }
|
|
6076
|
-
);
|
|
6077
|
-
return { command: wrap };
|
|
6349
|
+
return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
|
|
6078
6350
|
}
|
|
6079
6351
|
function mcpSpawnEnv(env) {
|
|
6080
6352
|
if (!env) return void 0;
|
|
6081
6353
|
const out = { ...env };
|
|
6082
6354
|
delete out.ELECTRON_RUN_AS_NODE;
|
|
6355
|
+
delete out.ELECTRON_RUN_AS_NODE;
|
|
6083
6356
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
6084
6357
|
}
|
|
6085
6358
|
function toCursorMcpServers(servers) {
|
|
@@ -6139,19 +6412,19 @@ function writeMcpServersConfig(servers) {
|
|
|
6139
6412
|
...env ? { env } : {}
|
|
6140
6413
|
};
|
|
6141
6414
|
}
|
|
6142
|
-
const dir = (0,
|
|
6143
|
-
const cfgPath = (0,
|
|
6144
|
-
(0,
|
|
6415
|
+
const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path21.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
|
|
6416
|
+
const cfgPath = (0, import_node_path21.join)(dir, "mcp.json");
|
|
6417
|
+
(0, import_node_fs20.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
6145
6418
|
return cfgPath;
|
|
6146
6419
|
}
|
|
6147
|
-
var
|
|
6420
|
+
var import_node_fs20, import_node_module, import_node_os8, import_node_path21, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
|
|
6148
6421
|
var init_injected_mcp = __esm({
|
|
6149
6422
|
"src/agents/injected-mcp.ts"() {
|
|
6150
6423
|
"use strict";
|
|
6151
|
-
|
|
6424
|
+
import_node_fs20 = require("fs");
|
|
6152
6425
|
import_node_module = require("module");
|
|
6153
|
-
|
|
6154
|
-
|
|
6426
|
+
import_node_os8 = require("os");
|
|
6427
|
+
import_node_path21 = require("path");
|
|
6155
6428
|
import_node_url = require("url");
|
|
6156
6429
|
init_run();
|
|
6157
6430
|
init_config();
|
|
@@ -6160,6 +6433,7 @@ var init_injected_mcp = __esm({
|
|
|
6160
6433
|
init_app_settings();
|
|
6161
6434
|
init_paths();
|
|
6162
6435
|
init_node_launch();
|
|
6436
|
+
init_packaged_runtime();
|
|
6163
6437
|
init_nested_electron_env();
|
|
6164
6438
|
init_git_auth_mode();
|
|
6165
6439
|
import_meta = {};
|
|
@@ -6229,7 +6503,7 @@ var PLAN_MODE_INSTRUCTION;
|
|
|
6229
6503
|
var init_types = __esm({
|
|
6230
6504
|
"src/agents/types.ts"() {
|
|
6231
6505
|
"use strict";
|
|
6232
|
-
PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope): (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
|
|
6506
|
+
PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope) \u2014 not greetings, check-ins, or an invented task menu: (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. If one option is the obvious default, proceed without asking. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
|
|
6233
6507
|
}
|
|
6234
6508
|
});
|
|
6235
6509
|
|
|
@@ -6339,11 +6613,11 @@ function parseIssuesJson(raw) {
|
|
|
6339
6613
|
}
|
|
6340
6614
|
return [];
|
|
6341
6615
|
}
|
|
6342
|
-
var
|
|
6616
|
+
var import_node_fs21, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
|
|
6343
6617
|
var init_claude = __esm({
|
|
6344
6618
|
"src/agents/claude.ts"() {
|
|
6345
6619
|
"use strict";
|
|
6346
|
-
|
|
6620
|
+
import_node_fs21 = require("fs");
|
|
6347
6621
|
init_run();
|
|
6348
6622
|
init_app_settings();
|
|
6349
6623
|
init_claude_mcp();
|
|
@@ -6372,7 +6646,7 @@ var init_claude = __esm({
|
|
|
6372
6646
|
async detect() {
|
|
6373
6647
|
const claude = resolveClaudeExecutable();
|
|
6374
6648
|
if (claude !== "claude") {
|
|
6375
|
-
if (!(0,
|
|
6649
|
+
if (!(0, import_node_fs21.existsSync)(claude)) {
|
|
6376
6650
|
return {
|
|
6377
6651
|
agent: "claude",
|
|
6378
6652
|
installed: false,
|
|
@@ -6609,7 +6883,7 @@ async function listCodexModels() {
|
|
|
6609
6883
|
if (codex === "codex") {
|
|
6610
6884
|
const which = await run("which", ["codex"], { reject: false });
|
|
6611
6885
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
6612
|
-
} else if (!(0,
|
|
6886
|
+
} else if (!(0, import_node_fs22.existsSync)(codex)) {
|
|
6613
6887
|
return FALLBACK_CODEX_MODELS;
|
|
6614
6888
|
}
|
|
6615
6889
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -6644,12 +6918,12 @@ function usageFromCodex(usage) {
|
|
|
6644
6918
|
}
|
|
6645
6919
|
function codexConfigHasNetworkAccess() {
|
|
6646
6920
|
const candidates = [
|
|
6647
|
-
(0,
|
|
6648
|
-
(0,
|
|
6921
|
+
(0, import_node_path22.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
|
|
6922
|
+
(0, import_node_path22.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
|
|
6649
6923
|
];
|
|
6650
6924
|
for (const path of candidates) {
|
|
6651
|
-
if (!(0,
|
|
6652
|
-
const text3 = (0,
|
|
6925
|
+
if (!(0, import_node_fs22.existsSync)(path)) continue;
|
|
6926
|
+
const text3 = (0, import_node_fs22.readFileSync)(path, "utf8");
|
|
6653
6927
|
if (/network_access\s*=\s*true/.test(text3)) return true;
|
|
6654
6928
|
}
|
|
6655
6929
|
return false;
|
|
@@ -6681,21 +6955,21 @@ function asRecord(value) {
|
|
|
6681
6955
|
return void 0;
|
|
6682
6956
|
}
|
|
6683
6957
|
function codexLooksAuthenticated() {
|
|
6684
|
-
const authPath = (0,
|
|
6685
|
-
if (!(0,
|
|
6958
|
+
const authPath = (0, import_node_path22.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
|
|
6959
|
+
if (!(0, import_node_fs22.existsSync)(authPath)) return false;
|
|
6686
6960
|
try {
|
|
6687
|
-
return (0,
|
|
6961
|
+
return (0, import_node_fs22.statSync)(authPath).size > 2;
|
|
6688
6962
|
} catch {
|
|
6689
6963
|
return false;
|
|
6690
6964
|
}
|
|
6691
6965
|
}
|
|
6692
|
-
var
|
|
6966
|
+
var import_node_fs22, import_node_os9, import_node_path22, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
6693
6967
|
var init_codex = __esm({
|
|
6694
6968
|
"src/agents/codex.ts"() {
|
|
6695
6969
|
"use strict";
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6970
|
+
import_node_fs22 = require("fs");
|
|
6971
|
+
import_node_os9 = require("os");
|
|
6972
|
+
import_node_path22 = require("path");
|
|
6699
6973
|
init_run();
|
|
6700
6974
|
init_app_settings();
|
|
6701
6975
|
init_global_workspace();
|
|
@@ -6720,7 +6994,7 @@ var init_codex = __esm({
|
|
|
6720
6994
|
async detect() {
|
|
6721
6995
|
const codex = resolveAgentExecutable("codex");
|
|
6722
6996
|
if (codex !== "codex") {
|
|
6723
|
-
if (!(0,
|
|
6997
|
+
if (!(0, import_node_fs22.existsSync)(codex)) {
|
|
6724
6998
|
return {
|
|
6725
6999
|
agent: "codex",
|
|
6726
7000
|
installed: false,
|
|
@@ -6793,8 +7067,13 @@ var init_codex = __esm({
|
|
|
6793
7067
|
// `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
|
|
6794
7068
|
"-c",
|
|
6795
7069
|
'approval_policy="never"',
|
|
6796
|
-
// Seatbelt cannot use the login Keychain;
|
|
6797
|
-
|
|
7070
|
+
// Seatbelt cannot use the login Keychain; inherit GH_CONFIG_DIR / GIT_CONFIG_*.
|
|
7071
|
+
// Default policy also strips *TOKEN*. Linked worktrees need the main
|
|
7072
|
+
// repo `.git` (+ `.git/worktrees/<name>`) as writable_roots so git commit
|
|
7073
|
+
// can create index.lock.
|
|
7074
|
+
...codexUnattendedGitConfigArgs(mode.codexSandbox, {
|
|
7075
|
+
writableRoots: mode.codexSandbox === "workspace-write" ? await resolveCodexGitWritableRoots(thread.worktreePath) : []
|
|
7076
|
+
}),
|
|
6798
7077
|
...model ? ["--model", model] : [],
|
|
6799
7078
|
...mcpOverrides
|
|
6800
7079
|
];
|
|
@@ -7115,6 +7394,74 @@ var init_cursor_events = __esm({
|
|
|
7115
7394
|
}
|
|
7116
7395
|
});
|
|
7117
7396
|
|
|
7397
|
+
// src/agents/cursor-ripgrep.ts
|
|
7398
|
+
function rgBinaryName() {
|
|
7399
|
+
return process.platform === "win32" ? "rg.exe" : "rg";
|
|
7400
|
+
}
|
|
7401
|
+
function platformRipgrepPackage() {
|
|
7402
|
+
return `@cursor/sdk-${process.platform}-${process.arch}`;
|
|
7403
|
+
}
|
|
7404
|
+
function usableRipgrepPath(candidate) {
|
|
7405
|
+
const raw = candidate?.trim();
|
|
7406
|
+
if (!raw || !(0, import_node_path23.isAbsolute)(raw)) return null;
|
|
7407
|
+
const readable = nodeReadableScriptPath(raw);
|
|
7408
|
+
if (!(0, import_node_fs23.existsSync)(readable) || isAsarPath(readable)) return null;
|
|
7409
|
+
return readable;
|
|
7410
|
+
}
|
|
7411
|
+
function walkForBundledRipgrep(startFile) {
|
|
7412
|
+
if (!startFile) return null;
|
|
7413
|
+
const pkg = platformRipgrepPackage();
|
|
7414
|
+
const name = rgBinaryName();
|
|
7415
|
+
let dir = (0, import_node_path23.dirname)((0, import_node_path23.resolve)(startFile));
|
|
7416
|
+
const root = (0, import_node_path23.parse)(dir).root;
|
|
7417
|
+
while (dir !== root) {
|
|
7418
|
+
const hit = usableRipgrepPath((0, import_node_path23.join)(dir, "node_modules", pkg, "bin", name));
|
|
7419
|
+
if (hit) return hit;
|
|
7420
|
+
const next = (0, import_node_path23.dirname)(dir);
|
|
7421
|
+
if (next === dir) break;
|
|
7422
|
+
dir = next;
|
|
7423
|
+
}
|
|
7424
|
+
return null;
|
|
7425
|
+
}
|
|
7426
|
+
function requireResolveBundledRipgrep(fromFile) {
|
|
7427
|
+
try {
|
|
7428
|
+
const req = (0, import_node_module2.createRequire)(fromFile);
|
|
7429
|
+
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
7430
|
+
return usableRipgrepPath((0, import_node_path23.join)((0, import_node_path23.dirname)(pkgJson), "bin", rgBinaryName()));
|
|
7431
|
+
} catch {
|
|
7432
|
+
return null;
|
|
7433
|
+
}
|
|
7434
|
+
}
|
|
7435
|
+
function resolveCursorRipgrepPath(opts) {
|
|
7436
|
+
const env = opts?.env ?? process.env;
|
|
7437
|
+
const fromEnv = usableRipgrepPath(env[RIPGREP_ENV]);
|
|
7438
|
+
if (fromEnv) return fromEnv;
|
|
7439
|
+
const fromPackaged = usableRipgrepPath(
|
|
7440
|
+
packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
|
|
7441
|
+
);
|
|
7442
|
+
if (fromPackaged) return fromPackaged;
|
|
7443
|
+
const start = opts?.startFile?.trim() || process.argv[1] || (0, import_node_url2.fileURLToPath)(import_meta2.url);
|
|
7444
|
+
return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
|
|
7445
|
+
}
|
|
7446
|
+
function cursorRipgrepEnv(opts) {
|
|
7447
|
+
const path = resolveCursorRipgrepPath(opts);
|
|
7448
|
+
return path ? { [RIPGREP_ENV]: path } : {};
|
|
7449
|
+
}
|
|
7450
|
+
var import_node_fs23, import_node_module2, import_node_path23, import_node_url2, import_meta2, RIPGREP_ENV;
|
|
7451
|
+
var init_cursor_ripgrep = __esm({
|
|
7452
|
+
"src/agents/cursor-ripgrep.ts"() {
|
|
7453
|
+
"use strict";
|
|
7454
|
+
import_node_fs23 = require("fs");
|
|
7455
|
+
import_node_module2 = require("module");
|
|
7456
|
+
import_node_path23 = require("path");
|
|
7457
|
+
import_node_url2 = require("url");
|
|
7458
|
+
init_node_launch();
|
|
7459
|
+
init_packaged_runtime();
|
|
7460
|
+
import_meta2 = {};
|
|
7461
|
+
RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
7462
|
+
}
|
|
7463
|
+
});
|
|
7464
|
+
|
|
7118
7465
|
// src/agents/cursor.ts
|
|
7119
7466
|
function resolveCursorApiKey() {
|
|
7120
7467
|
const fromEnv = (process.env.CURSOR_API_KEY || "").trim();
|
|
@@ -7154,51 +7501,55 @@ function entryDir() {
|
|
|
7154
7501
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
7155
7502
|
if (cjsDir) return cjsDir;
|
|
7156
7503
|
try {
|
|
7157
|
-
return (0,
|
|
7504
|
+
return (0, import_node_path24.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
|
|
7158
7505
|
} catch {
|
|
7159
7506
|
try {
|
|
7160
|
-
const req = (0,
|
|
7161
|
-
return (0,
|
|
7507
|
+
const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
|
|
7508
|
+
return (0, import_node_path24.dirname)(req.resolve("@sideboard-ai/core"));
|
|
7162
7509
|
} catch {
|
|
7163
7510
|
return process.cwd();
|
|
7164
7511
|
}
|
|
7165
7512
|
}
|
|
7166
7513
|
}
|
|
7167
7514
|
function cursorRunnerPath() {
|
|
7515
|
+
const packaged = packagedCursorRunnerPath();
|
|
7516
|
+
if (packaged) return packaged;
|
|
7168
7517
|
const root = entryDir();
|
|
7169
7518
|
const candidates = [
|
|
7170
|
-
(0,
|
|
7171
|
-
(0,
|
|
7519
|
+
(0, import_node_path24.join)(root, "agents", "cursor-runner.js"),
|
|
7520
|
+
(0, import_node_path24.join)(root, "agents", "cursor-runner.cjs"),
|
|
7172
7521
|
// If somehow resolved from package root instead of dist/
|
|
7173
|
-
(0,
|
|
7174
|
-
(0,
|
|
7522
|
+
(0, import_node_path24.join)(root, "dist", "agents", "cursor-runner.js"),
|
|
7523
|
+
(0, import_node_path24.join)(root, "dist", "agents", "cursor-runner.cjs"),
|
|
7175
7524
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
7176
|
-
(0,
|
|
7177
|
-
(0,
|
|
7525
|
+
(0, import_node_path24.join)(root, "cursor-runner.ts"),
|
|
7526
|
+
(0, import_node_path24.join)(root, "src", "agents", "cursor-runner.ts")
|
|
7178
7527
|
];
|
|
7179
7528
|
for (const candidate of candidates) {
|
|
7180
|
-
if ((0,
|
|
7529
|
+
if ((0, import_node_fs24.existsSync)(candidate)) return candidate;
|
|
7181
7530
|
}
|
|
7182
7531
|
return candidates[0];
|
|
7183
7532
|
}
|
|
7184
|
-
var
|
|
7533
|
+
var import_node_fs24, import_node_module3, import_node_path24, import_node_url3, import_sdk, import_meta3, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
|
|
7185
7534
|
var init_cursor = __esm({
|
|
7186
7535
|
"src/agents/cursor.ts"() {
|
|
7187
7536
|
"use strict";
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7537
|
+
import_node_fs24 = require("fs");
|
|
7538
|
+
import_node_module3 = require("module");
|
|
7539
|
+
import_node_path24 = require("path");
|
|
7540
|
+
import_node_url3 = require("url");
|
|
7192
7541
|
import_sdk = require("@cursor/sdk");
|
|
7193
7542
|
init_run();
|
|
7194
7543
|
init_app_settings();
|
|
7195
7544
|
init_global_workspace();
|
|
7196
7545
|
init_cursor_events();
|
|
7197
7546
|
init_injected_mcp();
|
|
7547
|
+
init_cursor_ripgrep();
|
|
7198
7548
|
init_node_launch();
|
|
7549
|
+
init_packaged_runtime();
|
|
7199
7550
|
init_turn_input();
|
|
7200
7551
|
init_cursor_events();
|
|
7201
|
-
|
|
7552
|
+
import_meta3 = {};
|
|
7202
7553
|
FALLBACK_CURSOR_MODELS = [
|
|
7203
7554
|
{ id: "default", displayName: "Auto" },
|
|
7204
7555
|
{ id: "composer-2.5", displayName: "Composer 2.5" },
|
|
@@ -7265,6 +7616,7 @@ var init_cursor = __esm({
|
|
|
7265
7616
|
stdin: JSON.stringify(req),
|
|
7266
7617
|
env: {
|
|
7267
7618
|
...launch.env,
|
|
7619
|
+
...cursorRipgrepEnv({ startFile: runner }),
|
|
7268
7620
|
...apiKey ? { CURSOR_API_KEY: apiKey } : {}
|
|
7269
7621
|
}
|
|
7270
7622
|
};
|
|
@@ -7316,7 +7668,7 @@ async function listOpencodeModels() {
|
|
|
7316
7668
|
if (opencode === "opencode") {
|
|
7317
7669
|
const which = await run("which", ["opencode"], { reject: false });
|
|
7318
7670
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
7319
|
-
} else if (!(0,
|
|
7671
|
+
} else if (!(0, import_node_fs25.existsSync)(opencode)) {
|
|
7320
7672
|
return FALLBACK_OPENCODE_MODELS;
|
|
7321
7673
|
}
|
|
7322
7674
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -7346,11 +7698,11 @@ function usageFromOpencode(tokens) {
|
|
|
7346
7698
|
cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
|
|
7347
7699
|
};
|
|
7348
7700
|
}
|
|
7349
|
-
var
|
|
7701
|
+
var import_node_fs25, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
|
|
7350
7702
|
var init_opencode = __esm({
|
|
7351
7703
|
"src/agents/opencode.ts"() {
|
|
7352
7704
|
"use strict";
|
|
7353
|
-
|
|
7705
|
+
import_node_fs25 = require("fs");
|
|
7354
7706
|
init_run();
|
|
7355
7707
|
init_app_settings();
|
|
7356
7708
|
init_global_workspace();
|
|
@@ -7376,7 +7728,7 @@ var init_opencode = __esm({
|
|
|
7376
7728
|
async detect() {
|
|
7377
7729
|
const opencode = resolveAgentExecutable("opencode");
|
|
7378
7730
|
if (opencode !== "opencode") {
|
|
7379
|
-
if (!(0,
|
|
7731
|
+
if (!(0, import_node_fs25.existsSync)(opencode)) {
|
|
7380
7732
|
return {
|
|
7381
7733
|
agent: "opencode",
|
|
7382
7734
|
installed: false,
|
|
@@ -8113,38 +8465,38 @@ __export(workspaces_exports, {
|
|
|
8113
8465
|
syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
|
|
8114
8466
|
});
|
|
8115
8467
|
function workspacesFile() {
|
|
8116
|
-
return (0,
|
|
8468
|
+
return (0, import_node_path27.join)(appDataDir(), "workspaces.json");
|
|
8117
8469
|
}
|
|
8118
8470
|
function removedWorkspacesFile() {
|
|
8119
|
-
return (0,
|
|
8471
|
+
return (0, import_node_path27.join)(appDataDir(), "removed-workspaces.json");
|
|
8120
8472
|
}
|
|
8121
8473
|
function readAll() {
|
|
8122
8474
|
const path = workspacesFile();
|
|
8123
|
-
if (!(0,
|
|
8475
|
+
if (!(0, import_node_fs28.existsSync)(path)) return [];
|
|
8124
8476
|
try {
|
|
8125
|
-
const raw = JSON.parse((0,
|
|
8477
|
+
const raw = JSON.parse((0, import_node_fs28.readFileSync)(path, "utf8"));
|
|
8126
8478
|
return Array.isArray(raw) ? raw : [];
|
|
8127
8479
|
} catch {
|
|
8128
8480
|
return [];
|
|
8129
8481
|
}
|
|
8130
8482
|
}
|
|
8131
8483
|
function writeAll(list) {
|
|
8132
|
-
(0,
|
|
8133
|
-
(0,
|
|
8484
|
+
(0, import_node_fs28.mkdirSync)(appDataDir(), { recursive: true });
|
|
8485
|
+
(0, import_node_fs28.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
|
|
8134
8486
|
}
|
|
8135
8487
|
function readRemoved() {
|
|
8136
8488
|
const path = removedWorkspacesFile();
|
|
8137
|
-
if (!(0,
|
|
8489
|
+
if (!(0, import_node_fs28.existsSync)(path)) return /* @__PURE__ */ new Set();
|
|
8138
8490
|
try {
|
|
8139
|
-
const raw = JSON.parse((0,
|
|
8491
|
+
const raw = JSON.parse((0, import_node_fs28.readFileSync)(path, "utf8"));
|
|
8140
8492
|
return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
|
|
8141
8493
|
} catch {
|
|
8142
8494
|
return /* @__PURE__ */ new Set();
|
|
8143
8495
|
}
|
|
8144
8496
|
}
|
|
8145
8497
|
function writeRemoved(paths) {
|
|
8146
|
-
(0,
|
|
8147
|
-
(0,
|
|
8498
|
+
(0, import_node_fs28.mkdirSync)(appDataDir(), { recursive: true });
|
|
8499
|
+
(0, import_node_fs28.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
|
|
8148
8500
|
}
|
|
8149
8501
|
function rememberRemoved(repoPath) {
|
|
8150
8502
|
const next = readRemoved();
|
|
@@ -8167,7 +8519,7 @@ function listWorkspaces() {
|
|
|
8167
8519
|
async function addWorkspace(repoPath) {
|
|
8168
8520
|
const root = await resolveRepoRoot(repoPath);
|
|
8169
8521
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
8170
|
-
if (!(0,
|
|
8522
|
+
if (!(0, import_node_fs28.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
|
|
8171
8523
|
forgetRemoved(root);
|
|
8172
8524
|
await ensureGhPreferOrigin(root);
|
|
8173
8525
|
const current = readAll();
|
|
@@ -8175,7 +8527,7 @@ async function addWorkspace(repoPath) {
|
|
|
8175
8527
|
if (existing) return existing;
|
|
8176
8528
|
const next = {
|
|
8177
8529
|
path: root,
|
|
8178
|
-
name: (0,
|
|
8530
|
+
name: (0, import_node_path27.basename)(root),
|
|
8179
8531
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8180
8532
|
};
|
|
8181
8533
|
writeAll([...current, next]);
|
|
@@ -8197,10 +8549,10 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
8197
8549
|
if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
|
|
8198
8550
|
continue;
|
|
8199
8551
|
}
|
|
8200
|
-
if (!(0,
|
|
8552
|
+
if (!(0, import_node_fs28.existsSync)(path)) continue;
|
|
8201
8553
|
const ws = {
|
|
8202
8554
|
path,
|
|
8203
|
-
name: (0,
|
|
8555
|
+
name: (0, import_node_path27.basename)(path),
|
|
8204
8556
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8205
8557
|
};
|
|
8206
8558
|
byPath.set(path, ws);
|
|
@@ -8210,12 +8562,12 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
8210
8562
|
if (dirty) writeAll(next);
|
|
8211
8563
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
8212
8564
|
}
|
|
8213
|
-
var
|
|
8565
|
+
var import_node_fs28, import_node_path27;
|
|
8214
8566
|
var init_workspaces = __esm({
|
|
8215
8567
|
"src/store/workspaces.ts"() {
|
|
8216
8568
|
"use strict";
|
|
8217
|
-
|
|
8218
|
-
|
|
8569
|
+
import_node_fs28 = require("fs");
|
|
8570
|
+
import_node_path27 = require("path");
|
|
8219
8571
|
init_paths();
|
|
8220
8572
|
init_global_workspace();
|
|
8221
8573
|
init_worktree();
|
|
@@ -8292,40 +8644,40 @@ __export(plan_file_exports, {
|
|
|
8292
8644
|
writePlanFile: () => writePlanFile
|
|
8293
8645
|
});
|
|
8294
8646
|
function ensureAttachmentsGitignore2(worktreePath) {
|
|
8295
|
-
const gitignoreAbs = (0,
|
|
8296
|
-
if ((0,
|
|
8297
|
-
(0,
|
|
8298
|
-
(0,
|
|
8647
|
+
const gitignoreAbs = (0, import_node_path35.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
8648
|
+
if ((0, import_node_fs38.existsSync)(gitignoreAbs)) return;
|
|
8649
|
+
(0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(gitignoreAbs), { recursive: true });
|
|
8650
|
+
(0, import_node_fs38.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
8299
8651
|
}
|
|
8300
8652
|
function planFileAbs(worktreePath) {
|
|
8301
|
-
return (0,
|
|
8653
|
+
return (0, import_node_path35.join)(worktreePath, PLAN_FILE_REL);
|
|
8302
8654
|
}
|
|
8303
8655
|
function readTextIfPresent2(abs) {
|
|
8304
|
-
if (!(0,
|
|
8656
|
+
if (!(0, import_node_fs38.existsSync)(abs)) return null;
|
|
8305
8657
|
try {
|
|
8306
|
-
const content = (0,
|
|
8658
|
+
const content = (0, import_node_fs38.readFileSync)(abs, "utf8");
|
|
8307
8659
|
return content.trim() ? content : null;
|
|
8308
8660
|
} catch {
|
|
8309
8661
|
return null;
|
|
8310
8662
|
}
|
|
8311
8663
|
}
|
|
8312
8664
|
function readPlanFile(worktreePath) {
|
|
8313
|
-
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0,
|
|
8665
|
+
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path35.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path35.join)(worktreePath, LEGACY_PLAN_FILE_REL));
|
|
8314
8666
|
}
|
|
8315
8667
|
function writePlanFile(worktreePath, content) {
|
|
8316
8668
|
ensureAttachmentsGitignore2(worktreePath);
|
|
8317
8669
|
const abs = planFileAbs(worktreePath);
|
|
8318
|
-
(0,
|
|
8670
|
+
(0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(abs), { recursive: true });
|
|
8319
8671
|
const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
|
|
8320
|
-
(0,
|
|
8672
|
+
(0, import_node_fs38.writeFileSync)(abs, body, "utf8");
|
|
8321
8673
|
return PLAN_FILE_REL;
|
|
8322
8674
|
}
|
|
8323
|
-
var
|
|
8675
|
+
var import_node_fs38, import_node_path35;
|
|
8324
8676
|
var init_plan_file = __esm({
|
|
8325
8677
|
"src/plan/plan-file.ts"() {
|
|
8326
8678
|
"use strict";
|
|
8327
|
-
|
|
8328
|
-
|
|
8679
|
+
import_node_fs38 = require("fs");
|
|
8680
|
+
import_node_path35 = require("path");
|
|
8329
8681
|
init_workspace_scratch();
|
|
8330
8682
|
init_plan_present();
|
|
8331
8683
|
init_plan_present();
|
|
@@ -8346,7 +8698,7 @@ function setCaffeinateHoldHooks(next) {
|
|
|
8346
8698
|
hooks = next;
|
|
8347
8699
|
}
|
|
8348
8700
|
function caffeinateHoldPath() {
|
|
8349
|
-
return (0,
|
|
8701
|
+
return (0, import_node_path36.join)(appDataDir(), "caffeinate-hold.json");
|
|
8350
8702
|
}
|
|
8351
8703
|
function processAlive(pid) {
|
|
8352
8704
|
if (hooks.processAlive) return hooks.processAlive(pid);
|
|
@@ -8380,9 +8732,9 @@ function uniqueIds(ids) {
|
|
|
8380
8732
|
}
|
|
8381
8733
|
function readHold() {
|
|
8382
8734
|
const path = caffeinateHoldPath();
|
|
8383
|
-
if (!(0,
|
|
8735
|
+
if (!(0, import_node_fs39.existsSync)(path)) return null;
|
|
8384
8736
|
try {
|
|
8385
|
-
const parsed = JSON.parse((0,
|
|
8737
|
+
const parsed = JSON.parse((0, import_node_fs39.readFileSync)(path, "utf8"));
|
|
8386
8738
|
if (typeof parsed?.pid === "number" && parsed.pid > 0) {
|
|
8387
8739
|
return {
|
|
8388
8740
|
pid: parsed.pid,
|
|
@@ -8404,7 +8756,7 @@ function writeHold(pid, threadIds) {
|
|
|
8404
8756
|
}
|
|
8405
8757
|
function clearHold() {
|
|
8406
8758
|
try {
|
|
8407
|
-
(0,
|
|
8759
|
+
(0, import_node_fs39.unlinkSync)(caffeinateHoldPath());
|
|
8408
8760
|
} catch {
|
|
8409
8761
|
}
|
|
8410
8762
|
}
|
|
@@ -8489,13 +8841,13 @@ function releaseCaffeinateHoldForThread(threadId) {
|
|
|
8489
8841
|
}
|
|
8490
8842
|
return setCaffeinateHold(false, { threadId: id });
|
|
8491
8843
|
}
|
|
8492
|
-
var import_node_child_process4,
|
|
8844
|
+
var import_node_child_process4, import_node_fs39, import_node_path36, hooks;
|
|
8493
8845
|
var init_caffeinate_hold = __esm({
|
|
8494
8846
|
"src/store/caffeinate-hold.ts"() {
|
|
8495
8847
|
"use strict";
|
|
8496
8848
|
import_node_child_process4 = require("child_process");
|
|
8497
|
-
|
|
8498
|
-
|
|
8849
|
+
import_node_fs39 = require("fs");
|
|
8850
|
+
import_node_path36 = require("path");
|
|
8499
8851
|
init_paths();
|
|
8500
8852
|
init_private_file();
|
|
8501
8853
|
hooks = {};
|
|
@@ -8510,10 +8862,10 @@ __export(cursor_recover_exports, {
|
|
|
8510
8862
|
function recoverFinishedCursorRun(opts) {
|
|
8511
8863
|
const agentId = opts.agentId.trim();
|
|
8512
8864
|
if (!agentId) return null;
|
|
8513
|
-
const runsPath = (0,
|
|
8514
|
-
if (!(0,
|
|
8865
|
+
const runsPath = (0, import_node_path37.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
|
|
8866
|
+
if (!(0, import_node_fs40.existsSync)(runsPath)) return null;
|
|
8515
8867
|
try {
|
|
8516
|
-
const lines = (0,
|
|
8868
|
+
const lines = (0, import_node_fs40.readFileSync)(runsPath, "utf8").split("\n");
|
|
8517
8869
|
let best = null;
|
|
8518
8870
|
for (const line of lines) {
|
|
8519
8871
|
const trimmed = line.trim();
|
|
@@ -8539,12 +8891,12 @@ function recoverFinishedCursorRun(opts) {
|
|
|
8539
8891
|
return null;
|
|
8540
8892
|
}
|
|
8541
8893
|
}
|
|
8542
|
-
var
|
|
8894
|
+
var import_node_fs40, import_node_path37;
|
|
8543
8895
|
var init_cursor_recover = __esm({
|
|
8544
8896
|
"src/agents/cursor-recover.ts"() {
|
|
8545
8897
|
"use strict";
|
|
8546
|
-
|
|
8547
|
-
|
|
8898
|
+
import_node_fs40 = require("fs");
|
|
8899
|
+
import_node_path37 = require("path");
|
|
8548
8900
|
init_paths();
|
|
8549
8901
|
}
|
|
8550
8902
|
});
|
|
@@ -8556,7 +8908,7 @@ init_nested_electron_env();
|
|
|
8556
8908
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
8557
8909
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
8558
8910
|
var import_zod3 = require("zod");
|
|
8559
|
-
var
|
|
8911
|
+
var import_node_path38 = require("path");
|
|
8560
8912
|
|
|
8561
8913
|
// src/orchestrator/orchestrator.ts
|
|
8562
8914
|
var import_node_events = require("events");
|
|
@@ -9067,7 +9419,7 @@ async function refreshSlackReplyBadges(opts) {
|
|
|
9067
9419
|
}
|
|
9068
9420
|
|
|
9069
9421
|
// src/orchestrator/orchestrator.ts
|
|
9070
|
-
var
|
|
9422
|
+
var import_node_fs41 = require("fs");
|
|
9071
9423
|
init_error_detail();
|
|
9072
9424
|
|
|
9073
9425
|
// src/agents/spawn.ts
|
|
@@ -9312,6 +9664,51 @@ function normalizeParseResult(parsed) {
|
|
|
9312
9664
|
// src/agents/spawn.ts
|
|
9313
9665
|
init_path();
|
|
9314
9666
|
init_usage();
|
|
9667
|
+
|
|
9668
|
+
// src/agents/cursor-stream-coalesce.ts
|
|
9669
|
+
function isTextEvent(event) {
|
|
9670
|
+
return event.type === "stdout" || event.type === "thinking";
|
|
9671
|
+
}
|
|
9672
|
+
function createAgentStreamCoalescer(emit, opts) {
|
|
9673
|
+
const intervalMs = opts?.intervalMs ?? 32;
|
|
9674
|
+
let pending = null;
|
|
9675
|
+
let timer = null;
|
|
9676
|
+
const flush = () => {
|
|
9677
|
+
if (timer) {
|
|
9678
|
+
clearTimeout(timer);
|
|
9679
|
+
timer = null;
|
|
9680
|
+
}
|
|
9681
|
+
if (!pending) return;
|
|
9682
|
+
const event = pending;
|
|
9683
|
+
pending = null;
|
|
9684
|
+
emit({ type: event.type, data: event.data });
|
|
9685
|
+
};
|
|
9686
|
+
const schedule = () => {
|
|
9687
|
+
if (timer) return;
|
|
9688
|
+
timer = setTimeout(flush, intervalMs);
|
|
9689
|
+
timer.unref?.();
|
|
9690
|
+
};
|
|
9691
|
+
return {
|
|
9692
|
+
push(event) {
|
|
9693
|
+
if (!isTextEvent(event)) {
|
|
9694
|
+
flush();
|
|
9695
|
+
emit(event);
|
|
9696
|
+
return;
|
|
9697
|
+
}
|
|
9698
|
+
if (!event.data) return;
|
|
9699
|
+
if (pending && pending.type === event.type) {
|
|
9700
|
+
pending.data += event.data;
|
|
9701
|
+
} else {
|
|
9702
|
+
flush();
|
|
9703
|
+
pending = { type: event.type, data: event.data };
|
|
9704
|
+
}
|
|
9705
|
+
schedule();
|
|
9706
|
+
},
|
|
9707
|
+
flush
|
|
9708
|
+
};
|
|
9709
|
+
}
|
|
9710
|
+
|
|
9711
|
+
// src/agents/spawn.ts
|
|
9315
9712
|
async function spawnAgentTurn(thread, input, onEvent) {
|
|
9316
9713
|
ensureAgentPath();
|
|
9317
9714
|
if (!thread.worktreePath?.trim()) {
|
|
@@ -9339,10 +9736,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
9339
9736
|
const env = childEnvWithAppSettings(cmd.env);
|
|
9340
9737
|
try {
|
|
9341
9738
|
if (isOrchestratorThread(thread)) {
|
|
9342
|
-
|
|
9739
|
+
mergeAgentGitAuthEnv(env, await resolveAgentGitAuthEnv(env));
|
|
9343
9740
|
} else {
|
|
9344
|
-
|
|
9345
|
-
Object.assign(env, originEnv);
|
|
9741
|
+
mergeAgentGitAuthEnv(env, await originGhRepoEnv(thread.worktreePath, { env }));
|
|
9346
9742
|
}
|
|
9347
9743
|
} catch (err) {
|
|
9348
9744
|
const detail = err instanceof Error ? err.message : String(err);
|
|
@@ -9366,12 +9762,13 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
9366
9762
|
let assistantText = "";
|
|
9367
9763
|
let parts = [];
|
|
9368
9764
|
let usage = null;
|
|
9765
|
+
const outbound = createAgentStreamCoalescer(onEvent);
|
|
9369
9766
|
const consume = (stream, kind) => {
|
|
9370
9767
|
if (!stream) return;
|
|
9371
9768
|
const rl = (0, import_node_readline2.createInterface)({ input: stream, crlfDelay: Infinity });
|
|
9372
9769
|
rl.on("line", (line) => {
|
|
9373
9770
|
if (kind === "stderr") {
|
|
9374
|
-
|
|
9771
|
+
outbound.push({ type: "stderr", data: line });
|
|
9375
9772
|
return;
|
|
9376
9773
|
}
|
|
9377
9774
|
let events = normalizeParseResult(adapter.parseEvent(line));
|
|
@@ -9386,12 +9783,12 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
9386
9783
|
for (const parsed of events) {
|
|
9387
9784
|
if (parsed.type === "session_id") {
|
|
9388
9785
|
sessionId = parsed.data;
|
|
9389
|
-
|
|
9786
|
+
outbound.push(parsed);
|
|
9390
9787
|
continue;
|
|
9391
9788
|
}
|
|
9392
9789
|
if (parsed.type === "usage") {
|
|
9393
9790
|
usage = applyTurnUsage(usage, parsed.data, parsed.scope ?? "request");
|
|
9394
|
-
|
|
9791
|
+
outbound.push(parsed);
|
|
9395
9792
|
continue;
|
|
9396
9793
|
}
|
|
9397
9794
|
if (parsed.type === "stdout") {
|
|
@@ -9404,13 +9801,14 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
9404
9801
|
assistantText += parsed.data;
|
|
9405
9802
|
}
|
|
9406
9803
|
parts = applyAgentEvent(parts, parsed);
|
|
9407
|
-
|
|
9804
|
+
outbound.push(parsed);
|
|
9408
9805
|
}
|
|
9409
9806
|
});
|
|
9410
9807
|
};
|
|
9411
9808
|
consume(child.stdout, "stdout");
|
|
9412
9809
|
consume(child.stderr, "stderr");
|
|
9413
9810
|
const done = child.then((result) => {
|
|
9811
|
+
outbound.flush();
|
|
9414
9812
|
const exitCode = result.exitCode ?? null;
|
|
9415
9813
|
onEvent({ type: "exit", data: exitCode });
|
|
9416
9814
|
const finalized = finalizeParts(parts);
|
|
@@ -9553,9 +9951,9 @@ function shouldAutoArchiveOnPrMerge(opts) {
|
|
|
9553
9951
|
}
|
|
9554
9952
|
|
|
9555
9953
|
// src/hook/conductor.ts
|
|
9556
|
-
var
|
|
9954
|
+
var import_node_fs26 = require("fs");
|
|
9557
9955
|
var import_node_net = require("net");
|
|
9558
|
-
var
|
|
9956
|
+
var import_node_path25 = require("path");
|
|
9559
9957
|
var import_execa4 = require("execa");
|
|
9560
9958
|
var import_node_readline3 = require("readline");
|
|
9561
9959
|
init_settings();
|
|
@@ -9570,9 +9968,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
9570
9968
|
return new RegExp(`^${escaped}$`).test(name);
|
|
9571
9969
|
}
|
|
9572
9970
|
function readWorktreeInclude(repoPath) {
|
|
9573
|
-
const path = (0,
|
|
9574
|
-
if (!(0,
|
|
9575
|
-
return (0,
|
|
9971
|
+
const path = (0, import_node_path25.join)(repoPath, ".worktreeinclude");
|
|
9972
|
+
if (!(0, import_node_fs26.existsSync)(path)) return [];
|
|
9973
|
+
return (0, import_node_fs26.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
9576
9974
|
}
|
|
9577
9975
|
function resolveFilesToCopy(repoPath) {
|
|
9578
9976
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -9582,10 +9980,10 @@ function resolveFilesToCopy(repoPath) {
|
|
|
9582
9980
|
if (settings?.fileIncludeGlobs?.length) {
|
|
9583
9981
|
const matched = [];
|
|
9584
9982
|
try {
|
|
9585
|
-
for (const entry of (0,
|
|
9983
|
+
for (const entry of (0, import_node_fs26.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
9586
9984
|
if (!entry.isFile()) continue;
|
|
9587
9985
|
for (const glob of settings.fileIncludeGlobs) {
|
|
9588
|
-
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0,
|
|
9986
|
+
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path25.basename)(glob), entry.name)) {
|
|
9589
9987
|
matched.push(entry.name);
|
|
9590
9988
|
break;
|
|
9591
9989
|
}
|
|
@@ -9597,7 +9995,7 @@ function resolveFilesToCopy(repoPath) {
|
|
|
9597
9995
|
}
|
|
9598
9996
|
const defaults = [];
|
|
9599
9997
|
try {
|
|
9600
|
-
for (const entry of (0,
|
|
9998
|
+
for (const entry of (0, import_node_fs26.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
9601
9999
|
if (entry.isFile() && entry.name.startsWith(".env")) {
|
|
9602
10000
|
defaults.push(entry.name);
|
|
9603
10001
|
}
|
|
@@ -9611,11 +10009,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
|
|
|
9611
10009
|
const patterns = resolveFilesToCopy(repoPath);
|
|
9612
10010
|
const copied = [];
|
|
9613
10011
|
for (const rel of patterns) {
|
|
9614
|
-
const src = (0,
|
|
9615
|
-
if (!(0,
|
|
9616
|
-
const dest = (0,
|
|
9617
|
-
(0,
|
|
9618
|
-
(0,
|
|
10012
|
+
const src = (0, import_node_path25.join)(repoPath, rel);
|
|
10013
|
+
if (!(0, import_node_fs26.existsSync)(src)) continue;
|
|
10014
|
+
const dest = (0, import_node_path25.join)(worktreePath, rel);
|
|
10015
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(dest), { recursive: true });
|
|
10016
|
+
(0, import_node_fs26.copyFileSync)(src, dest);
|
|
9619
10017
|
copied.push(rel);
|
|
9620
10018
|
}
|
|
9621
10019
|
return copied;
|
|
@@ -9651,7 +10049,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
|
9651
10049
|
const env = stripNestedElectronEnv({
|
|
9652
10050
|
...baseEnv ?? process.env
|
|
9653
10051
|
});
|
|
9654
|
-
const name = opts.workspaceName ?? (0,
|
|
10052
|
+
const name = opts.workspaceName ?? (0, import_node_path25.basename)(opts.worktreePath);
|
|
9655
10053
|
const ports = opts.ports ?? [];
|
|
9656
10054
|
const primary = ports[0];
|
|
9657
10055
|
env.SIDEBOARD_WORKSPACE_NAME = name;
|
|
@@ -9737,7 +10135,10 @@ async function spawnWorkspaceScript(command, opts) {
|
|
|
9737
10135
|
loginEnv
|
|
9738
10136
|
);
|
|
9739
10137
|
try {
|
|
9740
|
-
|
|
10138
|
+
mergeAgentGitAuthEnv(
|
|
10139
|
+
env,
|
|
10140
|
+
await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath })
|
|
10141
|
+
);
|
|
9741
10142
|
} catch {
|
|
9742
10143
|
}
|
|
9743
10144
|
const shell = process.platform === "darwin" ? "zsh" : "bash";
|
|
@@ -9905,8 +10306,8 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
|
|
|
9905
10306
|
}
|
|
9906
10307
|
|
|
9907
10308
|
// src/git/orphan-cleanup.ts
|
|
9908
|
-
var
|
|
9909
|
-
var
|
|
10309
|
+
var import_node_fs27 = require("fs");
|
|
10310
|
+
var import_node_path26 = require("path");
|
|
9910
10311
|
init_worktree();
|
|
9911
10312
|
init_thread_store();
|
|
9912
10313
|
init_paths();
|
|
@@ -9921,9 +10322,9 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
9921
10322
|
repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
|
|
9922
10323
|
);
|
|
9923
10324
|
const homeRoot = sideboardWorkspacesDir();
|
|
9924
|
-
if ((0,
|
|
10325
|
+
if ((0, import_node_fs27.existsSync)(homeRoot)) {
|
|
9925
10326
|
try {
|
|
9926
|
-
for (const entry of (0,
|
|
10327
|
+
for (const entry of (0, import_node_fs27.readdirSync)(homeRoot, { withFileTypes: true })) {
|
|
9927
10328
|
if (!entry.isDirectory()) continue;
|
|
9928
10329
|
void entry;
|
|
9929
10330
|
}
|
|
@@ -9933,7 +10334,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
9933
10334
|
const orphans = [];
|
|
9934
10335
|
const seen = /* @__PURE__ */ new Set();
|
|
9935
10336
|
for (const repoPath of repos) {
|
|
9936
|
-
if (!repoPath || !(0,
|
|
10337
|
+
if (!repoPath || !(0, import_node_fs27.existsSync)(repoPath)) continue;
|
|
9937
10338
|
try {
|
|
9938
10339
|
const wts = await listWorktrees(repoPath);
|
|
9939
10340
|
for (const wt of wts) {
|
|
@@ -9944,7 +10345,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
9944
10345
|
seen.add(path);
|
|
9945
10346
|
let mtimeMs = 0;
|
|
9946
10347
|
try {
|
|
9947
|
-
mtimeMs = (0,
|
|
10348
|
+
mtimeMs = (0, import_node_fs27.statSync)(path).mtimeMs;
|
|
9948
10349
|
} catch {
|
|
9949
10350
|
mtimeMs = 0;
|
|
9950
10351
|
}
|
|
@@ -9954,16 +10355,16 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
9954
10355
|
}
|
|
9955
10356
|
try {
|
|
9956
10357
|
const root = worktreesRoot(repoPath);
|
|
9957
|
-
if ((0,
|
|
9958
|
-
for (const entry of (0,
|
|
10358
|
+
if ((0, import_node_fs27.existsSync)(root)) {
|
|
10359
|
+
for (const entry of (0, import_node_fs27.readdirSync)(root, { withFileTypes: true })) {
|
|
9959
10360
|
if (!entry.isDirectory()) continue;
|
|
9960
|
-
const path = (0,
|
|
10361
|
+
const path = (0, import_node_path26.join)(root, entry.name).replace(/\/$/, "");
|
|
9961
10362
|
if (known.has(path) || seen.has(path)) continue;
|
|
9962
|
-
if (!(0,
|
|
10363
|
+
if (!(0, import_node_fs27.existsSync)((0, import_node_path26.join)(path, ".git"))) continue;
|
|
9963
10364
|
seen.add(path);
|
|
9964
10365
|
let mtimeMs = 0;
|
|
9965
10366
|
try {
|
|
9966
|
-
mtimeMs = (0,
|
|
10367
|
+
mtimeMs = (0, import_node_fs27.statSync)(path).mtimeMs;
|
|
9967
10368
|
} catch {
|
|
9968
10369
|
mtimeMs = Date.now();
|
|
9969
10370
|
}
|
|
@@ -10100,8 +10501,8 @@ async function applyThreadIntoMain(thread, opts) {
|
|
|
10100
10501
|
}
|
|
10101
10502
|
|
|
10102
10503
|
// src/git/clone-repo.ts
|
|
10103
|
-
var
|
|
10104
|
-
var
|
|
10504
|
+
var import_node_fs29 = require("fs");
|
|
10505
|
+
var import_node_path28 = require("path");
|
|
10105
10506
|
var import_execa6 = require("execa");
|
|
10106
10507
|
init_paths();
|
|
10107
10508
|
init_workspaces();
|
|
@@ -10111,12 +10512,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
10111
10512
|
if (!url) throw new Error("Clone URL is required");
|
|
10112
10513
|
let name = opts.name?.trim();
|
|
10113
10514
|
if (!name) {
|
|
10114
|
-
const leaf = (0,
|
|
10515
|
+
const leaf = (0, import_node_path28.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
|
|
10115
10516
|
name = leaf || "repo";
|
|
10116
10517
|
}
|
|
10117
10518
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
10118
|
-
const dest = (0,
|
|
10119
|
-
if ((0,
|
|
10519
|
+
const dest = (0, import_node_path28.join)(sideboardReposDir(), name);
|
|
10520
|
+
if ((0, import_node_fs29.existsSync)(dest)) {
|
|
10120
10521
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
10121
10522
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
10122
10523
|
return { repoPath: repoPath2, workspace: workspace2 };
|
|
@@ -10136,7 +10537,7 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
10136
10537
|
init_thread_store();
|
|
10137
10538
|
|
|
10138
10539
|
// src/threads/create.ts
|
|
10139
|
-
var
|
|
10540
|
+
var import_node_fs30 = require("fs");
|
|
10140
10541
|
|
|
10141
10542
|
// src/detect/detect.ts
|
|
10142
10543
|
init_agents();
|
|
@@ -10181,12 +10582,13 @@ async function createThread(input, _onSetupLine) {
|
|
|
10181
10582
|
});
|
|
10182
10583
|
await requireAgent(resolved.agent);
|
|
10183
10584
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
10184
|
-
if (!(0,
|
|
10585
|
+
if (!(0, import_node_fs30.existsSync)(repoPath)) {
|
|
10185
10586
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
10186
10587
|
}
|
|
10187
10588
|
let sourceRef = input.sourceRef;
|
|
10188
10589
|
let sourceIsFork = false;
|
|
10189
10590
|
let prUrl = null;
|
|
10591
|
+
let prTitle = null;
|
|
10190
10592
|
if (input.sourceType === "pr") {
|
|
10191
10593
|
const num2 = Number(input.sourceRef.replace(/^#/, ""));
|
|
10192
10594
|
if (!Number.isFinite(num2)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
|
|
@@ -10202,6 +10604,12 @@ async function createThread(input, _onSetupLine) {
|
|
|
10202
10604
|
} else if (input.sourceType === "branch") {
|
|
10203
10605
|
if (!sourceRef || sourceRef === "HEAD" || sourceRef === "default") {
|
|
10204
10606
|
sourceRef = await resolveDefaultBranch(repoPath);
|
|
10607
|
+
} else {
|
|
10608
|
+
const existing = await getPrForHeadBranch(repoPath, sourceRef);
|
|
10609
|
+
if (existing?.url) {
|
|
10610
|
+
prUrl = existing.url;
|
|
10611
|
+
prTitle = existing.title;
|
|
10612
|
+
}
|
|
10205
10613
|
}
|
|
10206
10614
|
} else if (input.sourceType === "adopt") {
|
|
10207
10615
|
throw new Error("Use adoptThread() for adopt sources");
|
|
@@ -10232,7 +10640,8 @@ async function createThread(input, _onSetupLine) {
|
|
|
10232
10640
|
sourceIsFork,
|
|
10233
10641
|
parentThreadId: input.parentThreadId ?? null,
|
|
10234
10642
|
status: "idle",
|
|
10235
|
-
prUrl
|
|
10643
|
+
prUrl,
|
|
10644
|
+
prTitle
|
|
10236
10645
|
});
|
|
10237
10646
|
writeThread(thread);
|
|
10238
10647
|
await ensureWorkspace(repoPath);
|
|
@@ -10644,8 +11053,8 @@ function forkChatTab(input) {
|
|
|
10644
11053
|
|
|
10645
11054
|
// src/review/request-review.ts
|
|
10646
11055
|
var import_node_crypto5 = require("crypto");
|
|
10647
|
-
var
|
|
10648
|
-
var
|
|
11056
|
+
var import_node_fs31 = require("fs");
|
|
11057
|
+
var import_node_path29 = require("path");
|
|
10649
11058
|
init_global_workspace();
|
|
10650
11059
|
init_thread_store();
|
|
10651
11060
|
|
|
@@ -10793,22 +11202,22 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
10793
11202
|
return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
|
|
10794
11203
|
}
|
|
10795
11204
|
function readTextIfPresent(abs) {
|
|
10796
|
-
if (!(0,
|
|
11205
|
+
if (!(0, import_node_fs31.existsSync)(abs)) return null;
|
|
10797
11206
|
try {
|
|
10798
|
-
const content = (0,
|
|
11207
|
+
const content = (0, import_node_fs31.readFileSync)(abs, "utf8");
|
|
10799
11208
|
return content.trim() ? content : null;
|
|
10800
11209
|
} catch {
|
|
10801
11210
|
return null;
|
|
10802
11211
|
}
|
|
10803
11212
|
}
|
|
10804
11213
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
10805
|
-
const gitignoreAbs = (0,
|
|
10806
|
-
if ((0,
|
|
10807
|
-
(0,
|
|
10808
|
-
(0,
|
|
11214
|
+
const gitignoreAbs = (0, import_node_path29.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
11215
|
+
if ((0, import_node_fs31.existsSync)(gitignoreAbs)) return;
|
|
11216
|
+
(0, import_node_fs31.mkdirSync)((0, import_node_path29.dirname)(gitignoreAbs), { recursive: true });
|
|
11217
|
+
(0, import_node_fs31.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
10809
11218
|
}
|
|
10810
11219
|
function resolveReviewGuidelines(worktreePath) {
|
|
10811
|
-
const repoAbs = (0,
|
|
11220
|
+
const repoAbs = (0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH);
|
|
10812
11221
|
const repoContent = readTextIfPresent(repoAbs);
|
|
10813
11222
|
if (repoContent) {
|
|
10814
11223
|
return {
|
|
@@ -10818,7 +11227,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
10818
11227
|
source: "repo"
|
|
10819
11228
|
};
|
|
10820
11229
|
}
|
|
10821
|
-
const localAbs = (0,
|
|
11230
|
+
const localAbs = (0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
10822
11231
|
const localContent = readTextIfPresent(localAbs);
|
|
10823
11232
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
10824
11233
|
return {
|
|
@@ -10828,7 +11237,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
10828
11237
|
source: "local"
|
|
10829
11238
|
};
|
|
10830
11239
|
}
|
|
10831
|
-
const legacyAbs = (0,
|
|
11240
|
+
const legacyAbs = (0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
10832
11241
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
10833
11242
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
10834
11243
|
return {
|
|
@@ -10839,8 +11248,8 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
10839
11248
|
};
|
|
10840
11249
|
}
|
|
10841
11250
|
ensureAttachmentsGitignore(worktreePath);
|
|
10842
|
-
(0,
|
|
10843
|
-
(0,
|
|
11251
|
+
(0, import_node_fs31.mkdirSync)((0, import_node_path29.dirname)(localAbs), { recursive: true });
|
|
11252
|
+
(0, import_node_fs31.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
|
|
10844
11253
|
return {
|
|
10845
11254
|
path: REVIEW_REQUEST_PATH,
|
|
10846
11255
|
name: REVIEW_REQUEST_NAME,
|
|
@@ -11040,20 +11449,26 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
11040
11449
|
|
|
11041
11450
|
// src/threads/adopt.ts
|
|
11042
11451
|
var import_node_child_process3 = require("child_process");
|
|
11043
|
-
var
|
|
11044
|
-
var
|
|
11045
|
-
var
|
|
11046
|
-
var
|
|
11452
|
+
var import_node_fs32 = require("fs");
|
|
11453
|
+
var import_node_os10 = require("os");
|
|
11454
|
+
var import_node_path30 = require("path");
|
|
11455
|
+
var import_node_module4 = require("module");
|
|
11047
11456
|
init_worktree();
|
|
11048
11457
|
init_thread_store();
|
|
11049
|
-
var
|
|
11458
|
+
var import_meta4 = {};
|
|
11459
|
+
var CONDUCTOR_APP_SUPPORT = (0, import_node_path30.join)(
|
|
11050
11460
|
process.env.HOME ?? "",
|
|
11051
11461
|
"Library",
|
|
11052
11462
|
"Application Support",
|
|
11053
11463
|
"com.conductor.app"
|
|
11054
11464
|
);
|
|
11055
|
-
var CONDUCTOR_DB = (0,
|
|
11056
|
-
var CURSOR_SDK_STORE = (0,
|
|
11465
|
+
var CONDUCTOR_DB = (0, import_node_path30.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
11466
|
+
var CURSOR_SDK_STORE = (0, import_node_path30.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
11467
|
+
function openReadonlySqlite(file) {
|
|
11468
|
+
const req = (0, import_node_module4.createRequire)(import_meta4.url);
|
|
11469
|
+
const Database = req("better-sqlite3");
|
|
11470
|
+
return new Database(file, { readonly: true, fileMustExist: true });
|
|
11471
|
+
}
|
|
11057
11472
|
function mapAgentType(raw) {
|
|
11058
11473
|
if (!raw) return null;
|
|
11059
11474
|
const v = raw.toLowerCase();
|
|
@@ -11065,21 +11480,21 @@ function mapAgentType(raw) {
|
|
|
11065
11480
|
return null;
|
|
11066
11481
|
}
|
|
11067
11482
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
11068
|
-
if (!workspacePath || !(0,
|
|
11483
|
+
if (!workspacePath || !(0, import_node_fs32.existsSync)(CURSOR_SDK_STORE)) return null;
|
|
11069
11484
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
11070
11485
|
let best = null;
|
|
11071
11486
|
let hashes;
|
|
11072
11487
|
try {
|
|
11073
|
-
hashes = (0,
|
|
11488
|
+
hashes = (0, import_node_fs32.readdirSync)(CURSOR_SDK_STORE);
|
|
11074
11489
|
} catch {
|
|
11075
11490
|
return null;
|
|
11076
11491
|
}
|
|
11077
11492
|
for (const hash of hashes) {
|
|
11078
|
-
const agentsFile = (0,
|
|
11079
|
-
if (!(0,
|
|
11493
|
+
const agentsFile = (0, import_node_path30.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
11494
|
+
if (!(0, import_node_fs32.existsSync)(agentsFile)) continue;
|
|
11080
11495
|
let text3;
|
|
11081
11496
|
try {
|
|
11082
|
-
text3 = (0,
|
|
11497
|
+
text3 = (0, import_node_fs32.readFileSync)(agentsFile, "utf8");
|
|
11083
11498
|
} catch {
|
|
11084
11499
|
continue;
|
|
11085
11500
|
}
|
|
@@ -11103,7 +11518,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
11103
11518
|
return best?.agentId ?? null;
|
|
11104
11519
|
}
|
|
11105
11520
|
async function adoptThread(input) {
|
|
11106
|
-
if (!(0,
|
|
11521
|
+
if (!(0, import_node_fs32.existsSync)(input.worktreePath)) {
|
|
11107
11522
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
11108
11523
|
}
|
|
11109
11524
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -11127,23 +11542,23 @@ async function adoptThread(input) {
|
|
|
11127
11542
|
return thread;
|
|
11128
11543
|
}
|
|
11129
11544
|
function listConductorWorkspaces() {
|
|
11130
|
-
if (!(0,
|
|
11545
|
+
if (!(0, import_node_fs32.existsSync)(CONDUCTOR_DB)) {
|
|
11131
11546
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
11132
11547
|
}
|
|
11133
|
-
const tmp = (0,
|
|
11134
|
-
const snapshot = (0,
|
|
11548
|
+
const tmp = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
|
|
11549
|
+
const snapshot = (0, import_node_path30.join)(tmp, "conductor.db");
|
|
11135
11550
|
try {
|
|
11136
|
-
(0,
|
|
11551
|
+
(0, import_node_fs32.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
11137
11552
|
for (const suffix of ["-wal", "-shm"]) {
|
|
11138
11553
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
11139
|
-
if ((0,
|
|
11554
|
+
if ((0, import_node_fs32.existsSync)(src)) {
|
|
11140
11555
|
try {
|
|
11141
|
-
(0,
|
|
11556
|
+
(0, import_node_fs32.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
11142
11557
|
} catch {
|
|
11143
11558
|
}
|
|
11144
11559
|
}
|
|
11145
11560
|
}
|
|
11146
|
-
const db =
|
|
11561
|
+
const db = openReadonlySqlite(snapshot);
|
|
11147
11562
|
try {
|
|
11148
11563
|
const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table'`).all();
|
|
11149
11564
|
const names = new Set(tables.map((t) => t.name));
|
|
@@ -11214,27 +11629,27 @@ function listConductorWorkspaces() {
|
|
|
11214
11629
|
db.close();
|
|
11215
11630
|
}
|
|
11216
11631
|
} finally {
|
|
11217
|
-
(0,
|
|
11632
|
+
(0, import_node_fs32.rmSync)(tmp, { recursive: true, force: true });
|
|
11218
11633
|
}
|
|
11219
11634
|
}
|
|
11220
11635
|
function importConductorWorkspace(workspaceId) {
|
|
11221
|
-
if (!(0,
|
|
11636
|
+
if (!(0, import_node_fs32.existsSync)(CONDUCTOR_DB)) {
|
|
11222
11637
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
11223
11638
|
}
|
|
11224
|
-
const tmp = (0,
|
|
11225
|
-
const snapshot = (0,
|
|
11639
|
+
const tmp = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
|
|
11640
|
+
const snapshot = (0, import_node_path30.join)(tmp, "conductor.db");
|
|
11226
11641
|
try {
|
|
11227
|
-
(0,
|
|
11642
|
+
(0, import_node_fs32.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
11228
11643
|
for (const suffix of ["-wal", "-shm"]) {
|
|
11229
11644
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
11230
|
-
if ((0,
|
|
11645
|
+
if ((0, import_node_fs32.existsSync)(src)) {
|
|
11231
11646
|
try {
|
|
11232
|
-
(0,
|
|
11647
|
+
(0, import_node_fs32.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
11233
11648
|
} catch {
|
|
11234
11649
|
}
|
|
11235
11650
|
}
|
|
11236
11651
|
}
|
|
11237
|
-
const db =
|
|
11652
|
+
const db = openReadonlySqlite(snapshot);
|
|
11238
11653
|
try {
|
|
11239
11654
|
const row = db.prepare(
|
|
11240
11655
|
`SELECT
|
|
@@ -11247,7 +11662,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
11247
11662
|
).get(workspaceId);
|
|
11248
11663
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
11249
11664
|
const worktreePath = String(row.workspacePath);
|
|
11250
|
-
if (!(0,
|
|
11665
|
+
if (!(0, import_node_fs32.existsSync)(worktreePath)) {
|
|
11251
11666
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
11252
11667
|
}
|
|
11253
11668
|
let sessionId = null;
|
|
@@ -11310,7 +11725,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
11310
11725
|
db.close();
|
|
11311
11726
|
}
|
|
11312
11727
|
} finally {
|
|
11313
|
-
(0,
|
|
11728
|
+
(0, import_node_fs32.rmSync)(tmp, { recursive: true, force: true });
|
|
11314
11729
|
}
|
|
11315
11730
|
}
|
|
11316
11731
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
@@ -11318,7 +11733,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
11318
11733
|
}
|
|
11319
11734
|
|
|
11320
11735
|
// src/threads/stack-layers.ts
|
|
11321
|
-
var
|
|
11736
|
+
var import_node_fs33 = require("fs");
|
|
11322
11737
|
init_run();
|
|
11323
11738
|
init_stack();
|
|
11324
11739
|
init_worktree();
|
|
@@ -11386,7 +11801,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
11386
11801
|
let createdWorktree = false;
|
|
11387
11802
|
const trees = await listWorktrees(repoPath);
|
|
11388
11803
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
11389
|
-
if (checkedOut?.path && (0,
|
|
11804
|
+
if (checkedOut?.path && (0, import_node_fs33.existsSync)(checkedOut.path)) {
|
|
11390
11805
|
if (input.reuseExistingWorktree !== false) {
|
|
11391
11806
|
worktreePath = checkedOut.path;
|
|
11392
11807
|
} else {
|
|
@@ -11528,7 +11943,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
11528
11943
|
async function createPrStack(input, onSetupLine) {
|
|
11529
11944
|
await requireAgent(input.agent);
|
|
11530
11945
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
11531
|
-
if (!(0,
|
|
11946
|
+
if (!(0, import_node_fs33.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
11532
11947
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
11533
11948
|
const status = await detectGhStack(repoPath);
|
|
11534
11949
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -11595,7 +12010,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
11595
12010
|
}
|
|
11596
12011
|
}
|
|
11597
12012
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
11598
|
-
if (!claimed.has(bootstrap.worktreePath) && (0,
|
|
12013
|
+
if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs33.existsSync)(bootstrap.worktreePath)) {
|
|
11599
12014
|
try {
|
|
11600
12015
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
11601
12016
|
deleteBranch: bootstrap.branchName
|
|
@@ -11610,12 +12025,12 @@ async function createPrStack(input, onSetupLine) {
|
|
|
11610
12025
|
init_worktree();
|
|
11611
12026
|
|
|
11612
12027
|
// src/diff/diff.ts
|
|
11613
|
-
var
|
|
11614
|
-
var
|
|
12028
|
+
var import_node_fs34 = require("fs");
|
|
12029
|
+
var import_node_path31 = require("path");
|
|
11615
12030
|
init_run();
|
|
11616
12031
|
init_worktree();
|
|
11617
12032
|
async function inspectGitWorktree(worktreePath) {
|
|
11618
|
-
if (!worktreePath || !(0,
|
|
12033
|
+
if (!worktreePath || !(0, import_node_fs34.existsSync)(worktreePath)) return "missing_worktree";
|
|
11619
12034
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
11620
12035
|
reject: false
|
|
11621
12036
|
});
|
|
@@ -11623,7 +12038,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
11623
12038
|
return "ok";
|
|
11624
12039
|
}
|
|
11625
12040
|
async function initializeGitRepository(worktreePath) {
|
|
11626
|
-
if (!worktreePath || !(0,
|
|
12041
|
+
if (!worktreePath || !(0, import_node_fs34.existsSync)(worktreePath)) {
|
|
11627
12042
|
throw new Error("Worktree not found");
|
|
11628
12043
|
}
|
|
11629
12044
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -11758,11 +12173,11 @@ new file mode 100644
|
|
|
11758
12173
|
};
|
|
11759
12174
|
}
|
|
11760
12175
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
11761
|
-
const abs = (0,
|
|
12176
|
+
const abs = (0, import_node_path31.join)(worktreePath, path);
|
|
11762
12177
|
try {
|
|
11763
|
-
const st = (0,
|
|
12178
|
+
const st = (0, import_node_fs34.statSync)(abs);
|
|
11764
12179
|
if (st.isFile() && st.size > maxHunk) {
|
|
11765
|
-
const buf = (0,
|
|
12180
|
+
const buf = (0, import_node_fs34.readFileSync)(abs).subarray(0, maxHunk);
|
|
11766
12181
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
11767
12182
|
}
|
|
11768
12183
|
} catch {
|
|
@@ -12263,8 +12678,8 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
12263
12678
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
12264
12679
|
assertSafeRelativePath(relativePath);
|
|
12265
12680
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
12266
|
-
const abs = (0,
|
|
12267
|
-
const st = (0,
|
|
12681
|
+
const abs = (0, import_node_path31.join)(worktreePath, relativePath);
|
|
12682
|
+
const st = (0, import_node_fs34.statSync)(abs);
|
|
12268
12683
|
if (!st.isFile()) {
|
|
12269
12684
|
throw new Error(`Not a file: ${relativePath}`);
|
|
12270
12685
|
}
|
|
@@ -12273,7 +12688,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
12273
12688
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
12274
12689
|
);
|
|
12275
12690
|
}
|
|
12276
|
-
const buf = (0,
|
|
12691
|
+
const buf = (0, import_node_fs34.readFileSync)(abs);
|
|
12277
12692
|
return {
|
|
12278
12693
|
path: relativePath,
|
|
12279
12694
|
contentBase64: buf.toString("base64"),
|
|
@@ -12283,12 +12698,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
12283
12698
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
12284
12699
|
assertSafeRelativePath(relativePath);
|
|
12285
12700
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
12286
|
-
const abs = (0,
|
|
12287
|
-
const st = (0,
|
|
12701
|
+
const abs = (0, import_node_path31.join)(worktreePath, relativePath);
|
|
12702
|
+
const st = (0, import_node_fs34.statSync)(abs);
|
|
12288
12703
|
if (!st.isFile()) {
|
|
12289
12704
|
throw new Error(`Not a file: ${relativePath}`);
|
|
12290
12705
|
}
|
|
12291
|
-
const buf = (0,
|
|
12706
|
+
const buf = (0, import_node_fs34.readFileSync)(abs);
|
|
12292
12707
|
if (isImageRelativePath(relativePath)) {
|
|
12293
12708
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
12294
12709
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -12331,9 +12746,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
12331
12746
|
}
|
|
12332
12747
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
12333
12748
|
assertSafeRelativePath(relativePath);
|
|
12334
|
-
const abs = (0,
|
|
12335
|
-
(0,
|
|
12336
|
-
(0,
|
|
12749
|
+
const abs = (0, import_node_path31.join)(worktreePath, relativePath);
|
|
12750
|
+
(0, import_node_fs34.mkdirSync)((0, import_node_path31.dirname)(abs), { recursive: true });
|
|
12751
|
+
(0, import_node_fs34.writeFileSync)(abs, content, "utf8");
|
|
12337
12752
|
return { path: relativePath };
|
|
12338
12753
|
}
|
|
12339
12754
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -12437,9 +12852,9 @@ async function confirmLand(thread, opts) {
|
|
|
12437
12852
|
}
|
|
12438
12853
|
|
|
12439
12854
|
// src/skills/discover.ts
|
|
12440
|
-
var
|
|
12441
|
-
var
|
|
12442
|
-
var
|
|
12855
|
+
var import_node_fs35 = require("fs");
|
|
12856
|
+
var import_node_os11 = require("os");
|
|
12857
|
+
var import_node_path32 = require("path");
|
|
12443
12858
|
function toCommand(name) {
|
|
12444
12859
|
return name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
12445
12860
|
}
|
|
@@ -12471,7 +12886,7 @@ function parseFrontmatter(content) {
|
|
|
12471
12886
|
}
|
|
12472
12887
|
function readSkill(skillMd, source) {
|
|
12473
12888
|
try {
|
|
12474
|
-
const content = (0,
|
|
12889
|
+
const content = (0, import_node_fs35.readFileSync)(skillMd, "utf8");
|
|
12475
12890
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
12476
12891
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
12477
12892
|
const name = fmName || dirName;
|
|
@@ -12490,19 +12905,19 @@ function readSkill(skillMd, source) {
|
|
|
12490
12905
|
}
|
|
12491
12906
|
}
|
|
12492
12907
|
function scanSkillsDir(dir, source, out) {
|
|
12493
|
-
if (!(0,
|
|
12908
|
+
if (!(0, import_node_fs35.existsSync)(dir)) return;
|
|
12494
12909
|
let entries;
|
|
12495
12910
|
try {
|
|
12496
|
-
entries = (0,
|
|
12911
|
+
entries = (0, import_node_fs35.readdirSync)(dir);
|
|
12497
12912
|
} catch {
|
|
12498
12913
|
return;
|
|
12499
12914
|
}
|
|
12500
12915
|
for (const entry of entries) {
|
|
12501
12916
|
if (entry.startsWith(".")) continue;
|
|
12502
|
-
const skillMd = (0,
|
|
12503
|
-
if (!(0,
|
|
12917
|
+
const skillMd = (0, import_node_path32.join)(dir, entry, "SKILL.md");
|
|
12918
|
+
if (!(0, import_node_fs35.existsSync)(skillMd)) continue;
|
|
12504
12919
|
try {
|
|
12505
|
-
if (!(0,
|
|
12920
|
+
if (!(0, import_node_fs35.statSync)(skillMd).isFile()) continue;
|
|
12506
12921
|
} catch {
|
|
12507
12922
|
continue;
|
|
12508
12923
|
}
|
|
@@ -12511,24 +12926,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
12511
12926
|
}
|
|
12512
12927
|
}
|
|
12513
12928
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
12514
|
-
if (!(0,
|
|
12929
|
+
if (!(0, import_node_fs35.existsSync)(pluginsRoot)) return;
|
|
12515
12930
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
12516
12931
|
if (depth > 7) return;
|
|
12517
12932
|
let entries;
|
|
12518
12933
|
try {
|
|
12519
|
-
entries = (0,
|
|
12934
|
+
entries = (0, import_node_fs35.readdirSync)(dir);
|
|
12520
12935
|
} catch {
|
|
12521
12936
|
return;
|
|
12522
12937
|
}
|
|
12523
12938
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
12524
|
-
const skill = readSkill((0,
|
|
12939
|
+
const skill = readSkill((0, import_node_path32.join)(dir, "SKILL.md"), "cli");
|
|
12525
12940
|
if (skill) out.push(skill);
|
|
12526
12941
|
}
|
|
12527
12942
|
for (const entry of entries) {
|
|
12528
12943
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
12529
|
-
const full = (0,
|
|
12944
|
+
const full = (0, import_node_path32.join)(dir, entry);
|
|
12530
12945
|
try {
|
|
12531
|
-
if (!(0,
|
|
12946
|
+
if (!(0, import_node_fs35.statSync)(full).isDirectory()) continue;
|
|
12532
12947
|
} catch {
|
|
12533
12948
|
continue;
|
|
12534
12949
|
}
|
|
@@ -12543,20 +12958,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
12543
12958
|
walk(pluginsRoot, 0, false);
|
|
12544
12959
|
}
|
|
12545
12960
|
function discoverSkills(worktreePath) {
|
|
12546
|
-
const home = (0,
|
|
12961
|
+
const home = (0, import_node_os11.homedir)();
|
|
12547
12962
|
const collected = [];
|
|
12548
12963
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
12549
|
-
scanSkillsDir((0,
|
|
12964
|
+
scanSkillsDir((0, import_node_path32.join)(worktreePath, rel), "workspace", collected);
|
|
12550
12965
|
}
|
|
12551
12966
|
for (const abs of [
|
|
12552
|
-
(0,
|
|
12553
|
-
(0,
|
|
12554
|
-
(0,
|
|
12555
|
-
(0,
|
|
12967
|
+
(0, import_node_path32.join)(home, ".claude/skills"),
|
|
12968
|
+
(0, import_node_path32.join)(home, ".cursor/skills"),
|
|
12969
|
+
(0, import_node_path32.join)(home, ".sideboard/skills"),
|
|
12970
|
+
(0, import_node_path32.join)(home, ".brightsy/skills")
|
|
12556
12971
|
]) {
|
|
12557
12972
|
scanSkillsDir(abs, "user", collected);
|
|
12558
12973
|
}
|
|
12559
|
-
scanClaudePluginSkills((0,
|
|
12974
|
+
scanClaudePluginSkills((0, import_node_path32.join)(home, ".claude/plugins"), collected);
|
|
12560
12975
|
const rank = { workspace: 0, user: 1, cli: 2 };
|
|
12561
12976
|
const byCommand = /* @__PURE__ */ new Map();
|
|
12562
12977
|
for (const skill of collected) {
|
|
@@ -12568,7 +12983,7 @@ function discoverSkills(worktreePath) {
|
|
|
12568
12983
|
return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
|
|
12569
12984
|
}
|
|
12570
12985
|
function readSkillBody(skillPath, maxChars = 12e3) {
|
|
12571
|
-
const raw = (0,
|
|
12986
|
+
const raw = (0, import_node_fs35.readFileSync)(skillPath, "utf8");
|
|
12572
12987
|
if (raw.startsWith("---")) {
|
|
12573
12988
|
const end = raw.indexOf("\n---", 3);
|
|
12574
12989
|
if (end >= 0) {
|
|
@@ -12661,8 +13076,8 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
12661
13076
|
}
|
|
12662
13077
|
|
|
12663
13078
|
// src/composer/stage-files.ts
|
|
12664
|
-
var
|
|
12665
|
-
var
|
|
13079
|
+
var import_node_fs36 = require("fs");
|
|
13080
|
+
var import_node_path33 = require("path");
|
|
12666
13081
|
var import_node_crypto7 = require("crypto");
|
|
12667
13082
|
init_workspace_scratch();
|
|
12668
13083
|
var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
@@ -12688,7 +13103,7 @@ var IMAGE_MIME_BY_EXT = {
|
|
|
12688
13103
|
var MAX_INLINE_BYTES = 4e5;
|
|
12689
13104
|
var MAX_PREVIEW_BYTES = 5e6;
|
|
12690
13105
|
function fileExtension(filePath) {
|
|
12691
|
-
const base = (0,
|
|
13106
|
+
const base = (0, import_node_path33.basename)(filePath).toLowerCase();
|
|
12692
13107
|
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
12693
13108
|
}
|
|
12694
13109
|
function isImageFilePath(filePath) {
|
|
@@ -12698,22 +13113,22 @@ function imageMimeType(filePath) {
|
|
|
12698
13113
|
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
12699
13114
|
}
|
|
12700
13115
|
function ensureAttachmentsDir(worktreePath) {
|
|
12701
|
-
const dir = (0,
|
|
12702
|
-
(0,
|
|
12703
|
-
const gi = (0,
|
|
12704
|
-
if (!(0,
|
|
12705
|
-
(0,
|
|
13116
|
+
const dir = (0, import_node_path33.join)(worktreePath, ATTACHMENTS_DIR);
|
|
13117
|
+
(0, import_node_fs36.mkdirSync)(dir, { recursive: true });
|
|
13118
|
+
const gi = (0, import_node_path33.join)(dir, ".gitignore");
|
|
13119
|
+
if (!(0, import_node_fs36.existsSync)(gi)) {
|
|
13120
|
+
(0, import_node_fs36.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
12706
13121
|
}
|
|
12707
13122
|
return dir;
|
|
12708
13123
|
}
|
|
12709
13124
|
function uniqueAttachmentName(dir, originalName) {
|
|
12710
13125
|
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
12711
|
-
if (!(0,
|
|
12712
|
-
const ext = (0,
|
|
13126
|
+
if (!(0, import_node_fs36.existsSync)((0, import_node_path33.join)(dir, safe))) return safe;
|
|
13127
|
+
const ext = (0, import_node_path33.extname)(safe);
|
|
12713
13128
|
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
12714
13129
|
for (let i = 1; i < 1e4; i++) {
|
|
12715
13130
|
const candidate = `${stem}-${i}${ext}`;
|
|
12716
|
-
if (!(0,
|
|
13131
|
+
if (!(0, import_node_fs36.existsSync)((0, import_node_path33.join)(dir, candidate))) return candidate;
|
|
12717
13132
|
}
|
|
12718
13133
|
return `${stem}-${(0, import_node_crypto7.randomUUID)()}${ext}`;
|
|
12719
13134
|
}
|
|
@@ -12769,15 +13184,15 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
|
12769
13184
|
const dir = ensureAttachmentsDir(worktreePath);
|
|
12770
13185
|
const out = [];
|
|
12771
13186
|
for (const abs of absolutePaths) {
|
|
12772
|
-
const originalName = (0,
|
|
13187
|
+
const originalName = (0, import_node_path33.basename)(abs);
|
|
12773
13188
|
try {
|
|
12774
|
-
const st = (0,
|
|
13189
|
+
const st = (0, import_node_fs36.statSync)(abs);
|
|
12775
13190
|
if (!st.isFile()) continue;
|
|
12776
13191
|
const name = uniqueAttachmentName(dir, originalName);
|
|
12777
|
-
const destAbs = (0,
|
|
12778
|
-
(0,
|
|
13192
|
+
const destAbs = (0, import_node_path33.join)(dir, name);
|
|
13193
|
+
(0, import_node_fs36.copyFileSync)(abs, destAbs);
|
|
12779
13194
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
12780
|
-
const buf = (0,
|
|
13195
|
+
const buf = (0, import_node_fs36.readFileSync)(destAbs);
|
|
12781
13196
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
12782
13197
|
} catch (err) {
|
|
12783
13198
|
out.push({
|
|
@@ -12799,8 +13214,8 @@ function stageBuffersAsAttachments(worktreePath, buffers) {
|
|
|
12799
13214
|
try {
|
|
12800
13215
|
const buf = Buffer.from(item.dataBase64, "base64");
|
|
12801
13216
|
const name = uniqueAttachmentName(dir, originalName);
|
|
12802
|
-
const destAbs = (0,
|
|
12803
|
-
(0,
|
|
13217
|
+
const destAbs = (0, import_node_path33.join)(dir, name);
|
|
13218
|
+
(0, import_node_fs36.writeFileSync)(destAbs, buf);
|
|
12804
13219
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
12805
13220
|
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
12806
13221
|
} catch (err) {
|
|
@@ -12820,18 +13235,18 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
12820
13235
|
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
12821
13236
|
out.push({
|
|
12822
13237
|
id: (0, import_node_crypto7.randomUUID)(),
|
|
12823
|
-
name: (0,
|
|
13238
|
+
name: (0, import_node_path33.basename)(rel) || "file",
|
|
12824
13239
|
kind: "file",
|
|
12825
13240
|
content: `(invalid path: ${rel})`
|
|
12826
13241
|
});
|
|
12827
13242
|
continue;
|
|
12828
13243
|
}
|
|
12829
|
-
const name = (0,
|
|
13244
|
+
const name = (0, import_node_path33.basename)(rel);
|
|
12830
13245
|
try {
|
|
12831
|
-
const abs = (0,
|
|
12832
|
-
const st = (0,
|
|
13246
|
+
const abs = (0, import_node_path33.join)(worktreePath, rel);
|
|
13247
|
+
const st = (0, import_node_fs36.statSync)(abs);
|
|
12833
13248
|
if (!st.isFile()) continue;
|
|
12834
|
-
const buf = (0,
|
|
13249
|
+
const buf = (0, import_node_fs36.readFileSync)(abs);
|
|
12835
13250
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
12836
13251
|
} catch (err) {
|
|
12837
13252
|
out.push({
|
|
@@ -12846,8 +13261,8 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
12846
13261
|
}
|
|
12847
13262
|
|
|
12848
13263
|
// src/agents/instructions.ts
|
|
12849
|
-
var
|
|
12850
|
-
var
|
|
13264
|
+
var import_node_fs37 = require("fs");
|
|
13265
|
+
var import_node_path34 = require("path");
|
|
12851
13266
|
init_git_auth_mode();
|
|
12852
13267
|
init_worktree_labels();
|
|
12853
13268
|
function normPath3(p) {
|
|
@@ -12980,9 +13395,10 @@ function formatArtifactDirective() {
|
|
|
12980
13395
|
"Files / media browser (CMS file manager column):",
|
|
12981
13396
|
"4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
|
|
12982
13397
|
" Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
|
|
12983
|
-
"Multiple-choice questions
|
|
12984
|
-
"5) Call Sideboard MCP `ask_user` when
|
|
12985
|
-
"
|
|
13398
|
+
"Multiple-choice questions:",
|
|
13399
|
+
"5) Call Sideboard MCP `ask_user` only when work is blocked on choosing among a few concrete options (approach forks, which API, auth vs cookies). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. If you are asking a real multiple-choice, use ask_user rather than chat bullets so Sideboard shows the composer picker.",
|
|
13400
|
+
"Do not call ask_user for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat. If one option is the obvious default, proceed without asking.",
|
|
13401
|
+
"Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
|
|
12986
13402
|
].join("\n");
|
|
12987
13403
|
}
|
|
12988
13404
|
function formatUiReminder() {
|
|
@@ -12993,7 +13409,7 @@ function formatUiReminder() {
|
|
|
12993
13409
|
"CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
|
|
12994
13410
|
"Files column: MCP present_files (brightsy account storage or memory).",
|
|
12995
13411
|
"Do not say artifacts/CMS UI are unavailable.",
|
|
12996
|
-
"
|
|
13412
|
+
"ask_user: only when blocked on a real multiple-choice (approach fork, which API). Never for hellos, check-ins, or \u201Cwhat next?\u201D menus \u2014 reply in chat."
|
|
12997
13413
|
].join(" ");
|
|
12998
13414
|
}
|
|
12999
13415
|
|
|
@@ -13121,7 +13537,7 @@ var Orchestrator = class {
|
|
|
13121
13537
|
}
|
|
13122
13538
|
continue;
|
|
13123
13539
|
}
|
|
13124
|
-
if (!(0,
|
|
13540
|
+
if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
|
|
13125
13541
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
13126
13542
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
13127
13543
|
continue;
|
|
@@ -13624,10 +14040,12 @@ var Orchestrator = class {
|
|
|
13624
14040
|
if (event.type === "stderr" && typeof event.data === "string") {
|
|
13625
14041
|
pushTurnStderr(stderrTail, event.data);
|
|
13626
14042
|
}
|
|
13627
|
-
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
14043
|
+
if (event.type !== "stdout" && event.type !== "thinking") {
|
|
14044
|
+
const live = readThread(threadId);
|
|
14045
|
+
if (live?.lastError?.includes("reconciled on startup") && (this.activeTurns.has(threadId) || this.startingTurns.has(threadId))) {
|
|
14046
|
+
setStatus(threadId, "running");
|
|
14047
|
+
this.emit({ type: "status_changed", threadId, status: "running" });
|
|
14048
|
+
}
|
|
13631
14049
|
}
|
|
13632
14050
|
}
|
|
13633
14051
|
);
|
|
@@ -14211,8 +14629,9 @@ var Orchestrator = class {
|
|
|
14211
14629
|
return result;
|
|
14212
14630
|
}
|
|
14213
14631
|
async mergePr(threadRef) {
|
|
14214
|
-
const { thread,
|
|
14632
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
14215
14633
|
this.assertNotGlobal(thread, "Merge PR");
|
|
14634
|
+
const selector = selectors[0];
|
|
14216
14635
|
if (!selector) throw new Error("No pull request linked to this thread");
|
|
14217
14636
|
const result = await mergePr(cwd, selector);
|
|
14218
14637
|
const state = normalizePrState(result.state) || "MERGED";
|
|
@@ -14232,29 +14651,34 @@ var Orchestrator = class {
|
|
|
14232
14651
|
await this.persistPrMetaAndMaybeArchive(thread, metaLike);
|
|
14233
14652
|
return { url: metaLike.url, state };
|
|
14234
14653
|
}
|
|
14235
|
-
/** Resolve PR
|
|
14654
|
+
/** Resolve PR selectors and optionally persist `prUrl` when found. */
|
|
14236
14655
|
async withPrSelector(threadRef) {
|
|
14237
14656
|
const thread = this.requireThread(threadRef);
|
|
14238
|
-
const
|
|
14657
|
+
const selectors = resolvePrSelectors(thread);
|
|
14239
14658
|
const cwd = thread.worktreePath;
|
|
14240
14659
|
if (!cwd?.trim()) {
|
|
14241
14660
|
throw new Error(`Thread ${threadRef} has no worktreePath`);
|
|
14242
14661
|
}
|
|
14243
|
-
return { thread,
|
|
14662
|
+
return { thread, selectors, cwd };
|
|
14244
14663
|
}
|
|
14245
14664
|
async getPrChecks(threadRef) {
|
|
14246
|
-
const {
|
|
14247
|
-
|
|
14248
|
-
|
|
14665
|
+
const { selectors, cwd } = await this.withPrSelector(threadRef);
|
|
14666
|
+
for (const selector of selectors) {
|
|
14667
|
+
const checks = await getPrChecks(cwd, selector);
|
|
14668
|
+
if (checks) return checks;
|
|
14669
|
+
}
|
|
14670
|
+
return null;
|
|
14249
14671
|
}
|
|
14250
14672
|
async getPrMeta(threadRef) {
|
|
14251
|
-
const { thread,
|
|
14252
|
-
|
|
14253
|
-
|
|
14254
|
-
|
|
14255
|
-
|
|
14673
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
14674
|
+
for (const selector of selectors) {
|
|
14675
|
+
const meta = await getPrMeta(cwd, selector);
|
|
14676
|
+
if (meta) {
|
|
14677
|
+
await this.persistPrMetaAndMaybeArchive(thread, meta);
|
|
14678
|
+
return meta;
|
|
14679
|
+
}
|
|
14256
14680
|
}
|
|
14257
|
-
return
|
|
14681
|
+
return null;
|
|
14258
14682
|
}
|
|
14259
14683
|
/**
|
|
14260
14684
|
* Persist PR URL/title/state and Conductor-style auto-archive when the PR
|
|
@@ -14378,9 +14802,12 @@ var Orchestrator = class {
|
|
|
14378
14802
|
return { stack: result.stack, threads: result.threads };
|
|
14379
14803
|
}
|
|
14380
14804
|
async getPrDetails(threadRef) {
|
|
14381
|
-
const { thread,
|
|
14382
|
-
|
|
14383
|
-
const
|
|
14805
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
14806
|
+
let details = null;
|
|
14807
|
+
for (const selector of selectors) {
|
|
14808
|
+
details = await getPrDetails(cwd, selector);
|
|
14809
|
+
if (details) break;
|
|
14810
|
+
}
|
|
14384
14811
|
if (details) {
|
|
14385
14812
|
const patch = {};
|
|
14386
14813
|
if (details.url && details.url !== thread.prUrl) patch.prUrl = details.url;
|
|
@@ -14607,7 +15034,7 @@ var Orchestrator = class {
|
|
|
14607
15034
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
14608
15035
|
return restored2;
|
|
14609
15036
|
}
|
|
14610
|
-
if (!(0,
|
|
15037
|
+
if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
|
|
14611
15038
|
const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
|
|
14612
15039
|
const { execa: execa7 } = await import("execa");
|
|
14613
15040
|
const slug = thread.worktreePath.split("/").pop();
|
|
@@ -15774,6 +16201,7 @@ function registerLinearTools(server) {
|
|
|
15774
16201
|
}
|
|
15775
16202
|
|
|
15776
16203
|
// src/mcp/server.ts
|
|
16204
|
+
init_git_auth_mode();
|
|
15777
16205
|
var MAX_ORCH_THREADS = 5;
|
|
15778
16206
|
var CREATE_THREAD_TIMEOUT_MS = 9e4;
|
|
15779
16207
|
function withTimeout(promise, ms, label) {
|
|
@@ -15795,6 +16223,14 @@ function withTimeout(promise, ms, label) {
|
|
|
15795
16223
|
}
|
|
15796
16224
|
async function startMcpServer() {
|
|
15797
16225
|
const orch = getOrchestrator();
|
|
16226
|
+
try {
|
|
16227
|
+
await warmGithubAgentAuth();
|
|
16228
|
+
} catch (err) {
|
|
16229
|
+
console.error(
|
|
16230
|
+
"[sideboard-mcp] GitHub agent auth warm skipped:",
|
|
16231
|
+
err instanceof Error ? err.message : err
|
|
16232
|
+
);
|
|
16233
|
+
}
|
|
15798
16234
|
try {
|
|
15799
16235
|
const { maxConcurrentAgents: maxConcurrentAgents2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
|
|
15800
16236
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
@@ -15838,7 +16274,7 @@ async function startMcpServer() {
|
|
|
15838
16274
|
async () => {
|
|
15839
16275
|
const threads = orch.getThreads(true);
|
|
15840
16276
|
const lines = threads.map((t) => {
|
|
15841
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
16277
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path38.basename)(t.repoPath) || t.repoPath;
|
|
15842
16278
|
return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}`;
|
|
15843
16279
|
});
|
|
15844
16280
|
return {
|
|
@@ -15901,7 +16337,7 @@ async function startMcpServer() {
|
|
|
15901
16337
|
);
|
|
15902
16338
|
server.tool(
|
|
15903
16339
|
"ask_user",
|
|
15904
|
-
"Ask the user clarifying multiple-choice
|
|
16340
|
+
"Ask the user a clarifying multiple-choice question in Sideboard\u2019s composer. Call only when work is blocked on choosing among a few concrete options (approach fork, which API, auth vs cookies). Do not call for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat instead. If one option is the obvious default, proceed without asking. Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. After calling, stop and wait for answers. Not for \u201Cis the plan ready?\u201D.",
|
|
15905
16341
|
{
|
|
15906
16342
|
questions: import_zod3.z.array(
|
|
15907
16343
|
import_zod3.z.object({
|