@sideboard-ai/core 0.1.89 → 0.1.95
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 +129 -14
- package/dist/agents/cursor-runner.js +4 -1
- package/dist/{agents-LMUFTGKF.js → agents-HBLA6FEV.js} +4 -4
- package/dist/{agents-ODBP7J6E.js → agents-WS5QV6LE.js} +5 -5
- 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-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
- package/dist/{chunk-RJLBSYUO.js → chunk-KWNUZ4LR.js} +46 -77
- 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-JE75QW2I.js → chunk-WBX46OPD.js} +237 -96
- 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 +1021 -473
- package/dist/index.d.cts +91 -20
- package/dist/index.d.ts +91 -20
- package/dist/index.js +244 -59
- package/dist/mcp/run-stdio.cjs +816 -428
- package/dist/mcp/run-stdio.js +77 -40
- 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/index.cjs
CHANGED
|
@@ -3068,42 +3068,124 @@ var init_gh_errors = __esm({
|
|
|
3068
3068
|
}
|
|
3069
3069
|
});
|
|
3070
3070
|
|
|
3071
|
+
// src/git/github-agent-auth.ts
|
|
3072
|
+
function githubAgentAuthDir() {
|
|
3073
|
+
const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
|
|
3074
|
+
if (override) return override;
|
|
3075
|
+
return (0, import_node_path10.join)((0, import_node_os4.homedir)(), ".sideboard-git-auth");
|
|
3076
|
+
}
|
|
3077
|
+
function githubCredentialStorePath() {
|
|
3078
|
+
return (0, import_node_path10.join)(githubAgentAuthDir(), "git-credentials");
|
|
3079
|
+
}
|
|
3080
|
+
function githubGhConfigDir() {
|
|
3081
|
+
return (0, import_node_path10.join)(githubAgentAuthDir(), "gh");
|
|
3082
|
+
}
|
|
3083
|
+
function writePrivateFile2(file, body) {
|
|
3084
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path10.dirname)(file), { recursive: true, mode: 448 });
|
|
3085
|
+
try {
|
|
3086
|
+
(0, import_node_fs10.chmodSync)((0, import_node_path10.dirname)(file), 448);
|
|
3087
|
+
} catch {
|
|
3088
|
+
}
|
|
3089
|
+
(0, import_node_fs10.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
3090
|
+
try {
|
|
3091
|
+
(0, import_node_fs10.chmodSync)(file, 384);
|
|
3092
|
+
} catch {
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
function gitCredentialStoreContents(token) {
|
|
3096
|
+
return `https://x-access-token:${encodeURIComponent(token)}@github.com
|
|
3097
|
+
`;
|
|
3098
|
+
}
|
|
3099
|
+
function ghHostsYml(token, user = "x-access-token") {
|
|
3100
|
+
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
3101
|
+
return [
|
|
3102
|
+
"github.com:",
|
|
3103
|
+
" git_protocol: https",
|
|
3104
|
+
` user: ${u}`,
|
|
3105
|
+
` oauth_token: ${token}`,
|
|
3106
|
+
" users:",
|
|
3107
|
+
` ${u}:`,
|
|
3108
|
+
` oauth_token: ${token}`,
|
|
3109
|
+
""
|
|
3110
|
+
].join("\n");
|
|
3111
|
+
}
|
|
3112
|
+
function materializeGithubAgentAuth(token, user) {
|
|
3113
|
+
const trimmed = token.trim();
|
|
3114
|
+
if (!trimmed) return;
|
|
3115
|
+
const root = githubAgentAuthDir();
|
|
3116
|
+
(0, import_node_fs10.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
3117
|
+
try {
|
|
3118
|
+
(0, import_node_fs10.chmodSync)(root, 448);
|
|
3119
|
+
} catch {
|
|
3120
|
+
}
|
|
3121
|
+
writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
|
|
3122
|
+
const ghDir = githubGhConfigDir();
|
|
3123
|
+
(0, import_node_fs10.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
3124
|
+
writePrivateFile2((0, import_node_path10.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
3125
|
+
writePrivateFile2((0, import_node_path10.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
3126
|
+
}
|
|
3127
|
+
function githubAgentAuthReady() {
|
|
3128
|
+
return (0, import_node_fs10.existsSync)(githubCredentialStorePath()) && (0, import_node_fs10.existsSync)((0, import_node_path10.join)(githubGhConfigDir(), "hosts.yml"));
|
|
3129
|
+
}
|
|
3130
|
+
function githubCredentialHelperGitConfig() {
|
|
3131
|
+
const file = githubCredentialStorePath();
|
|
3132
|
+
return [
|
|
3133
|
+
{ key: "credential.helper", value: "" },
|
|
3134
|
+
{ key: "credential.helper", value: `store --file=${file}` }
|
|
3135
|
+
];
|
|
3136
|
+
}
|
|
3137
|
+
function githubGhConfigEnv() {
|
|
3138
|
+
return {
|
|
3139
|
+
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
3140
|
+
GH_PROMPT_DISABLED: "1"
|
|
3141
|
+
};
|
|
3142
|
+
}
|
|
3143
|
+
var import_node_fs10, import_node_os4, import_node_path10;
|
|
3144
|
+
var init_github_agent_auth = __esm({
|
|
3145
|
+
"src/git/github-agent-auth.ts"() {
|
|
3146
|
+
"use strict";
|
|
3147
|
+
import_node_fs10 = require("fs");
|
|
3148
|
+
import_node_os4 = require("os");
|
|
3149
|
+
import_node_path10 = require("path");
|
|
3150
|
+
}
|
|
3151
|
+
});
|
|
3152
|
+
|
|
3071
3153
|
// src/agents/path.ts
|
|
3072
3154
|
function prependPathDir(env, dir) {
|
|
3073
|
-
if (!dir || !(0,
|
|
3155
|
+
if (!dir || !(0, import_node_fs11.existsSync)(dir)) return;
|
|
3074
3156
|
const current = env.PATH ?? "";
|
|
3075
|
-
const parts = current.split(
|
|
3157
|
+
const parts = current.split(import_node_path11.delimiter).filter(Boolean);
|
|
3076
3158
|
if (parts.includes(dir)) {
|
|
3077
3159
|
env.PATH = current;
|
|
3078
3160
|
return;
|
|
3079
3161
|
}
|
|
3080
|
-
env.PATH = [dir, ...parts].join(
|
|
3162
|
+
env.PATH = [dir, ...parts].join(import_node_path11.delimiter);
|
|
3081
3163
|
}
|
|
3082
|
-
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0,
|
|
3083
|
-
return (0,
|
|
3164
|
+
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os5.homedir)()) {
|
|
3165
|
+
return (0, import_node_path11.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
|
|
3084
3166
|
}
|
|
3085
3167
|
function isConductorBundledCli(filePath) {
|
|
3086
3168
|
const p = (filePath ?? "").replace(/\\/g, "/");
|
|
3087
3169
|
return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
|
|
3088
3170
|
}
|
|
3089
3171
|
function ensureAgentPath(env = process.env) {
|
|
3090
|
-
const home = env.HOME || env.USERPROFILE || (0,
|
|
3172
|
+
const home = env.HOME || env.USERPROFILE || (0, import_node_os5.homedir)();
|
|
3091
3173
|
const current = env.PATH ?? "";
|
|
3092
|
-
const parts = current.split(
|
|
3174
|
+
const parts = current.split(import_node_path11.delimiter).filter(Boolean);
|
|
3093
3175
|
const seen = new Set(parts);
|
|
3094
3176
|
const extras = [
|
|
3095
|
-
...EXTRA_BIN_DIRS.map((rel) => (0,
|
|
3177
|
+
...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path11.join)(home, rel)),
|
|
3096
3178
|
"/opt/homebrew/bin",
|
|
3097
3179
|
"/usr/local/bin",
|
|
3098
3180
|
// Keep after Homebrew/npm so a user-installed CLI still wins.
|
|
3099
3181
|
conductorBundledBinDir(home)
|
|
3100
3182
|
];
|
|
3101
3183
|
for (const dir of extras.reverse()) {
|
|
3102
|
-
if (!dir || seen.has(dir) || !(0,
|
|
3184
|
+
if (!dir || seen.has(dir) || !(0, import_node_fs11.existsSync)(dir)) continue;
|
|
3103
3185
|
parts.unshift(dir);
|
|
3104
3186
|
seen.add(dir);
|
|
3105
3187
|
}
|
|
3106
|
-
const next = parts.join(
|
|
3188
|
+
const next = parts.join(import_node_path11.delimiter);
|
|
3107
3189
|
env.PATH = next;
|
|
3108
3190
|
return next;
|
|
3109
3191
|
}
|
|
@@ -3117,7 +3199,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
|
|
|
3117
3199
|
stdio: ["ignore", "pipe", "ignore"]
|
|
3118
3200
|
}).trim().split(/\r?\n/).find(Boolean);
|
|
3119
3201
|
if (prefix) {
|
|
3120
|
-
const binDir = process.platform === "win32" ? prefix : (0,
|
|
3202
|
+
const binDir = process.platform === "win32" ? prefix : (0, import_node_path11.join)(prefix, "bin");
|
|
3121
3203
|
prependPathDir(env, binDir);
|
|
3122
3204
|
}
|
|
3123
3205
|
} catch {
|
|
@@ -3145,14 +3227,14 @@ function withExportedPath(command, pathValue) {
|
|
|
3145
3227
|
if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
|
|
3146
3228
|
return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
|
|
3147
3229
|
}
|
|
3148
|
-
var
|
|
3230
|
+
var import_node_fs11, import_node_child_process3, import_node_os5, import_node_path11, EXTRA_BIN_DIRS;
|
|
3149
3231
|
var init_path = __esm({
|
|
3150
3232
|
"src/agents/path.ts"() {
|
|
3151
3233
|
"use strict";
|
|
3152
|
-
|
|
3234
|
+
import_node_fs11 = require("fs");
|
|
3153
3235
|
import_node_child_process3 = require("child_process");
|
|
3154
|
-
|
|
3155
|
-
|
|
3236
|
+
import_node_os5 = require("os");
|
|
3237
|
+
import_node_path11 = require("path");
|
|
3156
3238
|
EXTRA_BIN_DIRS = [
|
|
3157
3239
|
".local/bin",
|
|
3158
3240
|
".cargo/bin",
|
|
@@ -3277,42 +3359,46 @@ function appendIndexedGitConfig(existing, entries) {
|
|
|
3277
3359
|
return out;
|
|
3278
3360
|
}
|
|
3279
3361
|
function githubAgentGitEnv(existing) {
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
function githubHttpsBearerEnv(existing, token) {
|
|
3283
|
-
const rewrite = githubAgentGitEnv(existing);
|
|
3284
|
-
const header = appendIndexedGitConfig(
|
|
3285
|
-
{ ...existing, ...rewrite },
|
|
3286
|
-
[
|
|
3287
|
-
{
|
|
3288
|
-
key: "http.https://github.com/.extraHeader",
|
|
3289
|
-
value: `AUTHORIZATION: bearer ${token}`
|
|
3290
|
-
}
|
|
3291
|
-
]
|
|
3292
|
-
);
|
|
3293
|
-
return { ...rewrite, ...header };
|
|
3362
|
+
const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
|
|
3363
|
+
return appendIndexedGitConfig(existing, [...HTTPS_REWRITE, ...helpers]);
|
|
3294
3364
|
}
|
|
3295
3365
|
function applyGithubGitAuthEnv(existing, opts) {
|
|
3296
3366
|
const out = { ...nonInteractiveGitProcessEnv() };
|
|
3367
|
+
const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
|
|
3368
|
+
if (token) materializeGithubAgentAuth(token);
|
|
3369
|
+
Object.assign(out, githubGhConfigEnv());
|
|
3297
3370
|
if (opts.mode === "ssh") return out;
|
|
3298
|
-
|
|
3299
|
-
const provided = existingToken ? "" : opts.token?.trim() || "";
|
|
3300
|
-
const token = existingToken || provided;
|
|
3301
|
-
Object.assign(
|
|
3302
|
-
out,
|
|
3303
|
-
token ? githubHttpsBearerEnv(existing, token) : githubAgentGitEnv(existing)
|
|
3304
|
-
);
|
|
3305
|
-
if (provided) out.GH_TOKEN = provided;
|
|
3371
|
+
Object.assign(out, githubAgentGitEnv(existing));
|
|
3306
3372
|
return out;
|
|
3307
3373
|
}
|
|
3374
|
+
function scrubGithubTokensFromChildEnv(env) {
|
|
3375
|
+
for (const key of GITHUB_CHILD_TOKEN_KEYS) {
|
|
3376
|
+
delete env[key];
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
function mergeAgentGitAuthEnv(env, gitEnv) {
|
|
3380
|
+
Object.assign(env, gitEnv);
|
|
3381
|
+
scrubGithubTokensFromChildEnv(env);
|
|
3382
|
+
}
|
|
3308
3383
|
async function resolveGithubAgentToken(mode, cwd) {
|
|
3309
|
-
if (mode ===
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3384
|
+
if (tokenMemo && tokenMemo.mode === mode && Date.now() - tokenMemo.at < TOKEN_TTL_MS) {
|
|
3385
|
+
return tokenMemo.value;
|
|
3386
|
+
}
|
|
3387
|
+
let value = null;
|
|
3388
|
+
if (mode === "token") {
|
|
3389
|
+
value = getGithubPat();
|
|
3390
|
+
} else {
|
|
3391
|
+
try {
|
|
3392
|
+
value = await resolveGhAuthToken(cwd);
|
|
3393
|
+
} catch {
|
|
3394
|
+
value = null;
|
|
3395
|
+
}
|
|
3315
3396
|
}
|
|
3397
|
+
tokenMemo = { mode, value, at: Date.now() };
|
|
3398
|
+
return value;
|
|
3399
|
+
}
|
|
3400
|
+
function resetGithubAgentTokenMemo() {
|
|
3401
|
+
tokenMemo = null;
|
|
3316
3402
|
}
|
|
3317
3403
|
async function resolveAgentGitAuthEnv(existing, opts) {
|
|
3318
3404
|
let mode = "auto";
|
|
@@ -3334,7 +3420,40 @@ async function resolveAgentGitAuthEnv(existing, opts) {
|
|
|
3334
3420
|
}
|
|
3335
3421
|
return applyGithubGitAuthEnv(existing, { mode, token });
|
|
3336
3422
|
}
|
|
3337
|
-
function
|
|
3423
|
+
async function warmGithubAgentAuth(opts) {
|
|
3424
|
+
if (!opts?.force && githubAgentAuthReady()) return;
|
|
3425
|
+
await resolveAgentGitAuthEnv(void 0, opts);
|
|
3426
|
+
}
|
|
3427
|
+
function normalizeWritableRoot(raw) {
|
|
3428
|
+
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
3429
|
+
return trimmed && (0, import_node_path12.isAbsolute)(trimmed) ? trimmed : null;
|
|
3430
|
+
}
|
|
3431
|
+
async function resolveCodexGitWritableRoots(cwd) {
|
|
3432
|
+
const roots = /* @__PURE__ */ new Set();
|
|
3433
|
+
const authDir = normalizeWritableRoot(githubAgentAuthDir());
|
|
3434
|
+
if (authDir) roots.add(authDir);
|
|
3435
|
+
try {
|
|
3436
|
+
const [gitDir, commonDir] = await Promise.all([
|
|
3437
|
+
git(["rev-parse", "--absolute-git-dir"], cwd, { reject: false, timeoutMs: 5e3 }),
|
|
3438
|
+
git(["rev-parse", "--path-format=absolute", "--git-common-dir"], cwd, {
|
|
3439
|
+
reject: false,
|
|
3440
|
+
timeoutMs: 5e3
|
|
3441
|
+
})
|
|
3442
|
+
]);
|
|
3443
|
+
const gitDirPath = gitDir.exitCode === 0 ? normalizeWritableRoot(gitDir.stdout) : null;
|
|
3444
|
+
const commonPath = commonDir.exitCode === 0 ? normalizeWritableRoot(commonDir.stdout) : null;
|
|
3445
|
+
if (gitDirPath) roots.add(gitDirPath);
|
|
3446
|
+
if (commonPath) roots.add(commonPath);
|
|
3447
|
+
} catch {
|
|
3448
|
+
}
|
|
3449
|
+
return [...roots];
|
|
3450
|
+
}
|
|
3451
|
+
function codexSandboxWritableRootsArgs(roots) {
|
|
3452
|
+
const abs = [...new Set(roots.map(normalizeWritableRoot).filter(Boolean))];
|
|
3453
|
+
if (abs.length === 0) return [];
|
|
3454
|
+
return ["-c", `sandbox_workspace_write.writable_roots=${JSON.stringify(abs)}`];
|
|
3455
|
+
}
|
|
3456
|
+
function codexUnattendedGitConfigArgs(sandbox, opts) {
|
|
3338
3457
|
const args = [
|
|
3339
3458
|
"-c",
|
|
3340
3459
|
'shell_environment_policy.inherit="all"',
|
|
@@ -3343,54 +3462,65 @@ function codexUnattendedGitConfigArgs(sandbox) {
|
|
|
3343
3462
|
];
|
|
3344
3463
|
if (sandbox === "workspace-write") {
|
|
3345
3464
|
args.push("-c", "sandbox_workspace_write.network_access=true");
|
|
3465
|
+
args.push(...codexSandboxWritableRootsArgs(opts?.writableRoots ?? []));
|
|
3346
3466
|
}
|
|
3347
3467
|
return args;
|
|
3348
3468
|
}
|
|
3349
3469
|
function formatGitAuthModeDirective(mode) {
|
|
3470
|
+
const shared = [
|
|
3471
|
+
"- `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.",
|
|
3472
|
+
"- Do not set GitHub token environment variables, pass `--with-token`, or run `gh auth login` from this turn.",
|
|
3473
|
+
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below.",
|
|
3474
|
+
"- 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."
|
|
3475
|
+
];
|
|
3350
3476
|
switch (mode) {
|
|
3351
3477
|
case "gh":
|
|
3352
3478
|
return [
|
|
3353
3479
|
"Git authentication (Account \u2192 GitHub mode: gh CLI):",
|
|
3354
3480
|
"- This process rewrites `git@github.com:` and `ssh://git@github.com/` to HTTPS.",
|
|
3355
|
-
|
|
3356
|
-
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
3481
|
+
...shared
|
|
3357
3482
|
].join("\n");
|
|
3358
3483
|
case "ssh":
|
|
3359
3484
|
return [
|
|
3360
3485
|
"Git authentication (Account \u2192 GitHub mode: SSH):",
|
|
3361
3486
|
"- Keep SSH remotes (`git@github.com:\u2026`). Do not rewrite them to HTTPS.",
|
|
3362
3487
|
"- 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.",
|
|
3363
|
-
"-
|
|
3488
|
+
"- `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.",
|
|
3489
|
+
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
3364
3490
|
].join("\n");
|
|
3365
3491
|
case "token":
|
|
3366
3492
|
return [
|
|
3367
3493
|
"Git authentication (Account \u2192 GitHub mode: personal access token):",
|
|
3368
3494
|
"- This process rewrites GitHub SSH remotes to HTTPS.",
|
|
3369
|
-
|
|
3370
|
-
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
3495
|
+
...shared
|
|
3371
3496
|
].join("\n");
|
|
3372
3497
|
case "auto":
|
|
3373
3498
|
default:
|
|
3374
3499
|
return [
|
|
3375
3500
|
"Git authentication (Account \u2192 GitHub mode: auto):",
|
|
3376
|
-
"- This process rewrites GitHub SSH remotes to HTTPS
|
|
3377
|
-
|
|
3378
|
-
"- 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."
|
|
3501
|
+
"- This process rewrites GitHub SSH remotes to HTTPS so git/ssh never prompt the macOS Keychain (required for unattended orchestrator turns).",
|
|
3502
|
+
...shared
|
|
3379
3503
|
].join("\n");
|
|
3380
3504
|
}
|
|
3381
3505
|
}
|
|
3382
|
-
var HTTPS_REWRITE;
|
|
3506
|
+
var import_node_path12, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
|
|
3383
3507
|
var init_git_auth_mode = __esm({
|
|
3384
3508
|
"src/git/git-auth-mode.ts"() {
|
|
3385
3509
|
"use strict";
|
|
3510
|
+
import_node_path12 = require("path");
|
|
3386
3511
|
init_app_settings();
|
|
3512
|
+
init_github_agent_auth();
|
|
3387
3513
|
init_run();
|
|
3388
3514
|
HTTPS_REWRITE = [
|
|
3389
3515
|
{ key: "url.https://github.com/.insteadOf", value: "git@github.com:" },
|
|
3390
|
-
{ key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" }
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3516
|
+
{ key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" }
|
|
3517
|
+
];
|
|
3518
|
+
TOKEN_TTL_MS = 12 * 60 * 60 * 1e3;
|
|
3519
|
+
tokenMemo = null;
|
|
3520
|
+
GITHUB_CHILD_TOKEN_KEYS = [
|
|
3521
|
+
"GH_TOKEN",
|
|
3522
|
+
"GITHUB_TOKEN",
|
|
3523
|
+
"GH_ENTERPRISE_TOKEN"
|
|
3394
3524
|
];
|
|
3395
3525
|
}
|
|
3396
3526
|
});
|
|
@@ -3751,10 +3881,12 @@ __export(worktree_exports, {
|
|
|
3751
3881
|
getPr: () => getPr,
|
|
3752
3882
|
getPrChecks: () => getPrChecks,
|
|
3753
3883
|
getPrDetails: () => getPrDetails,
|
|
3884
|
+
getPrForHeadBranch: () => getPrForHeadBranch,
|
|
3754
3885
|
getPrMeta: () => getPrMeta,
|
|
3755
3886
|
ghHeadRef: () => ghHeadRef,
|
|
3756
3887
|
ghRepoSelectArgs: () => ghRepoSelectArgs,
|
|
3757
3888
|
githubAgentGitEnv: () => githubAgentGitEnv,
|
|
3889
|
+
isDefaultishSourceRef: () => isDefaultishSourceRef,
|
|
3758
3890
|
isDirty: () => isDirty,
|
|
3759
3891
|
isPlaceholderBranch: () => isPlaceholderBranch,
|
|
3760
3892
|
isSideboardScratchPath: () => isSideboardScratchPath,
|
|
@@ -3772,6 +3904,7 @@ __export(worktree_exports, {
|
|
|
3772
3904
|
resolveDiffBaseRef: () => resolveDiffBaseRef,
|
|
3773
3905
|
resolveGithubRepoSlug: () => resolveGithubRepoSlug,
|
|
3774
3906
|
resolvePrSelector: () => resolvePrSelector,
|
|
3907
|
+
resolvePrSelectors: () => resolvePrSelectors,
|
|
3775
3908
|
resolveRepoRoot: () => resolveRepoRoot,
|
|
3776
3909
|
resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
|
|
3777
3910
|
slugify: () => slugify,
|
|
@@ -3880,7 +4013,7 @@ async function originGhRepoEnv(cwd, opts) {
|
|
|
3880
4013
|
await ensureGhPreferOrigin(cwd);
|
|
3881
4014
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
3882
4015
|
const mode = opts?.mode ?? getGithubGitAuthMode();
|
|
3883
|
-
const token =
|
|
4016
|
+
const token = await resolveGithubAgentToken(mode, cwd);
|
|
3884
4017
|
return {
|
|
3885
4018
|
...applyGithubGitAuthEnv(opts?.env, { mode, token }),
|
|
3886
4019
|
...slug ? { GH_REPO: slug } : {}
|
|
@@ -4020,13 +4153,78 @@ async function getPr(repoPath, number) {
|
|
|
4020
4153
|
if (exitCode !== 0 || !stdout.trim()) return null;
|
|
4021
4154
|
return JSON.parse(stdout);
|
|
4022
4155
|
}
|
|
4023
|
-
function
|
|
4024
|
-
|
|
4156
|
+
function normalizeGitBranchName(ref) {
|
|
4157
|
+
return ref.trim().replace(/^refs\/heads\//, "").replace(/^origin\//, "");
|
|
4158
|
+
}
|
|
4159
|
+
function isDefaultishSourceRef(ref) {
|
|
4160
|
+
const n = normalizeGitBranchName(ref ?? "").toLowerCase();
|
|
4161
|
+
return !n || n === "head" || n === "default" || n === "main" || n === "master" || n === "develop" || n === "trunk";
|
|
4162
|
+
}
|
|
4163
|
+
function resolvePrSelectors(thread) {
|
|
4164
|
+
const out = [];
|
|
4165
|
+
const push = (value) => {
|
|
4166
|
+
const v = value?.trim();
|
|
4167
|
+
if (!v || out.includes(v)) return;
|
|
4168
|
+
out.push(v);
|
|
4169
|
+
};
|
|
4170
|
+
push(thread.prUrl);
|
|
4025
4171
|
if (thread.sourceType === "pr" && thread.sourceRef?.trim()) {
|
|
4026
|
-
|
|
4172
|
+
push(thread.sourceRef.replace(/^#/, "").trim());
|
|
4173
|
+
}
|
|
4174
|
+
push(thread.branchName);
|
|
4175
|
+
if (thread.sourceType === "branch") {
|
|
4176
|
+
const source = normalizeGitBranchName(thread.sourceRef ?? "");
|
|
4177
|
+
if (source && !isDefaultishSourceRef(source) && source !== thread.branchName?.trim()) {
|
|
4178
|
+
push(source);
|
|
4179
|
+
}
|
|
4180
|
+
}
|
|
4181
|
+
return out;
|
|
4182
|
+
}
|
|
4183
|
+
function resolvePrSelector(thread) {
|
|
4184
|
+
return resolvePrSelectors(thread)[0] ?? null;
|
|
4185
|
+
}
|
|
4186
|
+
async function getPrForHeadBranch(repoPath, branch) {
|
|
4187
|
+
const head = normalizeGitBranchName(branch);
|
|
4188
|
+
if (!head || isDefaultishSourceRef(head)) return null;
|
|
4189
|
+
const slug = await resolveGithubRepoSlug(repoPath);
|
|
4190
|
+
const viewArgs = [
|
|
4191
|
+
"pr",
|
|
4192
|
+
"view",
|
|
4193
|
+
head,
|
|
4194
|
+
"--json",
|
|
4195
|
+
"number,title,headRefName,url,isCrossRepository"
|
|
4196
|
+
];
|
|
4197
|
+
if (slug) viewArgs.push("--repo", slug);
|
|
4198
|
+
const viewed = await gh(viewArgs, repoPath, { reject: false });
|
|
4199
|
+
if (viewed.exitCode === 0 && viewed.stdout.trim()) {
|
|
4200
|
+
try {
|
|
4201
|
+
return JSON.parse(viewed.stdout);
|
|
4202
|
+
} catch {
|
|
4203
|
+
return null;
|
|
4204
|
+
}
|
|
4205
|
+
}
|
|
4206
|
+
const listHead = slug ? ghHeadRef(slug, head) : head;
|
|
4207
|
+
const listArgs = [
|
|
4208
|
+
"pr",
|
|
4209
|
+
"list",
|
|
4210
|
+
"--head",
|
|
4211
|
+
listHead,
|
|
4212
|
+
"--json",
|
|
4213
|
+
"number,title,headRefName,url,isCrossRepository",
|
|
4214
|
+
"--limit",
|
|
4215
|
+
"1",
|
|
4216
|
+
"--state",
|
|
4217
|
+
"open"
|
|
4218
|
+
];
|
|
4219
|
+
if (slug) listArgs.push("--repo", slug);
|
|
4220
|
+
const listed = await gh(listArgs, repoPath, { reject: false });
|
|
4221
|
+
if (listed.exitCode !== 0 || !listed.stdout.trim()) return null;
|
|
4222
|
+
try {
|
|
4223
|
+
const rows = JSON.parse(listed.stdout);
|
|
4224
|
+
return rows[0] ?? null;
|
|
4225
|
+
} catch {
|
|
4226
|
+
return null;
|
|
4027
4227
|
}
|
|
4028
|
-
if (thread.branchName?.trim()) return thread.branchName.trim();
|
|
4029
|
-
return null;
|
|
4030
4228
|
}
|
|
4031
4229
|
function normalizeGhTime(value) {
|
|
4032
4230
|
if (typeof value !== "string" || !value.trim()) return null;
|
|
@@ -4352,7 +4550,7 @@ async function fetchPrHead(repoPath, number, localBranch) {
|
|
|
4352
4550
|
const label = opts?.ghAuth ? `${remote} (gh auth)` : remote;
|
|
4353
4551
|
const gitOpts = { reject: false };
|
|
4354
4552
|
if (opts?.ghAuth) {
|
|
4355
|
-
const token = await
|
|
4553
|
+
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), repoPath);
|
|
4356
4554
|
if (!token) {
|
|
4357
4555
|
errors.push(`${label}: gh auth token unavailable`);
|
|
4358
4556
|
return false;
|
|
@@ -4403,7 +4601,7 @@ async function fetchPrHead(repoPath, number, localBranch) {
|
|
|
4403
4601
|
const ensureOid = async (remote, opts) => {
|
|
4404
4602
|
const gitOpts = { reject: false };
|
|
4405
4603
|
if (opts?.ghAuth) {
|
|
4406
|
-
const token = await
|
|
4604
|
+
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), repoPath);
|
|
4407
4605
|
if (!token) return false;
|
|
4408
4606
|
gitOpts.env = { GIT_TERMINAL_PROMPT: "0" };
|
|
4409
4607
|
gitOpts.config = {
|
|
@@ -4471,8 +4669,8 @@ function isLocalPrFetchBranch(ref) {
|
|
|
4471
4669
|
}
|
|
4472
4670
|
async function createThreadWorktree(opts) {
|
|
4473
4671
|
let branchName = `thread/${opts.slug}`;
|
|
4474
|
-
const worktreePath = (0,
|
|
4475
|
-
if ((0,
|
|
4672
|
+
const worktreePath = (0, import_node_path13.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
4673
|
+
if ((0, import_node_fs12.existsSync)(worktreePath)) {
|
|
4476
4674
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
4477
4675
|
}
|
|
4478
4676
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -4541,8 +4739,8 @@ ${add.stdout}`;
|
|
|
4541
4739
|
async function createExistingBranchWorktree(opts) {
|
|
4542
4740
|
const branchName = opts.branchName.trim();
|
|
4543
4741
|
if (!branchName) throw new Error("branch name required");
|
|
4544
|
-
const worktreePath = (0,
|
|
4545
|
-
if ((0,
|
|
4742
|
+
const worktreePath = (0, import_node_path13.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
4743
|
+
if ((0, import_node_fs12.existsSync)(worktreePath)) {
|
|
4546
4744
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
4547
4745
|
}
|
|
4548
4746
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -4653,7 +4851,7 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
4653
4851
|
if (ssh.exitCode === 0) return;
|
|
4654
4852
|
const sshErr = (ssh.stderr || ssh.stdout).trim();
|
|
4655
4853
|
const slug = await resolveGithubRepoSlug(worktreePath);
|
|
4656
|
-
const token = await
|
|
4854
|
+
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
|
|
4657
4855
|
if (!slug || !token) {
|
|
4658
4856
|
throw new Error(
|
|
4659
4857
|
sshErr || `git push origin ${branchName} failed` + (!token ? " (no SSH agent and gh auth token unavailable \u2014 run: gh auth login)" : "")
|
|
@@ -4830,10 +5028,10 @@ function sameRepoPath(a, b) {
|
|
|
4830
5028
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
4831
5029
|
}
|
|
4832
5030
|
function listLocalThreadBranchSlugs(repoPath) {
|
|
4833
|
-
const refsDir = (0,
|
|
4834
|
-
if (!(0,
|
|
5031
|
+
const refsDir = (0, import_node_path13.join)(repoPath, ".git", "refs", "heads", "thread");
|
|
5032
|
+
if (!(0, import_node_fs12.existsSync)(refsDir)) return [];
|
|
4835
5033
|
try {
|
|
4836
|
-
return (0,
|
|
5034
|
+
return (0, import_node_fs12.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
|
|
4837
5035
|
} catch {
|
|
4838
5036
|
return [];
|
|
4839
5037
|
}
|
|
@@ -4841,8 +5039,8 @@ function listLocalThreadBranchSlugs(repoPath) {
|
|
|
4841
5039
|
function collectTakenTeamSlugs(repoPath) {
|
|
4842
5040
|
const taken = /* @__PURE__ */ new Set();
|
|
4843
5041
|
const root = worktreesRoot(repoPath);
|
|
4844
|
-
if ((0,
|
|
4845
|
-
for (const entry of (0,
|
|
5042
|
+
if ((0, import_node_fs12.existsSync)(root)) {
|
|
5043
|
+
for (const entry of (0, import_node_fs12.readdirSync)(root, { withFileTypes: true })) {
|
|
4846
5044
|
if (entry.isDirectory() && entry.name !== ".DS_Store") {
|
|
4847
5045
|
taken.add(normalizeTakenSlug(entry.name));
|
|
4848
5046
|
}
|
|
@@ -4863,18 +5061,18 @@ function allocateTeamSlug(repoPath) {
|
|
|
4863
5061
|
const taken = collectTakenTeamSlugs(repoPath);
|
|
4864
5062
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
4865
5063
|
const team = allocateTeamName(taken);
|
|
4866
|
-
const path2 = (0,
|
|
4867
|
-
if (!(0,
|
|
5064
|
+
const path2 = (0, import_node_path13.join)(worktreesRoot(repoPath), team.slug);
|
|
5065
|
+
if (!(0, import_node_fs12.existsSync)(path2)) return team;
|
|
4868
5066
|
taken.add(team.slug);
|
|
4869
5067
|
}
|
|
4870
5068
|
throw new Error("No available soccer team worktree directories left");
|
|
4871
5069
|
}
|
|
4872
|
-
var
|
|
5070
|
+
var import_node_fs12, import_node_path13;
|
|
4873
5071
|
var init_worktree = __esm({
|
|
4874
5072
|
"src/git/worktree.ts"() {
|
|
4875
5073
|
"use strict";
|
|
4876
|
-
|
|
4877
|
-
|
|
5074
|
+
import_node_fs12 = require("fs");
|
|
5075
|
+
import_node_path13 = require("path");
|
|
4878
5076
|
init_paths();
|
|
4879
5077
|
init_thread_store();
|
|
4880
5078
|
init_teams();
|
|
@@ -4958,7 +5156,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
4958
5156
|
function ensureGlobalCoordinatorCwd(opts) {
|
|
4959
5157
|
const dir = globalAgentCwd();
|
|
4960
5158
|
try {
|
|
4961
|
-
(0,
|
|
5159
|
+
(0, import_node_fs13.mkdirSync)(dir, { recursive: true });
|
|
4962
5160
|
} catch {
|
|
4963
5161
|
return dir;
|
|
4964
5162
|
}
|
|
@@ -4966,7 +5164,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
4966
5164
|
let orchId = opts?.orchestratorThreadId?.trim() || "";
|
|
4967
5165
|
if (!orchId) {
|
|
4968
5166
|
try {
|
|
4969
|
-
const existing = (0,
|
|
5167
|
+
const existing = (0, import_node_fs13.readFileSync)((0, import_node_path14.join)(dir, "AGENTS.md"), "utf8");
|
|
4970
5168
|
const m = existing.match(
|
|
4971
5169
|
/YOUR orchestration thread id is `([0-9a-f-]{36})`/i
|
|
4972
5170
|
);
|
|
@@ -5008,9 +5206,9 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
5008
5206
|
"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."
|
|
5009
5207
|
].join("\n");
|
|
5010
5208
|
try {
|
|
5011
|
-
(0,
|
|
5209
|
+
(0, import_node_fs13.writeFileSync)((0, import_node_path14.join)(dir, "CLAUDE.md"), `${body}
|
|
5012
5210
|
`, "utf8");
|
|
5013
|
-
(0,
|
|
5211
|
+
(0, import_node_fs13.writeFileSync)((0, import_node_path14.join)(dir, "AGENTS.md"), `${body}
|
|
5014
5212
|
`, "utf8");
|
|
5015
5213
|
} catch {
|
|
5016
5214
|
}
|
|
@@ -5042,12 +5240,12 @@ function coordinatorSystemPrompt(opts) {
|
|
|
5042
5240
|
formatWorkspaceInventory(opts.workspaces)
|
|
5043
5241
|
].join("\n");
|
|
5044
5242
|
}
|
|
5045
|
-
var
|
|
5243
|
+
var import_node_fs13, import_node_path14, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
|
|
5046
5244
|
var init_coordinator_prompt = __esm({
|
|
5047
5245
|
"src/orchestrator/coordinator-prompt.ts"() {
|
|
5048
5246
|
"use strict";
|
|
5049
|
-
|
|
5050
|
-
|
|
5247
|
+
import_node_fs13 = require("fs");
|
|
5248
|
+
import_node_path14 = require("path");
|
|
5051
5249
|
init_worktree();
|
|
5052
5250
|
init_app_settings();
|
|
5053
5251
|
init_paths();
|
|
@@ -5063,7 +5261,7 @@ var init_coordinator_prompt = __esm({
|
|
|
5063
5261
|
"- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
|
|
5064
5262
|
"- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
|
|
5065
5263
|
"- list_threads / get_thread \u2014 fleet status (what is going on)",
|
|
5066
|
-
"- ask_user \u2014 multiple-choice
|
|
5264
|
+
"- 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.",
|
|
5067
5265
|
"- 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.",
|
|
5068
5266
|
"Workspaces:",
|
|
5069
5267
|
"- add_workspace / remove_workspace \u2014 register or unregister a git repo",
|
|
@@ -5353,38 +5551,38 @@ __export(workspaces_exports, {
|
|
|
5353
5551
|
syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
|
|
5354
5552
|
});
|
|
5355
5553
|
function workspacesFile() {
|
|
5356
|
-
return (0,
|
|
5554
|
+
return (0, import_node_path15.join)(appDataDir(), "workspaces.json");
|
|
5357
5555
|
}
|
|
5358
5556
|
function removedWorkspacesFile() {
|
|
5359
|
-
return (0,
|
|
5557
|
+
return (0, import_node_path15.join)(appDataDir(), "removed-workspaces.json");
|
|
5360
5558
|
}
|
|
5361
5559
|
function readAll() {
|
|
5362
5560
|
const path2 = workspacesFile();
|
|
5363
|
-
if (!(0,
|
|
5561
|
+
if (!(0, import_node_fs14.existsSync)(path2)) return [];
|
|
5364
5562
|
try {
|
|
5365
|
-
const raw = JSON.parse((0,
|
|
5563
|
+
const raw = JSON.parse((0, import_node_fs14.readFileSync)(path2, "utf8"));
|
|
5366
5564
|
return Array.isArray(raw) ? raw : [];
|
|
5367
5565
|
} catch {
|
|
5368
5566
|
return [];
|
|
5369
5567
|
}
|
|
5370
5568
|
}
|
|
5371
5569
|
function writeAll(list) {
|
|
5372
|
-
(0,
|
|
5373
|
-
(0,
|
|
5570
|
+
(0, import_node_fs14.mkdirSync)(appDataDir(), { recursive: true });
|
|
5571
|
+
(0, import_node_fs14.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
|
|
5374
5572
|
}
|
|
5375
5573
|
function readRemoved() {
|
|
5376
5574
|
const path2 = removedWorkspacesFile();
|
|
5377
|
-
if (!(0,
|
|
5575
|
+
if (!(0, import_node_fs14.existsSync)(path2)) return /* @__PURE__ */ new Set();
|
|
5378
5576
|
try {
|
|
5379
|
-
const raw = JSON.parse((0,
|
|
5577
|
+
const raw = JSON.parse((0, import_node_fs14.readFileSync)(path2, "utf8"));
|
|
5380
5578
|
return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
|
|
5381
5579
|
} catch {
|
|
5382
5580
|
return /* @__PURE__ */ new Set();
|
|
5383
5581
|
}
|
|
5384
5582
|
}
|
|
5385
5583
|
function writeRemoved(paths) {
|
|
5386
|
-
(0,
|
|
5387
|
-
(0,
|
|
5584
|
+
(0, import_node_fs14.mkdirSync)(appDataDir(), { recursive: true });
|
|
5585
|
+
(0, import_node_fs14.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
|
|
5388
5586
|
}
|
|
5389
5587
|
function rememberRemoved(repoPath) {
|
|
5390
5588
|
const next = readRemoved();
|
|
@@ -5407,7 +5605,7 @@ function listWorkspaces() {
|
|
|
5407
5605
|
async function addWorkspace(repoPath) {
|
|
5408
5606
|
const root = await resolveRepoRoot(repoPath);
|
|
5409
5607
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
5410
|
-
if (!(0,
|
|
5608
|
+
if (!(0, import_node_fs14.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
|
|
5411
5609
|
forgetRemoved(root);
|
|
5412
5610
|
await ensureGhPreferOrigin(root);
|
|
5413
5611
|
const current = readAll();
|
|
@@ -5415,7 +5613,7 @@ async function addWorkspace(repoPath) {
|
|
|
5415
5613
|
if (existing) return existing;
|
|
5416
5614
|
const next = {
|
|
5417
5615
|
path: root,
|
|
5418
|
-
name: (0,
|
|
5616
|
+
name: (0, import_node_path15.basename)(root),
|
|
5419
5617
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5420
5618
|
};
|
|
5421
5619
|
writeAll([...current, next]);
|
|
@@ -5437,10 +5635,10 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
5437
5635
|
if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
|
|
5438
5636
|
continue;
|
|
5439
5637
|
}
|
|
5440
|
-
if (!(0,
|
|
5638
|
+
if (!(0, import_node_fs14.existsSync)(path2)) continue;
|
|
5441
5639
|
const ws = {
|
|
5442
5640
|
path: path2,
|
|
5443
|
-
name: (0,
|
|
5641
|
+
name: (0, import_node_path15.basename)(path2),
|
|
5444
5642
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5445
5643
|
};
|
|
5446
5644
|
byPath.set(path2, ws);
|
|
@@ -5450,12 +5648,12 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
5450
5648
|
if (dirty) writeAll(next);
|
|
5451
5649
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
5452
5650
|
}
|
|
5453
|
-
var
|
|
5651
|
+
var import_node_fs14, import_node_path15;
|
|
5454
5652
|
var init_workspaces = __esm({
|
|
5455
5653
|
"src/store/workspaces.ts"() {
|
|
5456
5654
|
"use strict";
|
|
5457
|
-
|
|
5458
|
-
|
|
5655
|
+
import_node_fs14 = require("fs");
|
|
5656
|
+
import_node_path15 = require("path");
|
|
5459
5657
|
init_paths();
|
|
5460
5658
|
init_global_workspace();
|
|
5461
5659
|
init_worktree();
|
|
@@ -5464,32 +5662,32 @@ var init_workspaces = __esm({
|
|
|
5464
5662
|
|
|
5465
5663
|
// src/brightsy/config.ts
|
|
5466
5664
|
function brightsyConfigPath() {
|
|
5467
|
-
return (0,
|
|
5665
|
+
return (0, import_node_path16.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
|
|
5468
5666
|
}
|
|
5469
5667
|
function loadBrightsyConfig() {
|
|
5470
5668
|
const path2 = brightsyConfigPath();
|
|
5471
|
-
if (!(0,
|
|
5669
|
+
if (!(0, import_node_fs15.existsSync)(path2)) {
|
|
5472
5670
|
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
5473
5671
|
}
|
|
5474
|
-
const raw = JSON.parse((0,
|
|
5672
|
+
const raw = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
|
|
5475
5673
|
if (!raw.access_token || !raw.account_id) {
|
|
5476
5674
|
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
5477
5675
|
}
|
|
5478
5676
|
return raw;
|
|
5479
5677
|
}
|
|
5480
5678
|
function saveBrightsyConfig(cfg) {
|
|
5481
|
-
(0,
|
|
5679
|
+
(0, import_node_fs15.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
5482
5680
|
`, {
|
|
5483
5681
|
mode: 384
|
|
5484
5682
|
});
|
|
5485
5683
|
}
|
|
5486
|
-
var
|
|
5684
|
+
var import_node_fs15, import_node_os6, import_node_path16;
|
|
5487
5685
|
var init_config = __esm({
|
|
5488
5686
|
"src/brightsy/config.ts"() {
|
|
5489
5687
|
"use strict";
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5688
|
+
import_node_fs15 = require("fs");
|
|
5689
|
+
import_node_os6 = require("os");
|
|
5690
|
+
import_node_path16 = require("path");
|
|
5493
5691
|
}
|
|
5494
5692
|
});
|
|
5495
5693
|
|
|
@@ -5592,22 +5790,22 @@ __export(connected_teams_exports, {
|
|
|
5592
5790
|
listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
|
|
5593
5791
|
});
|
|
5594
5792
|
function storePath() {
|
|
5595
|
-
return (0,
|
|
5793
|
+
return (0, import_node_path17.join)(appDataDir(), "brightsy-teams.json");
|
|
5596
5794
|
}
|
|
5597
5795
|
function readStore() {
|
|
5598
5796
|
const path2 = storePath();
|
|
5599
|
-
if (!(0,
|
|
5797
|
+
if (!(0, import_node_fs16.existsSync)(path2)) return [];
|
|
5600
5798
|
try {
|
|
5601
|
-
const parsed = JSON.parse((0,
|
|
5799
|
+
const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
|
|
5602
5800
|
return Array.isArray(parsed.teams) ? parsed.teams : [];
|
|
5603
5801
|
} catch {
|
|
5604
5802
|
return [];
|
|
5605
5803
|
}
|
|
5606
5804
|
}
|
|
5607
5805
|
function writeStore(teams) {
|
|
5608
|
-
(0,
|
|
5806
|
+
(0, import_node_fs16.mkdirSync)(appDataDir(), { recursive: true });
|
|
5609
5807
|
const path2 = storePath();
|
|
5610
|
-
(0,
|
|
5808
|
+
(0, import_node_fs16.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
|
|
5611
5809
|
`, {
|
|
5612
5810
|
mode: 384
|
|
5613
5811
|
});
|
|
@@ -5769,12 +5967,12 @@ function brightsyMcpServerName(slug) {
|
|
|
5769
5967
|
const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
|
|
5770
5968
|
return `brightsy_${cleaned || "team"}`;
|
|
5771
5969
|
}
|
|
5772
|
-
var
|
|
5970
|
+
var import_node_fs16, import_node_path17;
|
|
5773
5971
|
var init_connected_teams = __esm({
|
|
5774
5972
|
"src/brightsy/connected-teams.ts"() {
|
|
5775
5973
|
"use strict";
|
|
5776
|
-
|
|
5777
|
-
|
|
5974
|
+
import_node_fs16 = require("fs");
|
|
5975
|
+
import_node_path17 = require("path");
|
|
5778
5976
|
init_paths();
|
|
5779
5977
|
init_accounts();
|
|
5780
5978
|
init_config();
|
|
@@ -5911,17 +6109,27 @@ function extractJsonErrorMessage(obj) {
|
|
|
5911
6109
|
}
|
|
5912
6110
|
return null;
|
|
5913
6111
|
}
|
|
6112
|
+
function isPinnedStderrLine(line) {
|
|
6113
|
+
if (/^\s*at\s/.test(line)) return false;
|
|
6114
|
+
return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:/i.test(
|
|
6115
|
+
line
|
|
6116
|
+
);
|
|
6117
|
+
}
|
|
5914
6118
|
function pushTurnStderr(tail, line, maxLines = 12) {
|
|
5915
6119
|
const trimmed = line.trim();
|
|
5916
6120
|
if (!trimmed) return;
|
|
5917
6121
|
if (NODE_VERSION_FOOTER.test(trimmed)) return;
|
|
5918
6122
|
if (/^reconnecting\.\.\./i.test(trimmed)) return;
|
|
5919
6123
|
tail.push(trimmed);
|
|
5920
|
-
while (tail.length > maxLines)
|
|
6124
|
+
while (tail.length > maxLines) {
|
|
6125
|
+
const dropIdx = tail.findIndex((l) => !isPinnedStderrLine(l));
|
|
6126
|
+
if (dropIdx === -1) tail.shift();
|
|
6127
|
+
else tail.splice(dropIdx, 1);
|
|
6128
|
+
}
|
|
5921
6129
|
}
|
|
5922
6130
|
function looksLikeMinifiedJsDump(line) {
|
|
5923
6131
|
if (line.length < 200) return false;
|
|
5924
|
-
return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line);
|
|
6132
|
+
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);
|
|
5925
6133
|
}
|
|
5926
6134
|
function looksLikeNestedElectronCrash(line) {
|
|
5927
6135
|
return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
|
|
@@ -5936,7 +6144,15 @@ function summarizeTurnStderr(tail, maxChars = 500) {
|
|
|
5936
6144
|
const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
|
|
5937
6145
|
if (cursorStartup) return clipStderr(cursorStartup, maxChars);
|
|
5938
6146
|
if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
|
|
5939
|
-
|
|
6147
|
+
if (tail.some(
|
|
6148
|
+
(line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
|
|
6149
|
+
)) {
|
|
6150
|
+
return clipStderr(
|
|
6151
|
+
"Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.",
|
|
6152
|
+
maxChars
|
|
6153
|
+
);
|
|
6154
|
+
}
|
|
6155
|
+
const moduleMissing = [...tail].reverse().find((line) => /cannot find (?:package|module)/i.test(line));
|
|
5940
6156
|
if (moduleMissing) return clipStderr(moduleMissing, maxChars);
|
|
5941
6157
|
const useful = tail.filter((line) => !looksLikeMinifiedJsDump(line));
|
|
5942
6158
|
if (useful.length === 0 && tail.some(looksLikeMinifiedJsDump)) {
|
|
@@ -5955,7 +6171,7 @@ function looksLikeAgentFailureMessage(text3) {
|
|
|
5955
6171
|
if (!lower) return false;
|
|
5956
6172
|
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(
|
|
5957
6173
|
lower
|
|
5958
|
-
) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower);
|
|
6174
|
+
) || /\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);
|
|
5959
6175
|
}
|
|
5960
6176
|
function fallbackTurnFailDetail(assistantText) {
|
|
5961
6177
|
const t = assistantText.trim();
|
|
@@ -5977,6 +6193,9 @@ function humanizeAgentFailDetail(detail) {
|
|
|
5977
6193
|
if (/\b429\b|rate.?limit|too many requests/.test(lower)) {
|
|
5978
6194
|
return `${raw} \u2014 wait a moment and retry.`;
|
|
5979
6195
|
}
|
|
6196
|
+
if (/\[resource_exhausted\]|resource_exhausted|findfileswithripgrep/.test(lower)) {
|
|
6197
|
+
return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
|
|
6198
|
+
}
|
|
5980
6199
|
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(
|
|
5981
6200
|
lower
|
|
5982
6201
|
)) {
|
|
@@ -6303,11 +6522,11 @@ async function syncCliForTarget(accountId) {
|
|
|
6303
6522
|
}
|
|
6304
6523
|
applyConnectedTeamToCli(team);
|
|
6305
6524
|
}
|
|
6306
|
-
var
|
|
6525
|
+
var import_node_fs17, brightsyAdapter;
|
|
6307
6526
|
var init_brightsy = __esm({
|
|
6308
6527
|
"src/agents/brightsy.ts"() {
|
|
6309
6528
|
"use strict";
|
|
6310
|
-
|
|
6529
|
+
import_node_fs17 = require("fs");
|
|
6311
6530
|
init_run();
|
|
6312
6531
|
init_connected_teams();
|
|
6313
6532
|
init_config();
|
|
@@ -6322,7 +6541,7 @@ var init_brightsy = __esm({
|
|
|
6322
6541
|
async detect() {
|
|
6323
6542
|
const brightsy = resolveAgentExecutable("brightsy");
|
|
6324
6543
|
if (brightsy !== "brightsy") {
|
|
6325
|
-
if (!(0,
|
|
6544
|
+
if (!(0, import_node_fs17.existsSync)(brightsy)) {
|
|
6326
6545
|
return {
|
|
6327
6546
|
agent: "brightsy",
|
|
6328
6547
|
installed: false,
|
|
@@ -6457,13 +6676,38 @@ var init_profile = __esm({
|
|
|
6457
6676
|
|
|
6458
6677
|
// src/agents/node-launch.ts
|
|
6459
6678
|
function isAsarPath(filePath) {
|
|
6679
|
+
if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
|
|
6460
6680
|
return /\.asar([/\\]|$)/.test(filePath);
|
|
6461
6681
|
}
|
|
6682
|
+
function unpackedAsarPath(filePath) {
|
|
6683
|
+
if (!isAsarPath(filePath)) return null;
|
|
6684
|
+
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
6685
|
+
if (unpacked === filePath) return null;
|
|
6686
|
+
return (0, import_node_fs18.existsSync)(unpacked) ? unpacked : null;
|
|
6687
|
+
}
|
|
6688
|
+
function nodeReadableScriptPath(scriptPath) {
|
|
6689
|
+
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
6690
|
+
}
|
|
6691
|
+
async function findSystemNode() {
|
|
6692
|
+
const whichNode = await run("which", ["node"], { reject: false });
|
|
6693
|
+
const fromWhich = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : "";
|
|
6694
|
+
if (fromWhich && !isElectronLikeCommand(fromWhich)) return fromWhich;
|
|
6695
|
+
const fallbacks = [
|
|
6696
|
+
...WELL_KNOWN_NODE_BINS,
|
|
6697
|
+
(0, import_node_path18.join)((0, import_node_os7.homedir)(), ".local/share/fnm/aliases/default/bin/node"),
|
|
6698
|
+
(0, import_node_path18.join)((0, import_node_os7.homedir)(), ".nvm/current/bin/node")
|
|
6699
|
+
];
|
|
6700
|
+
for (const bin of fallbacks) {
|
|
6701
|
+
if ((0, import_node_fs18.existsSync)(bin) && !isElectronLikeCommand(bin)) return bin;
|
|
6702
|
+
}
|
|
6703
|
+
return null;
|
|
6704
|
+
}
|
|
6462
6705
|
function applyNodeLaunch(launch, args) {
|
|
6706
|
+
const readableArgs = args.map(nodeReadableScriptPath);
|
|
6463
6707
|
if (!launch.env.ELECTRON_RUN_AS_NODE) {
|
|
6464
|
-
return { file: launch.file, args, env: launch.env };
|
|
6708
|
+
return { file: launch.file, args: readableArgs, env: launch.env };
|
|
6465
6709
|
}
|
|
6466
|
-
const wrapped = wrapElectronAsNodeLaunch(launch.file,
|
|
6710
|
+
const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
|
|
6467
6711
|
if (process.platform === "win32") {
|
|
6468
6712
|
return { file: wrapped.file, args: wrapped.args, env: launch.env };
|
|
6469
6713
|
}
|
|
@@ -6472,27 +6716,73 @@ function applyNodeLaunch(launch, args) {
|
|
|
6472
6716
|
return { file: wrapped.file, args: wrapped.args, env };
|
|
6473
6717
|
}
|
|
6474
6718
|
async function resolveNodeLaunch(scriptPath) {
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
const whichNode = await run("which", ["node"], { reject: false });
|
|
6482
|
-
const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
|
|
6483
|
-
if (nodeBin) {
|
|
6484
|
-
return { file: nodeBin, env: {} };
|
|
6719
|
+
const script = nodeReadableScriptPath(scriptPath);
|
|
6720
|
+
if (!isAsarPath(script)) {
|
|
6721
|
+
const nodeBin = await findSystemNode();
|
|
6722
|
+
if (nodeBin) {
|
|
6723
|
+
return { file: nodeBin, env: {} };
|
|
6724
|
+
}
|
|
6485
6725
|
}
|
|
6486
6726
|
return {
|
|
6487
6727
|
file: process.execPath,
|
|
6488
6728
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
6489
6729
|
};
|
|
6490
6730
|
}
|
|
6731
|
+
var import_node_fs18, import_node_os7, import_node_path18, WELL_KNOWN_NODE_BINS;
|
|
6491
6732
|
var init_node_launch = __esm({
|
|
6492
6733
|
"src/agents/node-launch.ts"() {
|
|
6493
6734
|
"use strict";
|
|
6735
|
+
import_node_fs18 = require("fs");
|
|
6736
|
+
import_node_os7 = require("os");
|
|
6737
|
+
import_node_path18 = require("path");
|
|
6494
6738
|
init_nested_electron_env();
|
|
6495
6739
|
init_run();
|
|
6740
|
+
WELL_KNOWN_NODE_BINS = [
|
|
6741
|
+
"/opt/homebrew/bin/node",
|
|
6742
|
+
"/usr/local/bin/node"
|
|
6743
|
+
];
|
|
6744
|
+
}
|
|
6745
|
+
});
|
|
6746
|
+
|
|
6747
|
+
// src/agents/packaged-runtime.ts
|
|
6748
|
+
function electronResourcesPath() {
|
|
6749
|
+
const resources = process.resourcesPath;
|
|
6750
|
+
if (typeof resources !== "string" || !resources) return null;
|
|
6751
|
+
return resources;
|
|
6752
|
+
}
|
|
6753
|
+
function packagedCursorRuntimeDir() {
|
|
6754
|
+
const resources = electronResourcesPath();
|
|
6755
|
+
if (!resources) return null;
|
|
6756
|
+
const dir = (0, import_node_path19.join)(resources, "cursor-runtime");
|
|
6757
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path19.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
6758
|
+
return dir;
|
|
6759
|
+
}
|
|
6760
|
+
function packagedCursorRunnerPath() {
|
|
6761
|
+
const dir = packagedCursorRuntimeDir();
|
|
6762
|
+
return dir ? (0, import_node_path19.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
6763
|
+
}
|
|
6764
|
+
function packagedMcpDir() {
|
|
6765
|
+
const resources = electronResourcesPath();
|
|
6766
|
+
if (!resources) return null;
|
|
6767
|
+
const dir = (0, import_node_path19.join)(resources, "sideboard-mcp");
|
|
6768
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path19.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
6769
|
+
return dir;
|
|
6770
|
+
}
|
|
6771
|
+
function packagedMcpStdioPath() {
|
|
6772
|
+
const dir = packagedMcpDir();
|
|
6773
|
+
return dir ? (0, import_node_path19.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
6774
|
+
}
|
|
6775
|
+
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
6776
|
+
const dir = packagedCursorRuntimeDir();
|
|
6777
|
+
if (!dir) return null;
|
|
6778
|
+
return (0, import_node_path19.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
6779
|
+
}
|
|
6780
|
+
var import_node_fs19, import_node_path19;
|
|
6781
|
+
var init_packaged_runtime = __esm({
|
|
6782
|
+
"src/agents/packaged-runtime.ts"() {
|
|
6783
|
+
"use strict";
|
|
6784
|
+
import_node_fs19 = require("fs");
|
|
6785
|
+
import_node_path19 = require("path");
|
|
6496
6786
|
}
|
|
6497
6787
|
});
|
|
6498
6788
|
|
|
@@ -6579,35 +6869,37 @@ function corePackageDir() {
|
|
|
6579
6869
|
try {
|
|
6580
6870
|
const url = import_meta.url;
|
|
6581
6871
|
if (typeof url === "string" && url.length > 0) {
|
|
6582
|
-
return (0,
|
|
6872
|
+
return (0, import_node_path20.dirname)((0, import_node_url.fileURLToPath)(url));
|
|
6583
6873
|
}
|
|
6584
6874
|
} catch {
|
|
6585
6875
|
}
|
|
6586
6876
|
try {
|
|
6587
|
-
const req = (0, import_node_module.createRequire)((0,
|
|
6588
|
-
return (0,
|
|
6877
|
+
const req = (0, import_node_module.createRequire)((0, import_node_path20.join)(process.cwd(), "package.json"));
|
|
6878
|
+
return (0, import_node_path20.dirname)(req.resolve("@sideboard-ai/core"));
|
|
6589
6879
|
} catch {
|
|
6590
6880
|
return process.cwd();
|
|
6591
6881
|
}
|
|
6592
6882
|
}
|
|
6593
6883
|
function findSideboardMcpJsEntry() {
|
|
6594
6884
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
6595
|
-
if (override && (0,
|
|
6885
|
+
if (override && (0, import_node_fs20.existsSync)(override)) return override;
|
|
6886
|
+
const packaged = packagedMcpStdioPath();
|
|
6887
|
+
if (packaged) return packaged;
|
|
6596
6888
|
let dir = corePackageDir();
|
|
6597
6889
|
for (let i = 0; i < 10; i++) {
|
|
6598
6890
|
const candidates = [
|
|
6599
|
-
(0,
|
|
6600
|
-
(0,
|
|
6601
|
-
(0,
|
|
6602
|
-
(0,
|
|
6603
|
-
(0,
|
|
6604
|
-
(0,
|
|
6605
|
-
(0,
|
|
6891
|
+
(0, import_node_path20.join)(dir, "mcp/run-stdio.js"),
|
|
6892
|
+
(0, import_node_path20.join)(dir, "mcp/run-stdio.cjs"),
|
|
6893
|
+
(0, import_node_path20.join)(dir, "dist/mcp/run-stdio.js"),
|
|
6894
|
+
(0, import_node_path20.join)(dir, "dist/mcp/run-stdio.cjs"),
|
|
6895
|
+
(0, import_node_path20.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
|
|
6896
|
+
(0, import_node_path20.join)(dir, "packages/cli/dist/index.js"),
|
|
6897
|
+
(0, import_node_path20.join)(dir, "cli/dist/index.js")
|
|
6606
6898
|
];
|
|
6607
6899
|
for (const p of candidates) {
|
|
6608
|
-
if ((0,
|
|
6900
|
+
if ((0, import_node_fs20.existsSync)(p) && !isAsarPath(p)) return p;
|
|
6609
6901
|
}
|
|
6610
|
-
const parent = (0,
|
|
6902
|
+
const parent = (0, import_node_path20.dirname)(dir);
|
|
6611
6903
|
if (parent === dir) break;
|
|
6612
6904
|
dir = parent;
|
|
6613
6905
|
}
|
|
@@ -6619,12 +6911,14 @@ async function resolveSideboardMcpServer() {
|
|
|
6619
6911
|
const isCli = /[/\\]cli[/\\]dist[/\\]index\.js$/.test(entry);
|
|
6620
6912
|
const scriptArgs = isCli ? [entry, "mcp"] : [entry];
|
|
6621
6913
|
const launch = applyNodeLaunch(await resolveNodeLaunch(entry), scriptArgs);
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6914
|
+
if (launch.file !== "/bin/sh" && !isElectronLikeCommand(launch.file)) {
|
|
6915
|
+
return {
|
|
6916
|
+
name: "sideboard",
|
|
6917
|
+
command: launch.file,
|
|
6918
|
+
args: launch.args,
|
|
6919
|
+
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
6920
|
+
};
|
|
6921
|
+
}
|
|
6628
6922
|
}
|
|
6629
6923
|
const which = await run("which", ["sideboard"], { reject: false });
|
|
6630
6924
|
if (which.exitCode === 0 && which.stdout.trim()) {
|
|
@@ -6647,7 +6941,10 @@ async function buildInjectedMcpServers(opts) {
|
|
|
6647
6941
|
sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
|
|
6648
6942
|
}
|
|
6649
6943
|
try {
|
|
6650
|
-
|
|
6944
|
+
mergeAgentGitAuthEnv(
|
|
6945
|
+
sideboard.env,
|
|
6946
|
+
await resolveAgentGitAuthEnv(sideboard.env)
|
|
6947
|
+
);
|
|
6651
6948
|
} catch {
|
|
6652
6949
|
}
|
|
6653
6950
|
servers.push(sideboard);
|
|
@@ -6669,9 +6966,6 @@ async function buildInjectedMcpServers(opts) {
|
|
|
6669
6966
|
}
|
|
6670
6967
|
return servers;
|
|
6671
6968
|
}
|
|
6672
|
-
function shSingleQuote(value) {
|
|
6673
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
6674
|
-
}
|
|
6675
6969
|
function cursorSafeMcpLaunch(command, args) {
|
|
6676
6970
|
if (process.platform === "win32") {
|
|
6677
6971
|
return args && args.length > 0 ? { command, args } : { command };
|
|
@@ -6679,31 +6973,13 @@ function cursorSafeMcpLaunch(command, args) {
|
|
|
6679
6973
|
const unwrapped = unwrapStrippedElectronLaunch(command, args);
|
|
6680
6974
|
const file = unwrapped?.file ?? command;
|
|
6681
6975
|
const fileArgs = unwrapped?.args ?? args ?? [];
|
|
6682
|
-
|
|
6683
|
-
return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
|
|
6684
|
-
}
|
|
6685
|
-
const dir = (0, import_node_path16.join)(appDataDir(), "mcp-launch");
|
|
6686
|
-
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
6687
|
-
const wrap = (0, import_node_path16.join)(dir, "cursor-electron-as-node.sh");
|
|
6688
|
-
const execLine = [file, ...fileArgs].map(shSingleQuote).join(" ");
|
|
6689
|
-
(0, import_node_fs17.writeFileSync)(
|
|
6690
|
-
wrap,
|
|
6691
|
-
[
|
|
6692
|
-
"#!/bin/sh",
|
|
6693
|
-
"vars=`printenv | awk -F= '/^(ELECTRON_|CHROME_)/{print $1}'`",
|
|
6694
|
-
'[ -n "$vars" ] && unset $vars',
|
|
6695
|
-
"export ELECTRON_RUN_AS_NODE=1",
|
|
6696
|
-
`exec ${execLine} "$@"`,
|
|
6697
|
-
""
|
|
6698
|
-
].join("\n"),
|
|
6699
|
-
{ mode: 493 }
|
|
6700
|
-
);
|
|
6701
|
-
return { command: wrap };
|
|
6976
|
+
return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
|
|
6702
6977
|
}
|
|
6703
6978
|
function mcpSpawnEnv(env) {
|
|
6704
6979
|
if (!env) return void 0;
|
|
6705
6980
|
const out = { ...env };
|
|
6706
6981
|
delete out.ELECTRON_RUN_AS_NODE;
|
|
6982
|
+
delete out.ELECTRON_RUN_AS_NODE;
|
|
6707
6983
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
6708
6984
|
}
|
|
6709
6985
|
function toCursorMcpServers(servers) {
|
|
@@ -6712,6 +6988,7 @@ function toCursorMcpServers(servers) {
|
|
|
6712
6988
|
const env = mcpSpawnEnv(s.env);
|
|
6713
6989
|
const launch = cursorSafeMcpLaunch(s.command, s.args);
|
|
6714
6990
|
out[s.name] = {
|
|
6991
|
+
type: "stdio",
|
|
6715
6992
|
command: launch.command,
|
|
6716
6993
|
...launch.args && launch.args.length > 0 ? { args: launch.args } : {},
|
|
6717
6994
|
...env ? { env } : {}
|
|
@@ -6763,22 +7040,22 @@ function writeMcpServersConfig(servers) {
|
|
|
6763
7040
|
...env ? { env } : {}
|
|
6764
7041
|
};
|
|
6765
7042
|
}
|
|
6766
|
-
const dir = (0,
|
|
6767
|
-
const cfgPath = (0,
|
|
6768
|
-
(0,
|
|
7043
|
+
const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path20.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
|
|
7044
|
+
const cfgPath = (0, import_node_path20.join)(dir, "mcp.json");
|
|
7045
|
+
(0, import_node_fs20.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
6769
7046
|
return cfgPath;
|
|
6770
7047
|
}
|
|
6771
7048
|
async function writeInjectedMcpConfig(opts) {
|
|
6772
7049
|
return writeMcpServersConfig(await buildInjectedMcpServers(opts));
|
|
6773
7050
|
}
|
|
6774
|
-
var
|
|
7051
|
+
var import_node_fs20, import_node_module, import_node_os8, import_node_path20, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
|
|
6775
7052
|
var init_injected_mcp = __esm({
|
|
6776
7053
|
"src/agents/injected-mcp.ts"() {
|
|
6777
7054
|
"use strict";
|
|
6778
|
-
|
|
7055
|
+
import_node_fs20 = require("fs");
|
|
6779
7056
|
import_node_module = require("module");
|
|
6780
|
-
|
|
6781
|
-
|
|
7057
|
+
import_node_os8 = require("os");
|
|
7058
|
+
import_node_path20 = require("path");
|
|
6782
7059
|
import_node_url = require("url");
|
|
6783
7060
|
init_run();
|
|
6784
7061
|
init_config();
|
|
@@ -6787,6 +7064,7 @@ var init_injected_mcp = __esm({
|
|
|
6787
7064
|
init_app_settings();
|
|
6788
7065
|
init_paths();
|
|
6789
7066
|
init_node_launch();
|
|
7067
|
+
init_packaged_runtime();
|
|
6790
7068
|
init_nested_electron_env();
|
|
6791
7069
|
init_git_auth_mode();
|
|
6792
7070
|
import_meta = {};
|
|
@@ -6860,7 +7138,7 @@ var PLAN_MODE_INSTRUCTION;
|
|
|
6860
7138
|
var init_types = __esm({
|
|
6861
7139
|
"src/agents/types.ts"() {
|
|
6862
7140
|
"use strict";
|
|
6863
|
-
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.";
|
|
7141
|
+
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.";
|
|
6864
7142
|
}
|
|
6865
7143
|
});
|
|
6866
7144
|
|
|
@@ -6970,11 +7248,11 @@ function parseIssuesJson(raw) {
|
|
|
6970
7248
|
}
|
|
6971
7249
|
return [];
|
|
6972
7250
|
}
|
|
6973
|
-
var
|
|
7251
|
+
var import_node_fs21, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
|
|
6974
7252
|
var init_claude = __esm({
|
|
6975
7253
|
"src/agents/claude.ts"() {
|
|
6976
7254
|
"use strict";
|
|
6977
|
-
|
|
7255
|
+
import_node_fs21 = require("fs");
|
|
6978
7256
|
init_run();
|
|
6979
7257
|
init_app_settings();
|
|
6980
7258
|
init_claude_mcp();
|
|
@@ -7003,7 +7281,7 @@ var init_claude = __esm({
|
|
|
7003
7281
|
async detect() {
|
|
7004
7282
|
const claude = resolveClaudeExecutable();
|
|
7005
7283
|
if (claude !== "claude") {
|
|
7006
|
-
if (!(0,
|
|
7284
|
+
if (!(0, import_node_fs21.existsSync)(claude)) {
|
|
7007
7285
|
return {
|
|
7008
7286
|
agent: "claude",
|
|
7009
7287
|
installed: false,
|
|
@@ -7240,7 +7518,7 @@ async function listCodexModels() {
|
|
|
7240
7518
|
if (codex === "codex") {
|
|
7241
7519
|
const which = await run("which", ["codex"], { reject: false });
|
|
7242
7520
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
7243
|
-
} else if (!(0,
|
|
7521
|
+
} else if (!(0, import_node_fs22.existsSync)(codex)) {
|
|
7244
7522
|
return FALLBACK_CODEX_MODELS;
|
|
7245
7523
|
}
|
|
7246
7524
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -7275,12 +7553,12 @@ function usageFromCodex(usage) {
|
|
|
7275
7553
|
}
|
|
7276
7554
|
function codexConfigHasNetworkAccess() {
|
|
7277
7555
|
const candidates = [
|
|
7278
|
-
(0,
|
|
7279
|
-
(0,
|
|
7556
|
+
(0, import_node_path21.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
|
|
7557
|
+
(0, import_node_path21.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
|
|
7280
7558
|
];
|
|
7281
7559
|
for (const path2 of candidates) {
|
|
7282
|
-
if (!(0,
|
|
7283
|
-
const text3 = (0,
|
|
7560
|
+
if (!(0, import_node_fs22.existsSync)(path2)) continue;
|
|
7561
|
+
const text3 = (0, import_node_fs22.readFileSync)(path2, "utf8");
|
|
7284
7562
|
if (/network_access\s*=\s*true/.test(text3)) return true;
|
|
7285
7563
|
}
|
|
7286
7564
|
return false;
|
|
@@ -7312,21 +7590,21 @@ function asRecord(value) {
|
|
|
7312
7590
|
return void 0;
|
|
7313
7591
|
}
|
|
7314
7592
|
function codexLooksAuthenticated() {
|
|
7315
|
-
const authPath = (0,
|
|
7316
|
-
if (!(0,
|
|
7593
|
+
const authPath = (0, import_node_path21.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
|
|
7594
|
+
if (!(0, import_node_fs22.existsSync)(authPath)) return false;
|
|
7317
7595
|
try {
|
|
7318
|
-
return (0,
|
|
7596
|
+
return (0, import_node_fs22.statSync)(authPath).size > 2;
|
|
7319
7597
|
} catch {
|
|
7320
7598
|
return false;
|
|
7321
7599
|
}
|
|
7322
7600
|
}
|
|
7323
|
-
var
|
|
7601
|
+
var import_node_fs22, import_node_os9, import_node_path21, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
7324
7602
|
var init_codex = __esm({
|
|
7325
7603
|
"src/agents/codex.ts"() {
|
|
7326
7604
|
"use strict";
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
|
|
7605
|
+
import_node_fs22 = require("fs");
|
|
7606
|
+
import_node_os9 = require("os");
|
|
7607
|
+
import_node_path21 = require("path");
|
|
7330
7608
|
init_run();
|
|
7331
7609
|
init_app_settings();
|
|
7332
7610
|
init_global_workspace();
|
|
@@ -7351,7 +7629,7 @@ var init_codex = __esm({
|
|
|
7351
7629
|
async detect() {
|
|
7352
7630
|
const codex = resolveAgentExecutable("codex");
|
|
7353
7631
|
if (codex !== "codex") {
|
|
7354
|
-
if (!(0,
|
|
7632
|
+
if (!(0, import_node_fs22.existsSync)(codex)) {
|
|
7355
7633
|
return {
|
|
7356
7634
|
agent: "codex",
|
|
7357
7635
|
installed: false,
|
|
@@ -7424,8 +7702,13 @@ var init_codex = __esm({
|
|
|
7424
7702
|
// `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
|
|
7425
7703
|
"-c",
|
|
7426
7704
|
'approval_policy="never"',
|
|
7427
|
-
// Seatbelt cannot use the login Keychain;
|
|
7428
|
-
|
|
7705
|
+
// Seatbelt cannot use the login Keychain; inherit GH_CONFIG_DIR / GIT_CONFIG_*.
|
|
7706
|
+
// Default policy also strips *TOKEN*. Linked worktrees need the main
|
|
7707
|
+
// repo `.git` (+ `.git/worktrees/<name>`) as writable_roots so git commit
|
|
7708
|
+
// can create index.lock.
|
|
7709
|
+
...codexUnattendedGitConfigArgs(mode.codexSandbox, {
|
|
7710
|
+
writableRoots: mode.codexSandbox === "workspace-write" ? await resolveCodexGitWritableRoots(thread.worktreePath) : []
|
|
7711
|
+
}),
|
|
7429
7712
|
...model ? ["--model", model] : [],
|
|
7430
7713
|
...mcpOverrides
|
|
7431
7714
|
];
|
|
@@ -7746,6 +8029,74 @@ var init_cursor_events = __esm({
|
|
|
7746
8029
|
}
|
|
7747
8030
|
});
|
|
7748
8031
|
|
|
8032
|
+
// src/agents/cursor-ripgrep.ts
|
|
8033
|
+
function rgBinaryName() {
|
|
8034
|
+
return process.platform === "win32" ? "rg.exe" : "rg";
|
|
8035
|
+
}
|
|
8036
|
+
function platformRipgrepPackage() {
|
|
8037
|
+
return `@cursor/sdk-${process.platform}-${process.arch}`;
|
|
8038
|
+
}
|
|
8039
|
+
function usableRipgrepPath(candidate) {
|
|
8040
|
+
const raw = candidate?.trim();
|
|
8041
|
+
if (!raw || !(0, import_node_path22.isAbsolute)(raw)) return null;
|
|
8042
|
+
const readable = nodeReadableScriptPath(raw);
|
|
8043
|
+
if (!(0, import_node_fs23.existsSync)(readable) || isAsarPath(readable)) return null;
|
|
8044
|
+
return readable;
|
|
8045
|
+
}
|
|
8046
|
+
function walkForBundledRipgrep(startFile) {
|
|
8047
|
+
if (!startFile) return null;
|
|
8048
|
+
const pkg = platformRipgrepPackage();
|
|
8049
|
+
const name = rgBinaryName();
|
|
8050
|
+
let dir = (0, import_node_path22.dirname)((0, import_node_path22.resolve)(startFile));
|
|
8051
|
+
const root = (0, import_node_path22.parse)(dir).root;
|
|
8052
|
+
while (dir !== root) {
|
|
8053
|
+
const hit = usableRipgrepPath((0, import_node_path22.join)(dir, "node_modules", pkg, "bin", name));
|
|
8054
|
+
if (hit) return hit;
|
|
8055
|
+
const next = (0, import_node_path22.dirname)(dir);
|
|
8056
|
+
if (next === dir) break;
|
|
8057
|
+
dir = next;
|
|
8058
|
+
}
|
|
8059
|
+
return null;
|
|
8060
|
+
}
|
|
8061
|
+
function requireResolveBundledRipgrep(fromFile) {
|
|
8062
|
+
try {
|
|
8063
|
+
const req = (0, import_node_module2.createRequire)(fromFile);
|
|
8064
|
+
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
8065
|
+
return usableRipgrepPath((0, import_node_path22.join)((0, import_node_path22.dirname)(pkgJson), "bin", rgBinaryName()));
|
|
8066
|
+
} catch {
|
|
8067
|
+
return null;
|
|
8068
|
+
}
|
|
8069
|
+
}
|
|
8070
|
+
function resolveCursorRipgrepPath(opts) {
|
|
8071
|
+
const env = opts?.env ?? process.env;
|
|
8072
|
+
const fromEnv = usableRipgrepPath(env[RIPGREP_ENV]);
|
|
8073
|
+
if (fromEnv) return fromEnv;
|
|
8074
|
+
const fromPackaged = usableRipgrepPath(
|
|
8075
|
+
packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
|
|
8076
|
+
);
|
|
8077
|
+
if (fromPackaged) return fromPackaged;
|
|
8078
|
+
const start = opts?.startFile?.trim() || process.argv[1] || (0, import_node_url2.fileURLToPath)(import_meta2.url);
|
|
8079
|
+
return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
|
|
8080
|
+
}
|
|
8081
|
+
function cursorRipgrepEnv(opts) {
|
|
8082
|
+
const path2 = resolveCursorRipgrepPath(opts);
|
|
8083
|
+
return path2 ? { [RIPGREP_ENV]: path2 } : {};
|
|
8084
|
+
}
|
|
8085
|
+
var import_node_fs23, import_node_module2, import_node_path22, import_node_url2, import_meta2, RIPGREP_ENV;
|
|
8086
|
+
var init_cursor_ripgrep = __esm({
|
|
8087
|
+
"src/agents/cursor-ripgrep.ts"() {
|
|
8088
|
+
"use strict";
|
|
8089
|
+
import_node_fs23 = require("fs");
|
|
8090
|
+
import_node_module2 = require("module");
|
|
8091
|
+
import_node_path22 = require("path");
|
|
8092
|
+
import_node_url2 = require("url");
|
|
8093
|
+
init_node_launch();
|
|
8094
|
+
init_packaged_runtime();
|
|
8095
|
+
import_meta2 = {};
|
|
8096
|
+
RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
8097
|
+
}
|
|
8098
|
+
});
|
|
8099
|
+
|
|
7749
8100
|
// src/agents/cursor.ts
|
|
7750
8101
|
function resolveCursorApiKey() {
|
|
7751
8102
|
const fromEnv = (process.env.CURSOR_API_KEY || "").trim();
|
|
@@ -7785,51 +8136,55 @@ function entryDir() {
|
|
|
7785
8136
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
7786
8137
|
if (cjsDir) return cjsDir;
|
|
7787
8138
|
try {
|
|
7788
|
-
return (0,
|
|
8139
|
+
return (0, import_node_path23.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
|
|
7789
8140
|
} catch {
|
|
7790
8141
|
try {
|
|
7791
|
-
const req = (0,
|
|
7792
|
-
return (0,
|
|
8142
|
+
const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
|
|
8143
|
+
return (0, import_node_path23.dirname)(req.resolve("@sideboard-ai/core"));
|
|
7793
8144
|
} catch {
|
|
7794
8145
|
return process.cwd();
|
|
7795
8146
|
}
|
|
7796
8147
|
}
|
|
7797
8148
|
}
|
|
7798
8149
|
function cursorRunnerPath() {
|
|
8150
|
+
const packaged = packagedCursorRunnerPath();
|
|
8151
|
+
if (packaged) return packaged;
|
|
7799
8152
|
const root = entryDir();
|
|
7800
8153
|
const candidates = [
|
|
7801
|
-
(0,
|
|
7802
|
-
(0,
|
|
8154
|
+
(0, import_node_path23.join)(root, "agents", "cursor-runner.js"),
|
|
8155
|
+
(0, import_node_path23.join)(root, "agents", "cursor-runner.cjs"),
|
|
7803
8156
|
// If somehow resolved from package root instead of dist/
|
|
7804
|
-
(0,
|
|
7805
|
-
(0,
|
|
8157
|
+
(0, import_node_path23.join)(root, "dist", "agents", "cursor-runner.js"),
|
|
8158
|
+
(0, import_node_path23.join)(root, "dist", "agents", "cursor-runner.cjs"),
|
|
7806
8159
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
7807
|
-
(0,
|
|
7808
|
-
(0,
|
|
8160
|
+
(0, import_node_path23.join)(root, "cursor-runner.ts"),
|
|
8161
|
+
(0, import_node_path23.join)(root, "src", "agents", "cursor-runner.ts")
|
|
7809
8162
|
];
|
|
7810
8163
|
for (const candidate of candidates) {
|
|
7811
|
-
if ((0,
|
|
8164
|
+
if ((0, import_node_fs24.existsSync)(candidate)) return candidate;
|
|
7812
8165
|
}
|
|
7813
8166
|
return candidates[0];
|
|
7814
8167
|
}
|
|
7815
|
-
var
|
|
8168
|
+
var import_node_fs24, import_node_module3, import_node_path23, import_node_url3, import_sdk, import_meta3, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
|
|
7816
8169
|
var init_cursor = __esm({
|
|
7817
8170
|
"src/agents/cursor.ts"() {
|
|
7818
8171
|
"use strict";
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
8172
|
+
import_node_fs24 = require("fs");
|
|
8173
|
+
import_node_module3 = require("module");
|
|
8174
|
+
import_node_path23 = require("path");
|
|
8175
|
+
import_node_url3 = require("url");
|
|
7823
8176
|
import_sdk = require("@cursor/sdk");
|
|
7824
8177
|
init_run();
|
|
7825
8178
|
init_app_settings();
|
|
7826
8179
|
init_global_workspace();
|
|
7827
8180
|
init_cursor_events();
|
|
7828
8181
|
init_injected_mcp();
|
|
8182
|
+
init_cursor_ripgrep();
|
|
7829
8183
|
init_node_launch();
|
|
8184
|
+
init_packaged_runtime();
|
|
7830
8185
|
init_turn_input();
|
|
7831
8186
|
init_cursor_events();
|
|
7832
|
-
|
|
8187
|
+
import_meta3 = {};
|
|
7833
8188
|
FALLBACK_CURSOR_MODELS = [
|
|
7834
8189
|
{ id: "default", displayName: "Auto" },
|
|
7835
8190
|
{ id: "composer-2.5", displayName: "Composer 2.5" },
|
|
@@ -7896,6 +8251,7 @@ var init_cursor = __esm({
|
|
|
7896
8251
|
stdin: JSON.stringify(req),
|
|
7897
8252
|
env: {
|
|
7898
8253
|
...launch.env,
|
|
8254
|
+
...cursorRipgrepEnv({ startFile: runner }),
|
|
7899
8255
|
...apiKey ? { CURSOR_API_KEY: apiKey } : {}
|
|
7900
8256
|
}
|
|
7901
8257
|
};
|
|
@@ -7947,7 +8303,7 @@ async function listOpencodeModels() {
|
|
|
7947
8303
|
if (opencode === "opencode") {
|
|
7948
8304
|
const which = await run("which", ["opencode"], { reject: false });
|
|
7949
8305
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
7950
|
-
} else if (!(0,
|
|
8306
|
+
} else if (!(0, import_node_fs25.existsSync)(opencode)) {
|
|
7951
8307
|
return FALLBACK_OPENCODE_MODELS;
|
|
7952
8308
|
}
|
|
7953
8309
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -7977,11 +8333,11 @@ function usageFromOpencode(tokens) {
|
|
|
7977
8333
|
cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
|
|
7978
8334
|
};
|
|
7979
8335
|
}
|
|
7980
|
-
var
|
|
8336
|
+
var import_node_fs25, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
|
|
7981
8337
|
var init_opencode = __esm({
|
|
7982
8338
|
"src/agents/opencode.ts"() {
|
|
7983
8339
|
"use strict";
|
|
7984
|
-
|
|
8340
|
+
import_node_fs25 = require("fs");
|
|
7985
8341
|
init_run();
|
|
7986
8342
|
init_app_settings();
|
|
7987
8343
|
init_global_workspace();
|
|
@@ -8007,7 +8363,7 @@ var init_opencode = __esm({
|
|
|
8007
8363
|
async detect() {
|
|
8008
8364
|
const opencode = resolveAgentExecutable("opencode");
|
|
8009
8365
|
if (opencode !== "opencode") {
|
|
8010
|
-
if (!(0,
|
|
8366
|
+
if (!(0, import_node_fs25.existsSync)(opencode)) {
|
|
8011
8367
|
return {
|
|
8012
8368
|
agent: "opencode",
|
|
8013
8369
|
installed: false,
|
|
@@ -8804,40 +9160,40 @@ __export(plan_file_exports, {
|
|
|
8804
9160
|
writePlanFile: () => writePlanFile
|
|
8805
9161
|
});
|
|
8806
9162
|
function ensureAttachmentsGitignore2(worktreePath) {
|
|
8807
|
-
const gitignoreAbs = (0,
|
|
8808
|
-
if ((0,
|
|
8809
|
-
(0,
|
|
8810
|
-
(0,
|
|
9163
|
+
const gitignoreAbs = (0, import_node_path36.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
9164
|
+
if ((0, import_node_fs39.existsSync)(gitignoreAbs)) return;
|
|
9165
|
+
(0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(gitignoreAbs), { recursive: true });
|
|
9166
|
+
(0, import_node_fs39.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
8811
9167
|
}
|
|
8812
9168
|
function planFileAbs(worktreePath) {
|
|
8813
|
-
return (0,
|
|
9169
|
+
return (0, import_node_path36.join)(worktreePath, PLAN_FILE_REL);
|
|
8814
9170
|
}
|
|
8815
9171
|
function readTextIfPresent2(abs) {
|
|
8816
|
-
if (!(0,
|
|
9172
|
+
if (!(0, import_node_fs39.existsSync)(abs)) return null;
|
|
8817
9173
|
try {
|
|
8818
|
-
const content = (0,
|
|
9174
|
+
const content = (0, import_node_fs39.readFileSync)(abs, "utf8");
|
|
8819
9175
|
return content.trim() ? content : null;
|
|
8820
9176
|
} catch {
|
|
8821
9177
|
return null;
|
|
8822
9178
|
}
|
|
8823
9179
|
}
|
|
8824
9180
|
function readPlanFile(worktreePath) {
|
|
8825
|
-
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0,
|
|
9181
|
+
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path36.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path36.join)(worktreePath, LEGACY_PLAN_FILE_REL));
|
|
8826
9182
|
}
|
|
8827
9183
|
function writePlanFile(worktreePath, content) {
|
|
8828
9184
|
ensureAttachmentsGitignore2(worktreePath);
|
|
8829
9185
|
const abs = planFileAbs(worktreePath);
|
|
8830
|
-
(0,
|
|
9186
|
+
(0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(abs), { recursive: true });
|
|
8831
9187
|
const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
|
|
8832
|
-
(0,
|
|
9188
|
+
(0, import_node_fs39.writeFileSync)(abs, body, "utf8");
|
|
8833
9189
|
return PLAN_FILE_REL;
|
|
8834
9190
|
}
|
|
8835
|
-
var
|
|
9191
|
+
var import_node_fs39, import_node_path36;
|
|
8836
9192
|
var init_plan_file = __esm({
|
|
8837
9193
|
"src/plan/plan-file.ts"() {
|
|
8838
9194
|
"use strict";
|
|
8839
|
-
|
|
8840
|
-
|
|
9195
|
+
import_node_fs39 = require("fs");
|
|
9196
|
+
import_node_path36 = require("path");
|
|
8841
9197
|
init_workspace_scratch();
|
|
8842
9198
|
init_plan_present();
|
|
8843
9199
|
init_plan_present();
|
|
@@ -8852,10 +9208,10 @@ __export(cursor_recover_exports, {
|
|
|
8852
9208
|
function recoverFinishedCursorRun(opts) {
|
|
8853
9209
|
const agentId = opts.agentId.trim();
|
|
8854
9210
|
if (!agentId) return null;
|
|
8855
|
-
const runsPath = (0,
|
|
8856
|
-
if (!(0,
|
|
9211
|
+
const runsPath = (0, import_node_path37.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
|
|
9212
|
+
if (!(0, import_node_fs40.existsSync)(runsPath)) return null;
|
|
8857
9213
|
try {
|
|
8858
|
-
const lines = (0,
|
|
9214
|
+
const lines = (0, import_node_fs40.readFileSync)(runsPath, "utf8").split("\n");
|
|
8859
9215
|
let best = null;
|
|
8860
9216
|
for (const line of lines) {
|
|
8861
9217
|
const trimmed = line.trim();
|
|
@@ -8881,12 +9237,12 @@ function recoverFinishedCursorRun(opts) {
|
|
|
8881
9237
|
return null;
|
|
8882
9238
|
}
|
|
8883
9239
|
}
|
|
8884
|
-
var
|
|
9240
|
+
var import_node_fs40, import_node_path37;
|
|
8885
9241
|
var init_cursor_recover = __esm({
|
|
8886
9242
|
"src/agents/cursor-recover.ts"() {
|
|
8887
9243
|
"use strict";
|
|
8888
|
-
|
|
8889
|
-
|
|
9244
|
+
import_node_fs40 = require("fs");
|
|
9245
|
+
import_node_path37 = require("path");
|
|
8890
9246
|
init_paths();
|
|
8891
9247
|
}
|
|
8892
9248
|
});
|
|
@@ -8970,7 +9326,6 @@ __export(index_exports, {
|
|
|
8970
9326
|
SIDEBOARD_FORCE_STOP: () => SIDEBOARD_FORCE_STOP,
|
|
8971
9327
|
SIDEBOARD_MCP_ALLOWED_TOOLS: () => SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
8972
9328
|
SIDEBOARD_MCP_PROFILE_ENV: () => SIDEBOARD_MCP_PROFILE_ENV,
|
|
8973
|
-
SLACK_LISTEN_BUSY_REPLY: () => SLACK_LISTEN_BUSY_REPLY,
|
|
8974
9329
|
SLACK_LISTEN_STOPPED_REPLY: () => SLACK_LISTEN_STOPPED_REPLY,
|
|
8975
9330
|
SLACK_LISTEN_TIMEOUT_REPLY: () => SLACK_LISTEN_TIMEOUT_REPLY,
|
|
8976
9331
|
SLACK_OAUTH_CANCELLED: () => SLACK_OAUTH_CANCELLED,
|
|
@@ -9040,6 +9395,7 @@ __export(index_exports, {
|
|
|
9040
9395
|
cleanupOrphanWorktrees: () => cleanupOrphanWorktrees,
|
|
9041
9396
|
cloneRepoIntoSideboard: () => cloneRepoIntoSideboard,
|
|
9042
9397
|
codexAdapter: () => codexAdapter,
|
|
9398
|
+
codexSandboxWritableRootsArgs: () => codexSandboxWritableRootsArgs,
|
|
9043
9399
|
codexUnattendedGitConfigArgs: () => codexUnattendedGitConfigArgs,
|
|
9044
9400
|
coerceOrchestratorAgent: () => coerceOrchestratorAgent,
|
|
9045
9401
|
collectTakenTeamSlugs: () => collectTakenTeamSlugs,
|
|
@@ -9156,6 +9512,7 @@ __export(index_exports, {
|
|
|
9156
9512
|
getPr: () => getPr,
|
|
9157
9513
|
getPrChecks: () => getPrChecks,
|
|
9158
9514
|
getPrDetails: () => getPrDetails,
|
|
9515
|
+
getPrForHeadBranch: () => getPrForHeadBranch,
|
|
9159
9516
|
getPrMeta: () => getPrMeta,
|
|
9160
9517
|
getPrStack: () => getPrStack,
|
|
9161
9518
|
getRepoSetupInfo: () => getRepoSetupInfo,
|
|
@@ -9186,12 +9543,14 @@ __export(index_exports, {
|
|
|
9186
9543
|
initializeGitRepository: () => initializeGitRepository,
|
|
9187
9544
|
inspectGitWorktree: () => inspectGitWorktree,
|
|
9188
9545
|
installAgent: () => installAgent,
|
|
9546
|
+
interruptSlackCoordinatorForInbound: () => interruptSlackCoordinatorForInbound,
|
|
9189
9547
|
isAskUserToolName: () => isAskUserToolName,
|
|
9190
9548
|
isBrightsyConnected: () => isBrightsyConnected,
|
|
9191
9549
|
isBrightsyNdjsonLine: () => isBrightsyNdjsonLine,
|
|
9192
9550
|
isCloudCoordinatorThread: () => isCloudCoordinatorThread,
|
|
9193
9551
|
isConductorBundledCli: () => isConductorBundledCli,
|
|
9194
9552
|
isCursorAutoModel: () => isCursorAutoModel,
|
|
9553
|
+
isDefaultishSourceRef: () => isDefaultishSourceRef,
|
|
9195
9554
|
isDirty: () => isDirty,
|
|
9196
9555
|
isGhRateLimitError: () => isGhRateLimitError,
|
|
9197
9556
|
isGlobalRepoPath: () => isGlobalRepoPath,
|
|
@@ -9258,8 +9617,10 @@ __export(index_exports, {
|
|
|
9258
9617
|
maybeCompactContext: () => maybeCompactContext,
|
|
9259
9618
|
mcpAllowTools: () => mcpAllowTools,
|
|
9260
9619
|
mcpAuthWarnings: () => mcpAuthWarnings,
|
|
9620
|
+
mergeAgentGitAuthEnv: () => mergeAgentGitAuthEnv,
|
|
9261
9621
|
mergePr: () => mergePr,
|
|
9262
9622
|
mergePrStack: () => mergePrStack,
|
|
9623
|
+
mergeSideboardIntoMcpServersJson: () => mergeSideboardIntoMcpServersJson,
|
|
9263
9624
|
mergeUsage: () => mergeUsage,
|
|
9264
9625
|
nextPastedTextName: () => nextPastedTextName,
|
|
9265
9626
|
nextThinkingEffort: () => nextThinkingEffort,
|
|
@@ -9310,6 +9671,7 @@ __export(index_exports, {
|
|
|
9310
9671
|
recordSlackOutboundWatch: () => recordSlackOutboundWatch,
|
|
9311
9672
|
refreshGitHubAuth: () => refreshGitHubAuth,
|
|
9312
9673
|
refreshSlackReplyBadges: () => refreshSlackReplyBadges,
|
|
9674
|
+
registerPackagedUserMcpClients: () => registerPackagedUserMcpClients,
|
|
9313
9675
|
releaseCaffeinateHoldForThread: () => releaseCaffeinateHoldForThread,
|
|
9314
9676
|
removeWorkspace: () => removeWorkspace,
|
|
9315
9677
|
removeWorktree: () => removeWorktree,
|
|
@@ -9318,9 +9680,11 @@ __export(index_exports, {
|
|
|
9318
9680
|
requestReview: () => requestReview,
|
|
9319
9681
|
requireAgent: () => requireAgent,
|
|
9320
9682
|
resetGhStackDetectCache: () => resetGhStackDetectCache,
|
|
9683
|
+
resetGithubAgentTokenMemo: () => resetGithubAgentTokenMemo,
|
|
9321
9684
|
resolveAgentExecutable: () => resolveAgentExecutable,
|
|
9322
9685
|
resolveAgentGitAuthEnv: () => resolveAgentGitAuthEnv,
|
|
9323
9686
|
resolveClaudeExecutable: () => resolveClaudeExecutable,
|
|
9687
|
+
resolveCodexGitWritableRoots: () => resolveCodexGitWritableRoots,
|
|
9324
9688
|
resolveCommandBinarySync: () => resolveCommandBinarySync,
|
|
9325
9689
|
resolveConductorCursorAgentId: () => resolveConductorCursorAgentId,
|
|
9326
9690
|
resolveCursorModelId: () => resolveCursorModelId,
|
|
@@ -9337,6 +9701,7 @@ __export(index_exports, {
|
|
|
9337
9701
|
resolveNewThreadOptions: () => resolveNewThreadOptions,
|
|
9338
9702
|
resolvePlanMarkdown: () => resolvePlanMarkdown,
|
|
9339
9703
|
resolvePrSelector: () => resolvePrSelector,
|
|
9704
|
+
resolvePrSelectors: () => resolvePrSelectors,
|
|
9340
9705
|
resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
|
|
9341
9706
|
resolveRepoRoot: () => resolveRepoRoot,
|
|
9342
9707
|
resolveReviewGuidelines: () => resolveReviewGuidelines,
|
|
@@ -9359,6 +9724,7 @@ __export(index_exports, {
|
|
|
9359
9724
|
sanitizeMcpServerName: () => sanitizeMcpServerName,
|
|
9360
9725
|
saveAppSettings: () => saveAppSettings,
|
|
9361
9726
|
saveLinearOAuth: () => saveLinearOAuth,
|
|
9727
|
+
scrubGithubTokensFromChildEnv: () => scrubGithubTokensFromChildEnv,
|
|
9362
9728
|
secureFileUnlocksWith: () => secureFileUnlocksWith,
|
|
9363
9729
|
setCaffeinateHold: () => setCaffeinateHold,
|
|
9364
9730
|
setHttpFetchImpl: () => setHttpFetchImpl,
|
|
@@ -9429,7 +9795,10 @@ __export(index_exports, {
|
|
|
9429
9795
|
updateLinearIssue: () => updateLinearIssue,
|
|
9430
9796
|
updateOpencodeSettings: () => updateOpencodeSettings,
|
|
9431
9797
|
updateThread: () => updateThread,
|
|
9798
|
+
userClaudeMcpConfigPath: () => userClaudeMcpConfigPath,
|
|
9799
|
+
userCursorMcpConfigPath: () => userCursorMcpConfigPath,
|
|
9432
9800
|
validateLinearApiKey: () => validateLinearApiKey,
|
|
9801
|
+
warmGithubAgentAuth: () => warmGithubAgentAuth,
|
|
9433
9802
|
withAgentInstructions: () => withAgentInstructions,
|
|
9434
9803
|
withExportedPath: () => withExportedPath,
|
|
9435
9804
|
withThreadLock: () => withThreadLock,
|
|
@@ -10513,10 +10882,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
10513
10882
|
const env = childEnvWithAppSettings(cmd.env);
|
|
10514
10883
|
try {
|
|
10515
10884
|
if (isOrchestratorThread(thread)) {
|
|
10516
|
-
|
|
10885
|
+
mergeAgentGitAuthEnv(env, await resolveAgentGitAuthEnv(env));
|
|
10517
10886
|
} else {
|
|
10518
|
-
|
|
10519
|
-
Object.assign(env, originEnv);
|
|
10887
|
+
mergeAgentGitAuthEnv(env, await originGhRepoEnv(thread.worktreePath, { env }));
|
|
10520
10888
|
}
|
|
10521
10889
|
} catch (err) {
|
|
10522
10890
|
const detail = err instanceof Error ? err.message : String(err);
|
|
@@ -10611,8 +10979,8 @@ init_usage();
|
|
|
10611
10979
|
init_claude_mcp();
|
|
10612
10980
|
|
|
10613
10981
|
// src/agents/instructions.ts
|
|
10614
|
-
var
|
|
10615
|
-
var
|
|
10982
|
+
var import_node_fs26 = require("fs");
|
|
10983
|
+
var import_node_path24 = require("path");
|
|
10616
10984
|
init_git_auth_mode();
|
|
10617
10985
|
init_worktree_labels();
|
|
10618
10986
|
function normPath3(p) {
|
|
@@ -10745,9 +11113,10 @@ function formatArtifactDirective() {
|
|
|
10745
11113
|
"Files / media browser (CMS file manager column):",
|
|
10746
11114
|
"4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
|
|
10747
11115
|
" Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
|
|
10748
|
-
"Multiple-choice questions
|
|
10749
|
-
"5) Call Sideboard MCP `ask_user` when
|
|
10750
|
-
"
|
|
11116
|
+
"Multiple-choice questions:",
|
|
11117
|
+
"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.",
|
|
11118
|
+
"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.",
|
|
11119
|
+
"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."
|
|
10751
11120
|
].join("\n");
|
|
10752
11121
|
}
|
|
10753
11122
|
function formatUiReminder() {
|
|
@@ -10758,7 +11127,7 @@ function formatUiReminder() {
|
|
|
10758
11127
|
"CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
|
|
10759
11128
|
"Files column: MCP present_files (brightsy account storage or memory).",
|
|
10760
11129
|
"Do not say artifacts/CMS UI are unavailable.",
|
|
10761
|
-
"
|
|
11130
|
+
"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."
|
|
10762
11131
|
].join(" ");
|
|
10763
11132
|
}
|
|
10764
11133
|
var FILES_BY_AGENT = {
|
|
@@ -10782,11 +11151,11 @@ function loadAgentInstructions(worktreePath, agent) {
|
|
|
10782
11151
|
const out = [];
|
|
10783
11152
|
for (const rel of candidates) {
|
|
10784
11153
|
if (seenPaths.has(rel)) continue;
|
|
10785
|
-
const abs = (0,
|
|
10786
|
-
if (!(0,
|
|
11154
|
+
const abs = (0, import_node_path24.join)(worktreePath, rel);
|
|
11155
|
+
if (!(0, import_node_fs26.existsSync)(abs)) continue;
|
|
10787
11156
|
try {
|
|
10788
|
-
if (!(0,
|
|
10789
|
-
let content = (0,
|
|
11157
|
+
if (!(0, import_node_fs26.statSync)(abs).isFile()) continue;
|
|
11158
|
+
let content = (0, import_node_fs26.readFileSync)(abs, "utf8");
|
|
10790
11159
|
if (!content.trim()) continue;
|
|
10791
11160
|
if (content.length > MAX_CHARS_PER_FILE) {
|
|
10792
11161
|
content = `${content.slice(0, MAX_CHARS_PER_FILE)}
|
|
@@ -10868,9 +11237,9 @@ async function requireAgent(agent, opts) {
|
|
|
10868
11237
|
init_settings();
|
|
10869
11238
|
|
|
10870
11239
|
// src/hook/conductor.ts
|
|
10871
|
-
var
|
|
11240
|
+
var import_node_fs27 = require("fs");
|
|
10872
11241
|
var import_node_net = require("net");
|
|
10873
|
-
var
|
|
11242
|
+
var import_node_path25 = require("path");
|
|
10874
11243
|
var import_execa4 = require("execa");
|
|
10875
11244
|
var import_node_readline3 = require("readline");
|
|
10876
11245
|
init_settings();
|
|
@@ -10885,9 +11254,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
10885
11254
|
return new RegExp(`^${escaped}$`).test(name);
|
|
10886
11255
|
}
|
|
10887
11256
|
function readWorktreeInclude(repoPath) {
|
|
10888
|
-
const path2 = (0,
|
|
10889
|
-
if (!(0,
|
|
10890
|
-
return (0,
|
|
11257
|
+
const path2 = (0, import_node_path25.join)(repoPath, ".worktreeinclude");
|
|
11258
|
+
if (!(0, import_node_fs27.existsSync)(path2)) return [];
|
|
11259
|
+
return (0, import_node_fs27.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
10891
11260
|
}
|
|
10892
11261
|
function resolveFilesToCopy(repoPath) {
|
|
10893
11262
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -10897,10 +11266,10 @@ function resolveFilesToCopy(repoPath) {
|
|
|
10897
11266
|
if (settings?.fileIncludeGlobs?.length) {
|
|
10898
11267
|
const matched = [];
|
|
10899
11268
|
try {
|
|
10900
|
-
for (const entry of (0,
|
|
11269
|
+
for (const entry of (0, import_node_fs27.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
10901
11270
|
if (!entry.isFile()) continue;
|
|
10902
11271
|
for (const glob of settings.fileIncludeGlobs) {
|
|
10903
|
-
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0,
|
|
11272
|
+
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path25.basename)(glob), entry.name)) {
|
|
10904
11273
|
matched.push(entry.name);
|
|
10905
11274
|
break;
|
|
10906
11275
|
}
|
|
@@ -10912,7 +11281,7 @@ function resolveFilesToCopy(repoPath) {
|
|
|
10912
11281
|
}
|
|
10913
11282
|
const defaults = [];
|
|
10914
11283
|
try {
|
|
10915
|
-
for (const entry of (0,
|
|
11284
|
+
for (const entry of (0, import_node_fs27.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
10916
11285
|
if (entry.isFile() && entry.name.startsWith(".env")) {
|
|
10917
11286
|
defaults.push(entry.name);
|
|
10918
11287
|
}
|
|
@@ -10926,11 +11295,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
|
|
|
10926
11295
|
const patterns = resolveFilesToCopy(repoPath);
|
|
10927
11296
|
const copied = [];
|
|
10928
11297
|
for (const rel of patterns) {
|
|
10929
|
-
const src = (0,
|
|
10930
|
-
if (!(0,
|
|
10931
|
-
const dest = (0,
|
|
10932
|
-
(0,
|
|
10933
|
-
(0,
|
|
11298
|
+
const src = (0, import_node_path25.join)(repoPath, rel);
|
|
11299
|
+
if (!(0, import_node_fs27.existsSync)(src)) continue;
|
|
11300
|
+
const dest = (0, import_node_path25.join)(worktreePath, rel);
|
|
11301
|
+
(0, import_node_fs27.mkdirSync)((0, import_node_path25.dirname)(dest), { recursive: true });
|
|
11302
|
+
(0, import_node_fs27.copyFileSync)(src, dest);
|
|
10934
11303
|
copied.push(rel);
|
|
10935
11304
|
}
|
|
10936
11305
|
return copied;
|
|
@@ -10966,7 +11335,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
|
10966
11335
|
const env = stripNestedElectronEnv({
|
|
10967
11336
|
...baseEnv ?? process.env
|
|
10968
11337
|
});
|
|
10969
|
-
const name = opts.workspaceName ?? (0,
|
|
11338
|
+
const name = opts.workspaceName ?? (0, import_node_path25.basename)(opts.worktreePath);
|
|
10970
11339
|
const ports = opts.ports ?? [];
|
|
10971
11340
|
const primary = ports[0];
|
|
10972
11341
|
env.SIDEBOARD_WORKSPACE_NAME = name;
|
|
@@ -11052,7 +11421,10 @@ async function spawnWorkspaceScript(command, opts) {
|
|
|
11052
11421
|
loginEnv
|
|
11053
11422
|
);
|
|
11054
11423
|
try {
|
|
11055
|
-
|
|
11424
|
+
mergeAgentGitAuthEnv(
|
|
11425
|
+
env,
|
|
11426
|
+
await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath })
|
|
11427
|
+
);
|
|
11056
11428
|
} catch {
|
|
11057
11429
|
}
|
|
11058
11430
|
const shell = process.platform === "darwin" ? "zsh" : "bash";
|
|
@@ -11224,12 +11596,12 @@ init_convention_setup();
|
|
|
11224
11596
|
init_cursor_worktrees();
|
|
11225
11597
|
|
|
11226
11598
|
// src/diff/diff.ts
|
|
11227
|
-
var
|
|
11228
|
-
var
|
|
11599
|
+
var import_node_fs28 = require("fs");
|
|
11600
|
+
var import_node_path26 = require("path");
|
|
11229
11601
|
init_run();
|
|
11230
11602
|
init_worktree();
|
|
11231
11603
|
async function inspectGitWorktree(worktreePath) {
|
|
11232
|
-
if (!worktreePath || !(0,
|
|
11604
|
+
if (!worktreePath || !(0, import_node_fs28.existsSync)(worktreePath)) return "missing_worktree";
|
|
11233
11605
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
11234
11606
|
reject: false
|
|
11235
11607
|
});
|
|
@@ -11237,7 +11609,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
11237
11609
|
return "ok";
|
|
11238
11610
|
}
|
|
11239
11611
|
async function initializeGitRepository(worktreePath) {
|
|
11240
|
-
if (!worktreePath || !(0,
|
|
11612
|
+
if (!worktreePath || !(0, import_node_fs28.existsSync)(worktreePath)) {
|
|
11241
11613
|
throw new Error("Worktree not found");
|
|
11242
11614
|
}
|
|
11243
11615
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -11372,11 +11744,11 @@ new file mode 100644
|
|
|
11372
11744
|
};
|
|
11373
11745
|
}
|
|
11374
11746
|
async function untrackedPatch(worktreePath, path2, maxHunk) {
|
|
11375
|
-
const abs = (0,
|
|
11747
|
+
const abs = (0, import_node_path26.join)(worktreePath, path2);
|
|
11376
11748
|
try {
|
|
11377
|
-
const st = (0,
|
|
11749
|
+
const st = (0, import_node_fs28.statSync)(abs);
|
|
11378
11750
|
if (st.isFile() && st.size > maxHunk) {
|
|
11379
|
-
const buf = (0,
|
|
11751
|
+
const buf = (0, import_node_fs28.readFileSync)(abs).subarray(0, maxHunk);
|
|
11380
11752
|
return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
|
|
11381
11753
|
}
|
|
11382
11754
|
} catch {
|
|
@@ -11877,8 +12249,8 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
11877
12249
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
11878
12250
|
assertSafeRelativePath(relativePath);
|
|
11879
12251
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
11880
|
-
const abs = (0,
|
|
11881
|
-
const st = (0,
|
|
12252
|
+
const abs = (0, import_node_path26.join)(worktreePath, relativePath);
|
|
12253
|
+
const st = (0, import_node_fs28.statSync)(abs);
|
|
11882
12254
|
if (!st.isFile()) {
|
|
11883
12255
|
throw new Error(`Not a file: ${relativePath}`);
|
|
11884
12256
|
}
|
|
@@ -11887,7 +12259,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
11887
12259
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
11888
12260
|
);
|
|
11889
12261
|
}
|
|
11890
|
-
const buf = (0,
|
|
12262
|
+
const buf = (0, import_node_fs28.readFileSync)(abs);
|
|
11891
12263
|
return {
|
|
11892
12264
|
path: relativePath,
|
|
11893
12265
|
contentBase64: buf.toString("base64"),
|
|
@@ -11897,12 +12269,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
11897
12269
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
11898
12270
|
assertSafeRelativePath(relativePath);
|
|
11899
12271
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
11900
|
-
const abs = (0,
|
|
11901
|
-
const st = (0,
|
|
12272
|
+
const abs = (0, import_node_path26.join)(worktreePath, relativePath);
|
|
12273
|
+
const st = (0, import_node_fs28.statSync)(abs);
|
|
11902
12274
|
if (!st.isFile()) {
|
|
11903
12275
|
throw new Error(`Not a file: ${relativePath}`);
|
|
11904
12276
|
}
|
|
11905
|
-
const buf = (0,
|
|
12277
|
+
const buf = (0, import_node_fs28.readFileSync)(abs);
|
|
11906
12278
|
if (isImageRelativePath(relativePath)) {
|
|
11907
12279
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
11908
12280
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -11945,9 +12317,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
11945
12317
|
}
|
|
11946
12318
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
11947
12319
|
assertSafeRelativePath(relativePath);
|
|
11948
|
-
const abs = (0,
|
|
11949
|
-
(0,
|
|
11950
|
-
(0,
|
|
12320
|
+
const abs = (0, import_node_path26.join)(worktreePath, relativePath);
|
|
12321
|
+
(0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(abs), { recursive: true });
|
|
12322
|
+
(0, import_node_fs28.writeFileSync)(abs, content, "utf8");
|
|
11951
12323
|
return { path: relativePath };
|
|
11952
12324
|
}
|
|
11953
12325
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -11966,9 +12338,9 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
11966
12338
|
}
|
|
11967
12339
|
|
|
11968
12340
|
// src/skills/discover.ts
|
|
11969
|
-
var
|
|
11970
|
-
var
|
|
11971
|
-
var
|
|
12341
|
+
var import_node_fs29 = require("fs");
|
|
12342
|
+
var import_node_os10 = require("os");
|
|
12343
|
+
var import_node_path27 = require("path");
|
|
11972
12344
|
function toCommand(name) {
|
|
11973
12345
|
return name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
11974
12346
|
}
|
|
@@ -12000,7 +12372,7 @@ function parseFrontmatter(content) {
|
|
|
12000
12372
|
}
|
|
12001
12373
|
function readSkill(skillMd, source) {
|
|
12002
12374
|
try {
|
|
12003
|
-
const content = (0,
|
|
12375
|
+
const content = (0, import_node_fs29.readFileSync)(skillMd, "utf8");
|
|
12004
12376
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
12005
12377
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
12006
12378
|
const name = fmName || dirName;
|
|
@@ -12019,19 +12391,19 @@ function readSkill(skillMd, source) {
|
|
|
12019
12391
|
}
|
|
12020
12392
|
}
|
|
12021
12393
|
function scanSkillsDir(dir, source, out) {
|
|
12022
|
-
if (!(0,
|
|
12394
|
+
if (!(0, import_node_fs29.existsSync)(dir)) return;
|
|
12023
12395
|
let entries;
|
|
12024
12396
|
try {
|
|
12025
|
-
entries = (0,
|
|
12397
|
+
entries = (0, import_node_fs29.readdirSync)(dir);
|
|
12026
12398
|
} catch {
|
|
12027
12399
|
return;
|
|
12028
12400
|
}
|
|
12029
12401
|
for (const entry of entries) {
|
|
12030
12402
|
if (entry.startsWith(".")) continue;
|
|
12031
|
-
const skillMd = (0,
|
|
12032
|
-
if (!(0,
|
|
12403
|
+
const skillMd = (0, import_node_path27.join)(dir, entry, "SKILL.md");
|
|
12404
|
+
if (!(0, import_node_fs29.existsSync)(skillMd)) continue;
|
|
12033
12405
|
try {
|
|
12034
|
-
if (!(0,
|
|
12406
|
+
if (!(0, import_node_fs29.statSync)(skillMd).isFile()) continue;
|
|
12035
12407
|
} catch {
|
|
12036
12408
|
continue;
|
|
12037
12409
|
}
|
|
@@ -12040,24 +12412,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
12040
12412
|
}
|
|
12041
12413
|
}
|
|
12042
12414
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
12043
|
-
if (!(0,
|
|
12415
|
+
if (!(0, import_node_fs29.existsSync)(pluginsRoot)) return;
|
|
12044
12416
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
12045
12417
|
if (depth > 7) return;
|
|
12046
12418
|
let entries;
|
|
12047
12419
|
try {
|
|
12048
|
-
entries = (0,
|
|
12420
|
+
entries = (0, import_node_fs29.readdirSync)(dir);
|
|
12049
12421
|
} catch {
|
|
12050
12422
|
return;
|
|
12051
12423
|
}
|
|
12052
12424
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
12053
|
-
const skill = readSkill((0,
|
|
12425
|
+
const skill = readSkill((0, import_node_path27.join)(dir, "SKILL.md"), "cli");
|
|
12054
12426
|
if (skill) out.push(skill);
|
|
12055
12427
|
}
|
|
12056
12428
|
for (const entry of entries) {
|
|
12057
12429
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
12058
|
-
const full = (0,
|
|
12430
|
+
const full = (0, import_node_path27.join)(dir, entry);
|
|
12059
12431
|
try {
|
|
12060
|
-
if (!(0,
|
|
12432
|
+
if (!(0, import_node_fs29.statSync)(full).isDirectory()) continue;
|
|
12061
12433
|
} catch {
|
|
12062
12434
|
continue;
|
|
12063
12435
|
}
|
|
@@ -12072,20 +12444,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
12072
12444
|
walk(pluginsRoot, 0, false);
|
|
12073
12445
|
}
|
|
12074
12446
|
function discoverSkills(worktreePath) {
|
|
12075
|
-
const home = (0,
|
|
12447
|
+
const home = (0, import_node_os10.homedir)();
|
|
12076
12448
|
const collected = [];
|
|
12077
12449
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
12078
|
-
scanSkillsDir((0,
|
|
12450
|
+
scanSkillsDir((0, import_node_path27.join)(worktreePath, rel), "workspace", collected);
|
|
12079
12451
|
}
|
|
12080
12452
|
for (const abs of [
|
|
12081
|
-
(0,
|
|
12082
|
-
(0,
|
|
12083
|
-
(0,
|
|
12084
|
-
(0,
|
|
12453
|
+
(0, import_node_path27.join)(home, ".claude/skills"),
|
|
12454
|
+
(0, import_node_path27.join)(home, ".cursor/skills"),
|
|
12455
|
+
(0, import_node_path27.join)(home, ".sideboard/skills"),
|
|
12456
|
+
(0, import_node_path27.join)(home, ".brightsy/skills")
|
|
12085
12457
|
]) {
|
|
12086
12458
|
scanSkillsDir(abs, "user", collected);
|
|
12087
12459
|
}
|
|
12088
|
-
scanClaudePluginSkills((0,
|
|
12460
|
+
scanClaudePluginSkills((0, import_node_path27.join)(home, ".claude/plugins"), collected);
|
|
12089
12461
|
const rank = { workspace: 0, user: 1, cli: 2 };
|
|
12090
12462
|
const byCommand = /* @__PURE__ */ new Map();
|
|
12091
12463
|
for (const skill of collected) {
|
|
@@ -12097,7 +12469,7 @@ function discoverSkills(worktreePath) {
|
|
|
12097
12469
|
return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
|
|
12098
12470
|
}
|
|
12099
12471
|
function readSkillBody(skillPath, maxChars = 12e3) {
|
|
12100
|
-
const raw = (0,
|
|
12472
|
+
const raw = (0, import_node_fs29.readFileSync)(skillPath, "utf8");
|
|
12101
12473
|
if (raw.startsWith("---")) {
|
|
12102
12474
|
const end = raw.indexOf("\n---", 3);
|
|
12103
12475
|
if (end >= 0) {
|
|
@@ -12238,8 +12610,8 @@ function buildDiffCommentAttachment(input) {
|
|
|
12238
12610
|
}
|
|
12239
12611
|
|
|
12240
12612
|
// src/composer/stage-files.ts
|
|
12241
|
-
var
|
|
12242
|
-
var
|
|
12613
|
+
var import_node_fs30 = require("fs");
|
|
12614
|
+
var import_node_path28 = require("path");
|
|
12243
12615
|
var import_node_crypto5 = require("crypto");
|
|
12244
12616
|
init_workspace_scratch();
|
|
12245
12617
|
var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
@@ -12265,7 +12637,7 @@ var IMAGE_MIME_BY_EXT = {
|
|
|
12265
12637
|
var MAX_INLINE_BYTES = 4e5;
|
|
12266
12638
|
var MAX_PREVIEW_BYTES = 5e6;
|
|
12267
12639
|
function fileExtension(filePath) {
|
|
12268
|
-
const base = (0,
|
|
12640
|
+
const base = (0, import_node_path28.basename)(filePath).toLowerCase();
|
|
12269
12641
|
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
12270
12642
|
}
|
|
12271
12643
|
function isImageFilePath(filePath) {
|
|
@@ -12275,22 +12647,22 @@ function imageMimeType(filePath) {
|
|
|
12275
12647
|
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
12276
12648
|
}
|
|
12277
12649
|
function ensureAttachmentsDir(worktreePath) {
|
|
12278
|
-
const dir = (0,
|
|
12279
|
-
(0,
|
|
12280
|
-
const gi = (0,
|
|
12281
|
-
if (!(0,
|
|
12282
|
-
(0,
|
|
12650
|
+
const dir = (0, import_node_path28.join)(worktreePath, ATTACHMENTS_DIR);
|
|
12651
|
+
(0, import_node_fs30.mkdirSync)(dir, { recursive: true });
|
|
12652
|
+
const gi = (0, import_node_path28.join)(dir, ".gitignore");
|
|
12653
|
+
if (!(0, import_node_fs30.existsSync)(gi)) {
|
|
12654
|
+
(0, import_node_fs30.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
12283
12655
|
}
|
|
12284
12656
|
return dir;
|
|
12285
12657
|
}
|
|
12286
12658
|
function uniqueAttachmentName(dir, originalName) {
|
|
12287
12659
|
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
12288
|
-
if (!(0,
|
|
12289
|
-
const ext = (0,
|
|
12660
|
+
if (!(0, import_node_fs30.existsSync)((0, import_node_path28.join)(dir, safe))) return safe;
|
|
12661
|
+
const ext = (0, import_node_path28.extname)(safe);
|
|
12290
12662
|
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
12291
12663
|
for (let i = 1; i < 1e4; i++) {
|
|
12292
12664
|
const candidate = `${stem}-${i}${ext}`;
|
|
12293
|
-
if (!(0,
|
|
12665
|
+
if (!(0, import_node_fs30.existsSync)((0, import_node_path28.join)(dir, candidate))) return candidate;
|
|
12294
12666
|
}
|
|
12295
12667
|
return `${stem}-${(0, import_node_crypto5.randomUUID)()}${ext}`;
|
|
12296
12668
|
}
|
|
@@ -12342,9 +12714,9 @@ function attachmentFromBuffer(name, buf, opts) {
|
|
|
12342
12714
|
};
|
|
12343
12715
|
}
|
|
12344
12716
|
function attachmentFromAbsolutePath(absolutePath) {
|
|
12345
|
-
const name = (0,
|
|
12717
|
+
const name = (0, import_node_path28.basename)(absolutePath);
|
|
12346
12718
|
try {
|
|
12347
|
-
const st = (0,
|
|
12719
|
+
const st = (0, import_node_fs30.statSync)(absolutePath);
|
|
12348
12720
|
if (!st.isFile()) {
|
|
12349
12721
|
return {
|
|
12350
12722
|
id: (0, import_node_crypto5.randomUUID)(),
|
|
@@ -12353,7 +12725,7 @@ function attachmentFromAbsolutePath(absolutePath) {
|
|
|
12353
12725
|
content: `(not a file: ${absolutePath})`
|
|
12354
12726
|
};
|
|
12355
12727
|
}
|
|
12356
|
-
const buf = (0,
|
|
12728
|
+
const buf = (0, import_node_fs30.readFileSync)(absolutePath);
|
|
12357
12729
|
return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
|
|
12358
12730
|
} catch (err) {
|
|
12359
12731
|
return {
|
|
@@ -12369,15 +12741,15 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
|
12369
12741
|
const dir = ensureAttachmentsDir(worktreePath);
|
|
12370
12742
|
const out = [];
|
|
12371
12743
|
for (const abs of absolutePaths) {
|
|
12372
|
-
const originalName = (0,
|
|
12744
|
+
const originalName = (0, import_node_path28.basename)(abs);
|
|
12373
12745
|
try {
|
|
12374
|
-
const st = (0,
|
|
12746
|
+
const st = (0, import_node_fs30.statSync)(abs);
|
|
12375
12747
|
if (!st.isFile()) continue;
|
|
12376
12748
|
const name = uniqueAttachmentName(dir, originalName);
|
|
12377
|
-
const destAbs = (0,
|
|
12378
|
-
(0,
|
|
12749
|
+
const destAbs = (0, import_node_path28.join)(dir, name);
|
|
12750
|
+
(0, import_node_fs30.copyFileSync)(abs, destAbs);
|
|
12379
12751
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
12380
|
-
const buf = (0,
|
|
12752
|
+
const buf = (0, import_node_fs30.readFileSync)(destAbs);
|
|
12381
12753
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
12382
12754
|
} catch (err) {
|
|
12383
12755
|
out.push({
|
|
@@ -12399,8 +12771,8 @@ function stageBuffersAsAttachments(worktreePath, buffers) {
|
|
|
12399
12771
|
try {
|
|
12400
12772
|
const buf = Buffer.from(item.dataBase64, "base64");
|
|
12401
12773
|
const name = uniqueAttachmentName(dir, originalName);
|
|
12402
|
-
const destAbs = (0,
|
|
12403
|
-
(0,
|
|
12774
|
+
const destAbs = (0, import_node_path28.join)(dir, name);
|
|
12775
|
+
(0, import_node_fs30.writeFileSync)(destAbs, buf);
|
|
12404
12776
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
12405
12777
|
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
12406
12778
|
} catch (err) {
|
|
@@ -12436,18 +12808,18 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
12436
12808
|
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
12437
12809
|
out.push({
|
|
12438
12810
|
id: (0, import_node_crypto5.randomUUID)(),
|
|
12439
|
-
name: (0,
|
|
12811
|
+
name: (0, import_node_path28.basename)(rel) || "file",
|
|
12440
12812
|
kind: "file",
|
|
12441
12813
|
content: `(invalid path: ${rel})`
|
|
12442
12814
|
});
|
|
12443
12815
|
continue;
|
|
12444
12816
|
}
|
|
12445
|
-
const name = (0,
|
|
12817
|
+
const name = (0, import_node_path28.basename)(rel);
|
|
12446
12818
|
try {
|
|
12447
|
-
const abs = (0,
|
|
12448
|
-
const st = (0,
|
|
12819
|
+
const abs = (0, import_node_path28.join)(worktreePath, rel);
|
|
12820
|
+
const st = (0, import_node_fs30.statSync)(abs);
|
|
12449
12821
|
if (!st.isFile()) continue;
|
|
12450
|
-
const buf = (0,
|
|
12822
|
+
const buf = (0, import_node_fs30.readFileSync)(abs);
|
|
12451
12823
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
12452
12824
|
} catch (err) {
|
|
12453
12825
|
out.push({
|
|
@@ -12935,7 +13307,7 @@ async function confirmLand(thread, opts) {
|
|
|
12935
13307
|
}
|
|
12936
13308
|
|
|
12937
13309
|
// src/threads/create.ts
|
|
12938
|
-
var
|
|
13310
|
+
var import_node_fs31 = require("fs");
|
|
12939
13311
|
init_worktree();
|
|
12940
13312
|
init_app_settings();
|
|
12941
13313
|
init_thread_store();
|
|
@@ -12949,12 +13321,13 @@ async function createThread(input, _onSetupLine) {
|
|
|
12949
13321
|
});
|
|
12950
13322
|
await requireAgent(resolved.agent);
|
|
12951
13323
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
12952
|
-
if (!(0,
|
|
13324
|
+
if (!(0, import_node_fs31.existsSync)(repoPath)) {
|
|
12953
13325
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
12954
13326
|
}
|
|
12955
13327
|
let sourceRef = input.sourceRef;
|
|
12956
13328
|
let sourceIsFork = false;
|
|
12957
13329
|
let prUrl = null;
|
|
13330
|
+
let prTitle = null;
|
|
12958
13331
|
if (input.sourceType === "pr") {
|
|
12959
13332
|
const num2 = Number(input.sourceRef.replace(/^#/, ""));
|
|
12960
13333
|
if (!Number.isFinite(num2)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
|
|
@@ -12970,6 +13343,12 @@ async function createThread(input, _onSetupLine) {
|
|
|
12970
13343
|
} else if (input.sourceType === "branch") {
|
|
12971
13344
|
if (!sourceRef || sourceRef === "HEAD" || sourceRef === "default") {
|
|
12972
13345
|
sourceRef = await resolveDefaultBranch(repoPath);
|
|
13346
|
+
} else {
|
|
13347
|
+
const existing = await getPrForHeadBranch(repoPath, sourceRef);
|
|
13348
|
+
if (existing?.url) {
|
|
13349
|
+
prUrl = existing.url;
|
|
13350
|
+
prTitle = existing.title;
|
|
13351
|
+
}
|
|
12973
13352
|
}
|
|
12974
13353
|
} else if (input.sourceType === "adopt") {
|
|
12975
13354
|
throw new Error("Use adoptThread() for adopt sources");
|
|
@@ -13000,7 +13379,8 @@ async function createThread(input, _onSetupLine) {
|
|
|
13000
13379
|
sourceIsFork,
|
|
13001
13380
|
parentThreadId: input.parentThreadId ?? null,
|
|
13002
13381
|
status: "idle",
|
|
13003
|
-
prUrl
|
|
13382
|
+
prUrl,
|
|
13383
|
+
prTitle
|
|
13004
13384
|
});
|
|
13005
13385
|
writeThread(thread);
|
|
13006
13386
|
await ensureWorkspace(repoPath);
|
|
@@ -13176,7 +13556,7 @@ async function forkThreadWorktree(input, onSetupLine) {
|
|
|
13176
13556
|
}
|
|
13177
13557
|
|
|
13178
13558
|
// src/threads/stack-layers.ts
|
|
13179
|
-
var
|
|
13559
|
+
var import_node_fs32 = require("fs");
|
|
13180
13560
|
init_run();
|
|
13181
13561
|
init_stack();
|
|
13182
13562
|
init_worktree();
|
|
@@ -13244,7 +13624,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
13244
13624
|
let createdWorktree = false;
|
|
13245
13625
|
const trees = await listWorktrees(repoPath);
|
|
13246
13626
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
13247
|
-
if (checkedOut?.path && (0,
|
|
13627
|
+
if (checkedOut?.path && (0, import_node_fs32.existsSync)(checkedOut.path)) {
|
|
13248
13628
|
if (input.reuseExistingWorktree !== false) {
|
|
13249
13629
|
worktreePath = checkedOut.path;
|
|
13250
13630
|
} else {
|
|
@@ -13386,7 +13766,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
13386
13766
|
async function createPrStack(input, onSetupLine) {
|
|
13387
13767
|
await requireAgent(input.agent);
|
|
13388
13768
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
13389
|
-
if (!(0,
|
|
13769
|
+
if (!(0, import_node_fs32.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
13390
13770
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
13391
13771
|
const status = await detectGhStack(repoPath);
|
|
13392
13772
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -13453,7 +13833,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
13453
13833
|
}
|
|
13454
13834
|
}
|
|
13455
13835
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
13456
|
-
if (!claimed.has(bootstrap.worktreePath) && (0,
|
|
13836
|
+
if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs32.existsSync)(bootstrap.worktreePath)) {
|
|
13457
13837
|
try {
|
|
13458
13838
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
13459
13839
|
deleteBranch: bootstrap.branchName
|
|
@@ -13476,20 +13856,26 @@ function stackAgentDefaultsFrom(input) {
|
|
|
13476
13856
|
|
|
13477
13857
|
// src/threads/adopt.ts
|
|
13478
13858
|
var import_node_child_process4 = require("child_process");
|
|
13479
|
-
var
|
|
13480
|
-
var
|
|
13481
|
-
var
|
|
13482
|
-
var
|
|
13859
|
+
var import_node_fs33 = require("fs");
|
|
13860
|
+
var import_node_os11 = require("os");
|
|
13861
|
+
var import_node_path29 = require("path");
|
|
13862
|
+
var import_node_module4 = require("module");
|
|
13483
13863
|
init_worktree();
|
|
13484
13864
|
init_thread_store();
|
|
13485
|
-
var
|
|
13865
|
+
var import_meta4 = {};
|
|
13866
|
+
var CONDUCTOR_APP_SUPPORT = (0, import_node_path29.join)(
|
|
13486
13867
|
process.env.HOME ?? "",
|
|
13487
13868
|
"Library",
|
|
13488
13869
|
"Application Support",
|
|
13489
13870
|
"com.conductor.app"
|
|
13490
13871
|
);
|
|
13491
|
-
var CONDUCTOR_DB = (0,
|
|
13492
|
-
var CURSOR_SDK_STORE = (0,
|
|
13872
|
+
var CONDUCTOR_DB = (0, import_node_path29.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
13873
|
+
var CURSOR_SDK_STORE = (0, import_node_path29.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
13874
|
+
function openReadonlySqlite(file) {
|
|
13875
|
+
const req = (0, import_node_module4.createRequire)(import_meta4.url);
|
|
13876
|
+
const Database = req("better-sqlite3");
|
|
13877
|
+
return new Database(file, { readonly: true, fileMustExist: true });
|
|
13878
|
+
}
|
|
13493
13879
|
function mapAgentType(raw) {
|
|
13494
13880
|
if (!raw) return null;
|
|
13495
13881
|
const v = raw.toLowerCase();
|
|
@@ -13501,21 +13887,21 @@ function mapAgentType(raw) {
|
|
|
13501
13887
|
return null;
|
|
13502
13888
|
}
|
|
13503
13889
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
13504
|
-
if (!workspacePath || !(0,
|
|
13890
|
+
if (!workspacePath || !(0, import_node_fs33.existsSync)(CURSOR_SDK_STORE)) return null;
|
|
13505
13891
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
13506
13892
|
let best = null;
|
|
13507
13893
|
let hashes;
|
|
13508
13894
|
try {
|
|
13509
|
-
hashes = (0,
|
|
13895
|
+
hashes = (0, import_node_fs33.readdirSync)(CURSOR_SDK_STORE);
|
|
13510
13896
|
} catch {
|
|
13511
13897
|
return null;
|
|
13512
13898
|
}
|
|
13513
13899
|
for (const hash of hashes) {
|
|
13514
|
-
const agentsFile = (0,
|
|
13515
|
-
if (!(0,
|
|
13900
|
+
const agentsFile = (0, import_node_path29.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
13901
|
+
if (!(0, import_node_fs33.existsSync)(agentsFile)) continue;
|
|
13516
13902
|
let text3;
|
|
13517
13903
|
try {
|
|
13518
|
-
text3 = (0,
|
|
13904
|
+
text3 = (0, import_node_fs33.readFileSync)(agentsFile, "utf8");
|
|
13519
13905
|
} catch {
|
|
13520
13906
|
continue;
|
|
13521
13907
|
}
|
|
@@ -13539,7 +13925,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
13539
13925
|
return best?.agentId ?? null;
|
|
13540
13926
|
}
|
|
13541
13927
|
async function adoptThread(input) {
|
|
13542
|
-
if (!(0,
|
|
13928
|
+
if (!(0, import_node_fs33.existsSync)(input.worktreePath)) {
|
|
13543
13929
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
13544
13930
|
}
|
|
13545
13931
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -13566,23 +13952,23 @@ function conductorDbPath() {
|
|
|
13566
13952
|
return CONDUCTOR_DB;
|
|
13567
13953
|
}
|
|
13568
13954
|
function listConductorWorkspaces() {
|
|
13569
|
-
if (!(0,
|
|
13955
|
+
if (!(0, import_node_fs33.existsSync)(CONDUCTOR_DB)) {
|
|
13570
13956
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
13571
13957
|
}
|
|
13572
|
-
const tmp = (0,
|
|
13573
|
-
const snapshot = (0,
|
|
13958
|
+
const tmp = (0, import_node_fs33.mkdtempSync)((0, import_node_path29.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
|
|
13959
|
+
const snapshot = (0, import_node_path29.join)(tmp, "conductor.db");
|
|
13574
13960
|
try {
|
|
13575
|
-
(0,
|
|
13961
|
+
(0, import_node_fs33.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
13576
13962
|
for (const suffix of ["-wal", "-shm"]) {
|
|
13577
13963
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
13578
|
-
if ((0,
|
|
13964
|
+
if ((0, import_node_fs33.existsSync)(src)) {
|
|
13579
13965
|
try {
|
|
13580
|
-
(0,
|
|
13966
|
+
(0, import_node_fs33.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
13581
13967
|
} catch {
|
|
13582
13968
|
}
|
|
13583
13969
|
}
|
|
13584
13970
|
}
|
|
13585
|
-
const db =
|
|
13971
|
+
const db = openReadonlySqlite(snapshot);
|
|
13586
13972
|
try {
|
|
13587
13973
|
const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table'`).all();
|
|
13588
13974
|
const names = new Set(tables.map((t) => t.name));
|
|
@@ -13653,27 +14039,27 @@ function listConductorWorkspaces() {
|
|
|
13653
14039
|
db.close();
|
|
13654
14040
|
}
|
|
13655
14041
|
} finally {
|
|
13656
|
-
(0,
|
|
14042
|
+
(0, import_node_fs33.rmSync)(tmp, { recursive: true, force: true });
|
|
13657
14043
|
}
|
|
13658
14044
|
}
|
|
13659
14045
|
function importConductorWorkspace(workspaceId) {
|
|
13660
|
-
if (!(0,
|
|
14046
|
+
if (!(0, import_node_fs33.existsSync)(CONDUCTOR_DB)) {
|
|
13661
14047
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
13662
14048
|
}
|
|
13663
|
-
const tmp = (0,
|
|
13664
|
-
const snapshot = (0,
|
|
14049
|
+
const tmp = (0, import_node_fs33.mkdtempSync)((0, import_node_path29.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
|
|
14050
|
+
const snapshot = (0, import_node_path29.join)(tmp, "conductor.db");
|
|
13665
14051
|
try {
|
|
13666
|
-
(0,
|
|
14052
|
+
(0, import_node_fs33.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
13667
14053
|
for (const suffix of ["-wal", "-shm"]) {
|
|
13668
14054
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
13669
|
-
if ((0,
|
|
14055
|
+
if ((0, import_node_fs33.existsSync)(src)) {
|
|
13670
14056
|
try {
|
|
13671
|
-
(0,
|
|
14057
|
+
(0, import_node_fs33.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
13672
14058
|
} catch {
|
|
13673
14059
|
}
|
|
13674
14060
|
}
|
|
13675
14061
|
}
|
|
13676
|
-
const db =
|
|
14062
|
+
const db = openReadonlySqlite(snapshot);
|
|
13677
14063
|
try {
|
|
13678
14064
|
const row = db.prepare(
|
|
13679
14065
|
`SELECT
|
|
@@ -13686,7 +14072,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
13686
14072
|
).get(workspaceId);
|
|
13687
14073
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
13688
14074
|
const worktreePath = String(row.workspacePath);
|
|
13689
|
-
if (!(0,
|
|
14075
|
+
if (!(0, import_node_fs33.existsSync)(worktreePath)) {
|
|
13690
14076
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
13691
14077
|
}
|
|
13692
14078
|
let sessionId = null;
|
|
@@ -13749,7 +14135,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
13749
14135
|
db.close();
|
|
13750
14136
|
}
|
|
13751
14137
|
} finally {
|
|
13752
|
-
(0,
|
|
14138
|
+
(0, import_node_fs33.rmSync)(tmp, { recursive: true, force: true });
|
|
13753
14139
|
}
|
|
13754
14140
|
}
|
|
13755
14141
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
@@ -13760,8 +14146,8 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
13760
14146
|
var import_node_events = require("events");
|
|
13761
14147
|
|
|
13762
14148
|
// src/slack/outbound-watch.ts
|
|
13763
|
-
var
|
|
13764
|
-
var
|
|
14149
|
+
var import_node_fs35 = require("fs");
|
|
14150
|
+
var import_node_path32 = require("path");
|
|
13765
14151
|
init_paths();
|
|
13766
14152
|
init_private_file();
|
|
13767
14153
|
init_secure_file();
|
|
@@ -13807,19 +14193,19 @@ async function slackAuthTest(token) {
|
|
|
13807
14193
|
}
|
|
13808
14194
|
|
|
13809
14195
|
// src/slack/reply-target.ts
|
|
13810
|
-
var
|
|
13811
|
-
var
|
|
14196
|
+
var import_node_fs34 = require("fs");
|
|
14197
|
+
var import_node_path30 = require("path");
|
|
13812
14198
|
init_paths();
|
|
13813
14199
|
init_private_file();
|
|
13814
14200
|
init_secure_file();
|
|
13815
14201
|
function storePath2() {
|
|
13816
|
-
return (0,
|
|
14202
|
+
return (0, import_node_path30.join)(appDataDir(), "slack-reply-to.json");
|
|
13817
14203
|
}
|
|
13818
14204
|
function readStore2() {
|
|
13819
14205
|
const path2 = storePath2();
|
|
13820
|
-
if (!(0,
|
|
14206
|
+
if (!(0, import_node_fs34.existsSync)(path2)) return {};
|
|
13821
14207
|
try {
|
|
13822
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
14208
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
|
|
13823
14209
|
return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
|
|
13824
14210
|
} catch {
|
|
13825
14211
|
return {};
|
|
@@ -13836,11 +14222,11 @@ function getSlackReplyTarget(threadId) {
|
|
|
13836
14222
|
}
|
|
13837
14223
|
|
|
13838
14224
|
// src/slack/workspaces.ts
|
|
13839
|
-
var
|
|
14225
|
+
var import_node_path31 = require("path");
|
|
13840
14226
|
init_paths();
|
|
13841
14227
|
init_secure_file();
|
|
13842
14228
|
function storePath3() {
|
|
13843
|
-
return (0,
|
|
14229
|
+
return (0, import_node_path31.join)(appDataDir(), "slack-workspaces.json");
|
|
13844
14230
|
}
|
|
13845
14231
|
function readStore3() {
|
|
13846
14232
|
try {
|
|
@@ -13956,7 +14342,7 @@ var POLL_INTERVAL_MS = 12e3;
|
|
|
13956
14342
|
var lastPollMs = 0;
|
|
13957
14343
|
var nameCache = /* @__PURE__ */ new Map();
|
|
13958
14344
|
function storePath4() {
|
|
13959
|
-
return (0,
|
|
14345
|
+
return (0, import_node_path32.join)(appDataDir(), "slack-outbound-watch.json");
|
|
13960
14346
|
}
|
|
13961
14347
|
function watchId(teamId, channelId, ts) {
|
|
13962
14348
|
return `${teamId}:${channelId}:${ts}`;
|
|
@@ -13986,9 +14372,9 @@ function tsNewer(a, b) {
|
|
|
13986
14372
|
}
|
|
13987
14373
|
function readStore4() {
|
|
13988
14374
|
const path2 = storePath4();
|
|
13989
|
-
if (!(0,
|
|
14375
|
+
if (!(0, import_node_fs35.existsSync)(path2)) return [];
|
|
13990
14376
|
try {
|
|
13991
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
14377
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
|
|
13992
14378
|
return Array.isArray(parsed?.watches) ? parsed.watches : [];
|
|
13993
14379
|
} catch {
|
|
13994
14380
|
return [];
|
|
@@ -14333,7 +14719,7 @@ async function refreshSlackReplyBadges(opts) {
|
|
|
14333
14719
|
}
|
|
14334
14720
|
|
|
14335
14721
|
// src/orchestrator/orchestrator.ts
|
|
14336
|
-
var
|
|
14722
|
+
var import_node_fs41 = require("fs");
|
|
14337
14723
|
init_error_detail();
|
|
14338
14724
|
init_agents();
|
|
14339
14725
|
init_worktree();
|
|
@@ -14354,8 +14740,8 @@ function shouldAutoArchiveOnPrMerge(opts) {
|
|
|
14354
14740
|
}
|
|
14355
14741
|
|
|
14356
14742
|
// src/git/orphan-cleanup.ts
|
|
14357
|
-
var
|
|
14358
|
-
var
|
|
14743
|
+
var import_node_fs36 = require("fs");
|
|
14744
|
+
var import_node_path33 = require("path");
|
|
14359
14745
|
init_worktree();
|
|
14360
14746
|
init_thread_store();
|
|
14361
14747
|
init_paths();
|
|
@@ -14370,9 +14756,9 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
14370
14756
|
repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
|
|
14371
14757
|
);
|
|
14372
14758
|
const homeRoot = sideboardWorkspacesDir();
|
|
14373
|
-
if ((0,
|
|
14759
|
+
if ((0, import_node_fs36.existsSync)(homeRoot)) {
|
|
14374
14760
|
try {
|
|
14375
|
-
for (const entry of (0,
|
|
14761
|
+
for (const entry of (0, import_node_fs36.readdirSync)(homeRoot, { withFileTypes: true })) {
|
|
14376
14762
|
if (!entry.isDirectory()) continue;
|
|
14377
14763
|
void entry;
|
|
14378
14764
|
}
|
|
@@ -14382,7 +14768,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
14382
14768
|
const orphans = [];
|
|
14383
14769
|
const seen = /* @__PURE__ */ new Set();
|
|
14384
14770
|
for (const repoPath of repos) {
|
|
14385
|
-
if (!repoPath || !(0,
|
|
14771
|
+
if (!repoPath || !(0, import_node_fs36.existsSync)(repoPath)) continue;
|
|
14386
14772
|
try {
|
|
14387
14773
|
const wts = await listWorktrees(repoPath);
|
|
14388
14774
|
for (const wt of wts) {
|
|
@@ -14393,7 +14779,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
14393
14779
|
seen.add(path2);
|
|
14394
14780
|
let mtimeMs = 0;
|
|
14395
14781
|
try {
|
|
14396
|
-
mtimeMs = (0,
|
|
14782
|
+
mtimeMs = (0, import_node_fs36.statSync)(path2).mtimeMs;
|
|
14397
14783
|
} catch {
|
|
14398
14784
|
mtimeMs = 0;
|
|
14399
14785
|
}
|
|
@@ -14403,16 +14789,16 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
14403
14789
|
}
|
|
14404
14790
|
try {
|
|
14405
14791
|
const root = worktreesRoot(repoPath);
|
|
14406
|
-
if ((0,
|
|
14407
|
-
for (const entry of (0,
|
|
14792
|
+
if ((0, import_node_fs36.existsSync)(root)) {
|
|
14793
|
+
for (const entry of (0, import_node_fs36.readdirSync)(root, { withFileTypes: true })) {
|
|
14408
14794
|
if (!entry.isDirectory()) continue;
|
|
14409
|
-
const path2 = (0,
|
|
14795
|
+
const path2 = (0, import_node_path33.join)(root, entry.name).replace(/\/$/, "");
|
|
14410
14796
|
if (known.has(path2) || seen.has(path2)) continue;
|
|
14411
|
-
if (!(0,
|
|
14797
|
+
if (!(0, import_node_fs36.existsSync)((0, import_node_path33.join)(path2, ".git"))) continue;
|
|
14412
14798
|
seen.add(path2);
|
|
14413
14799
|
let mtimeMs = 0;
|
|
14414
14800
|
try {
|
|
14415
|
-
mtimeMs = (0,
|
|
14801
|
+
mtimeMs = (0, import_node_fs36.statSync)(path2).mtimeMs;
|
|
14416
14802
|
} catch {
|
|
14417
14803
|
mtimeMs = Date.now();
|
|
14418
14804
|
}
|
|
@@ -14558,8 +14944,8 @@ async function applyThreadIntoMain(thread, opts) {
|
|
|
14558
14944
|
}
|
|
14559
14945
|
|
|
14560
14946
|
// src/git/clone-repo.ts
|
|
14561
|
-
var
|
|
14562
|
-
var
|
|
14947
|
+
var import_node_fs37 = require("fs");
|
|
14948
|
+
var import_node_path34 = require("path");
|
|
14563
14949
|
var import_execa6 = require("execa");
|
|
14564
14950
|
init_paths();
|
|
14565
14951
|
init_workspaces();
|
|
@@ -14569,12 +14955,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
14569
14955
|
if (!url) throw new Error("Clone URL is required");
|
|
14570
14956
|
let name = opts.name?.trim();
|
|
14571
14957
|
if (!name) {
|
|
14572
|
-
const leaf = (0,
|
|
14958
|
+
const leaf = (0, import_node_path34.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
|
|
14573
14959
|
name = leaf || "repo";
|
|
14574
14960
|
}
|
|
14575
14961
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
14576
|
-
const dest = (0,
|
|
14577
|
-
if ((0,
|
|
14962
|
+
const dest = (0, import_node_path34.join)(sideboardReposDir(), name);
|
|
14963
|
+
if ((0, import_node_fs37.existsSync)(dest)) {
|
|
14578
14964
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
14579
14965
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
14580
14966
|
return { repoPath: repoPath2, workspace: workspace2 };
|
|
@@ -14596,8 +14982,8 @@ init_orchestrator_capable();
|
|
|
14596
14982
|
|
|
14597
14983
|
// src/review/request-review.ts
|
|
14598
14984
|
var import_node_crypto8 = require("crypto");
|
|
14599
|
-
var
|
|
14600
|
-
var
|
|
14985
|
+
var import_node_fs38 = require("fs");
|
|
14986
|
+
var import_node_path35 = require("path");
|
|
14601
14987
|
init_global_workspace();
|
|
14602
14988
|
init_thread_store();
|
|
14603
14989
|
|
|
@@ -14745,22 +15131,22 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
14745
15131
|
return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
|
|
14746
15132
|
}
|
|
14747
15133
|
function readTextIfPresent(abs) {
|
|
14748
|
-
if (!(0,
|
|
15134
|
+
if (!(0, import_node_fs38.existsSync)(abs)) return null;
|
|
14749
15135
|
try {
|
|
14750
|
-
const content = (0,
|
|
15136
|
+
const content = (0, import_node_fs38.readFileSync)(abs, "utf8");
|
|
14751
15137
|
return content.trim() ? content : null;
|
|
14752
15138
|
} catch {
|
|
14753
15139
|
return null;
|
|
14754
15140
|
}
|
|
14755
15141
|
}
|
|
14756
15142
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
14757
|
-
const gitignoreAbs = (0,
|
|
14758
|
-
if ((0,
|
|
14759
|
-
(0,
|
|
14760
|
-
(0,
|
|
15143
|
+
const gitignoreAbs = (0, import_node_path35.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
15144
|
+
if ((0, import_node_fs38.existsSync)(gitignoreAbs)) return;
|
|
15145
|
+
(0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(gitignoreAbs), { recursive: true });
|
|
15146
|
+
(0, import_node_fs38.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
14761
15147
|
}
|
|
14762
15148
|
function resolveReviewGuidelines(worktreePath) {
|
|
14763
|
-
const repoAbs = (0,
|
|
15149
|
+
const repoAbs = (0, import_node_path35.join)(worktreePath, REPO_REVIEW_PATH);
|
|
14764
15150
|
const repoContent = readTextIfPresent(repoAbs);
|
|
14765
15151
|
if (repoContent) {
|
|
14766
15152
|
return {
|
|
@@ -14770,7 +15156,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
14770
15156
|
source: "repo"
|
|
14771
15157
|
};
|
|
14772
15158
|
}
|
|
14773
|
-
const localAbs = (0,
|
|
15159
|
+
const localAbs = (0, import_node_path35.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
14774
15160
|
const localContent = readTextIfPresent(localAbs);
|
|
14775
15161
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
14776
15162
|
return {
|
|
@@ -14780,7 +15166,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
14780
15166
|
source: "local"
|
|
14781
15167
|
};
|
|
14782
15168
|
}
|
|
14783
|
-
const legacyAbs = (0,
|
|
15169
|
+
const legacyAbs = (0, import_node_path35.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
14784
15170
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
14785
15171
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
14786
15172
|
return {
|
|
@@ -14791,8 +15177,8 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
14791
15177
|
};
|
|
14792
15178
|
}
|
|
14793
15179
|
ensureAttachmentsGitignore(worktreePath);
|
|
14794
|
-
(0,
|
|
14795
|
-
(0,
|
|
15180
|
+
(0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(localAbs), { recursive: true });
|
|
15181
|
+
(0, import_node_fs38.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
|
|
14796
15182
|
return {
|
|
14797
15183
|
path: REVIEW_REQUEST_PATH,
|
|
14798
15184
|
name: REVIEW_REQUEST_NAME,
|
|
@@ -14801,7 +15187,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
14801
15187
|
};
|
|
14802
15188
|
}
|
|
14803
15189
|
function ensureReviewRequestFile(worktreePath) {
|
|
14804
|
-
const repoAbs = (0,
|
|
15190
|
+
const repoAbs = (0, import_node_path35.join)(worktreePath, REPO_REVIEW_PATH);
|
|
14805
15191
|
const repoContent = readTextIfPresent(repoAbs);
|
|
14806
15192
|
if (repoContent) {
|
|
14807
15193
|
return {
|
|
@@ -14811,10 +15197,10 @@ function ensureReviewRequestFile(worktreePath) {
|
|
|
14811
15197
|
source: "repo"
|
|
14812
15198
|
};
|
|
14813
15199
|
}
|
|
14814
|
-
const localAbs = (0,
|
|
14815
|
-
const localContent = readTextIfPresent(localAbs) ?? readTextIfPresent((0,
|
|
15200
|
+
const localAbs = (0, import_node_path35.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
15201
|
+
const localContent = readTextIfPresent(localAbs) ?? readTextIfPresent((0, import_node_path35.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
|
|
14816
15202
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
14817
|
-
const path2 = (0,
|
|
15203
|
+
const path2 = (0, import_node_fs38.existsSync)(localAbs) ? REVIEW_REQUEST_PATH : LEGACY_REVIEW_REQUEST_PATH;
|
|
14818
15204
|
return {
|
|
14819
15205
|
path: path2,
|
|
14820
15206
|
name: REVIEW_REQUEST_NAME,
|
|
@@ -14822,8 +15208,8 @@ function ensureReviewRequestFile(worktreePath) {
|
|
|
14822
15208
|
source: "local"
|
|
14823
15209
|
};
|
|
14824
15210
|
}
|
|
14825
|
-
(0,
|
|
14826
|
-
(0,
|
|
15211
|
+
(0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(repoAbs), { recursive: true });
|
|
15212
|
+
(0, import_node_fs38.writeFileSync)(repoAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
|
|
14827
15213
|
return {
|
|
14828
15214
|
path: REPO_REVIEW_PATH,
|
|
14829
15215
|
name: REPO_REVIEW_NAME,
|
|
@@ -14843,7 +15229,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
14843
15229
|
};
|
|
14844
15230
|
}
|
|
14845
15231
|
function readExistingReviewRequestFile(worktreePath) {
|
|
14846
|
-
return readTextIfPresent((0,
|
|
15232
|
+
return readTextIfPresent((0, import_node_path35.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path35.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path35.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
|
|
14847
15233
|
}
|
|
14848
15234
|
async function requestReview(threadRef, send2) {
|
|
14849
15235
|
const from = findThreadByRef(threadRef);
|
|
@@ -15104,7 +15490,7 @@ var Orchestrator = class {
|
|
|
15104
15490
|
}
|
|
15105
15491
|
continue;
|
|
15106
15492
|
}
|
|
15107
|
-
if (!(0,
|
|
15493
|
+
if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
|
|
15108
15494
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
15109
15495
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
15110
15496
|
continue;
|
|
@@ -16196,8 +16582,9 @@ var Orchestrator = class {
|
|
|
16196
16582
|
return result;
|
|
16197
16583
|
}
|
|
16198
16584
|
async mergePr(threadRef) {
|
|
16199
|
-
const { thread,
|
|
16585
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
16200
16586
|
this.assertNotGlobal(thread, "Merge PR");
|
|
16587
|
+
const selector = selectors[0];
|
|
16201
16588
|
if (!selector) throw new Error("No pull request linked to this thread");
|
|
16202
16589
|
const result = await mergePr(cwd, selector);
|
|
16203
16590
|
const state = normalizePrState(result.state) || "MERGED";
|
|
@@ -16217,29 +16604,34 @@ var Orchestrator = class {
|
|
|
16217
16604
|
await this.persistPrMetaAndMaybeArchive(thread, metaLike);
|
|
16218
16605
|
return { url: metaLike.url, state };
|
|
16219
16606
|
}
|
|
16220
|
-
/** Resolve PR
|
|
16607
|
+
/** Resolve PR selectors and optionally persist `prUrl` when found. */
|
|
16221
16608
|
async withPrSelector(threadRef) {
|
|
16222
16609
|
const thread = this.requireThread(threadRef);
|
|
16223
|
-
const
|
|
16610
|
+
const selectors = resolvePrSelectors(thread);
|
|
16224
16611
|
const cwd = thread.worktreePath;
|
|
16225
16612
|
if (!cwd?.trim()) {
|
|
16226
16613
|
throw new Error(`Thread ${threadRef} has no worktreePath`);
|
|
16227
16614
|
}
|
|
16228
|
-
return { thread,
|
|
16615
|
+
return { thread, selectors, cwd };
|
|
16229
16616
|
}
|
|
16230
16617
|
async getPrChecks(threadRef) {
|
|
16231
|
-
const {
|
|
16232
|
-
|
|
16233
|
-
|
|
16618
|
+
const { selectors, cwd } = await this.withPrSelector(threadRef);
|
|
16619
|
+
for (const selector of selectors) {
|
|
16620
|
+
const checks = await getPrChecks(cwd, selector);
|
|
16621
|
+
if (checks) return checks;
|
|
16622
|
+
}
|
|
16623
|
+
return null;
|
|
16234
16624
|
}
|
|
16235
16625
|
async getPrMeta(threadRef) {
|
|
16236
|
-
const { thread,
|
|
16237
|
-
|
|
16238
|
-
|
|
16239
|
-
|
|
16240
|
-
|
|
16626
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
16627
|
+
for (const selector of selectors) {
|
|
16628
|
+
const meta = await getPrMeta(cwd, selector);
|
|
16629
|
+
if (meta) {
|
|
16630
|
+
await this.persistPrMetaAndMaybeArchive(thread, meta);
|
|
16631
|
+
return meta;
|
|
16632
|
+
}
|
|
16241
16633
|
}
|
|
16242
|
-
return
|
|
16634
|
+
return null;
|
|
16243
16635
|
}
|
|
16244
16636
|
/**
|
|
16245
16637
|
* Persist PR URL/title/state and Conductor-style auto-archive when the PR
|
|
@@ -16363,9 +16755,12 @@ var Orchestrator = class {
|
|
|
16363
16755
|
return { stack: result.stack, threads: result.threads };
|
|
16364
16756
|
}
|
|
16365
16757
|
async getPrDetails(threadRef) {
|
|
16366
|
-
const { thread,
|
|
16367
|
-
|
|
16368
|
-
const
|
|
16758
|
+
const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
|
|
16759
|
+
let details = null;
|
|
16760
|
+
for (const selector of selectors) {
|
|
16761
|
+
details = await getPrDetails(cwd, selector);
|
|
16762
|
+
if (details) break;
|
|
16763
|
+
}
|
|
16369
16764
|
if (details) {
|
|
16370
16765
|
const patch = {};
|
|
16371
16766
|
if (details.url && details.url !== thread.prUrl) patch.prUrl = details.url;
|
|
@@ -16592,7 +16987,7 @@ var Orchestrator = class {
|
|
|
16592
16987
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
16593
16988
|
return restored2;
|
|
16594
16989
|
}
|
|
16595
|
-
if (!(0,
|
|
16990
|
+
if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
|
|
16596
16991
|
const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
|
|
16597
16992
|
const { execa: execa7 } = await import("execa");
|
|
16598
16993
|
const slug = thread.worktreePath.split("/").pop();
|
|
@@ -16833,7 +17228,7 @@ init_coordinator_prompt();
|
|
|
16833
17228
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
16834
17229
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
16835
17230
|
var import_zod3 = require("zod");
|
|
16836
|
-
var
|
|
17231
|
+
var import_node_path38 = require("path");
|
|
16837
17232
|
init_worktree();
|
|
16838
17233
|
init_global_workspace();
|
|
16839
17234
|
init_list_models();
|
|
@@ -17447,6 +17842,7 @@ function registerLinearTools(server) {
|
|
|
17447
17842
|
}
|
|
17448
17843
|
|
|
17449
17844
|
// src/mcp/server.ts
|
|
17845
|
+
init_git_auth_mode();
|
|
17450
17846
|
var MAX_ORCH_THREADS = 5;
|
|
17451
17847
|
var CREATE_THREAD_TIMEOUT_MS = 9e4;
|
|
17452
17848
|
function withTimeout(promise, ms, label) {
|
|
@@ -17468,6 +17864,14 @@ function withTimeout(promise, ms, label) {
|
|
|
17468
17864
|
}
|
|
17469
17865
|
async function startMcpServer() {
|
|
17470
17866
|
const orch = getOrchestrator();
|
|
17867
|
+
try {
|
|
17868
|
+
await warmGithubAgentAuth();
|
|
17869
|
+
} catch (err) {
|
|
17870
|
+
console.error(
|
|
17871
|
+
"[sideboard-mcp] GitHub agent auth warm skipped:",
|
|
17872
|
+
err instanceof Error ? err.message : err
|
|
17873
|
+
);
|
|
17874
|
+
}
|
|
17471
17875
|
try {
|
|
17472
17876
|
const { maxConcurrentAgents: maxConcurrentAgents2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
|
|
17473
17877
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
@@ -17511,7 +17915,7 @@ async function startMcpServer() {
|
|
|
17511
17915
|
async () => {
|
|
17512
17916
|
const threads = orch.getThreads(true);
|
|
17513
17917
|
const lines = threads.map((t) => {
|
|
17514
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
17918
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path38.basename)(t.repoPath) || t.repoPath;
|
|
17515
17919
|
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}` : ""}`;
|
|
17516
17920
|
});
|
|
17517
17921
|
return {
|
|
@@ -17574,7 +17978,7 @@ async function startMcpServer() {
|
|
|
17574
17978
|
);
|
|
17575
17979
|
server.tool(
|
|
17576
17980
|
"ask_user",
|
|
17577
|
-
"Ask the user clarifying multiple-choice
|
|
17981
|
+
"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.",
|
|
17578
17982
|
{
|
|
17579
17983
|
questions: import_zod3.z.array(
|
|
17580
17984
|
import_zod3.z.object({
|
|
@@ -18819,6 +19223,77 @@ init_accounts();
|
|
|
18819
19223
|
init_connected_teams();
|
|
18820
19224
|
init_injected_mcp();
|
|
18821
19225
|
|
|
19226
|
+
// src/agents/user-mcp-config.ts
|
|
19227
|
+
var import_node_fs42 = require("fs");
|
|
19228
|
+
var import_node_os12 = require("os");
|
|
19229
|
+
var import_node_path39 = require("path");
|
|
19230
|
+
init_paths();
|
|
19231
|
+
init_injected_mcp();
|
|
19232
|
+
function userCursorMcpConfigPath() {
|
|
19233
|
+
return (0, import_node_path39.join)((0, import_node_os12.homedir)(), ".cursor", "mcp.json");
|
|
19234
|
+
}
|
|
19235
|
+
function userClaudeMcpConfigPath() {
|
|
19236
|
+
return (0, import_node_path39.join)((0, import_node_os12.homedir)(), ".claude.json");
|
|
19237
|
+
}
|
|
19238
|
+
function asObject(value) {
|
|
19239
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
19240
|
+
return { ...value };
|
|
19241
|
+
}
|
|
19242
|
+
function stripElectronSpawnEnv(env) {
|
|
19243
|
+
if (!env) return void 0;
|
|
19244
|
+
const next = { ...env };
|
|
19245
|
+
delete next.ELECTRON_RUN_AS_NODE;
|
|
19246
|
+
delete next.ELECTRON_RUN_AS_NODE;
|
|
19247
|
+
return Object.keys(next).length > 0 ? next : void 0;
|
|
19248
|
+
}
|
|
19249
|
+
function mergeSideboardIntoMcpServersJson(existing, sideboard) {
|
|
19250
|
+
const root = asObject(existing);
|
|
19251
|
+
const servers = asObject(root.mcpServers);
|
|
19252
|
+
const env = stripElectronSpawnEnv(sideboard.env);
|
|
19253
|
+
servers.sideboard = {
|
|
19254
|
+
type: "stdio",
|
|
19255
|
+
command: sideboard.command,
|
|
19256
|
+
...sideboard.args && sideboard.args.length > 0 ? { args: sideboard.args } : {},
|
|
19257
|
+
...env ? { env } : {}
|
|
19258
|
+
};
|
|
19259
|
+
return { ...root, mcpServers: servers };
|
|
19260
|
+
}
|
|
19261
|
+
function writeMergedMcpServersJson(configPath, sideboard) {
|
|
19262
|
+
let existing = {};
|
|
19263
|
+
if ((0, import_node_fs42.existsSync)(configPath)) {
|
|
19264
|
+
try {
|
|
19265
|
+
existing = JSON.parse((0, import_node_fs42.readFileSync)(configPath, "utf8"));
|
|
19266
|
+
} catch {
|
|
19267
|
+
existing = {};
|
|
19268
|
+
}
|
|
19269
|
+
}
|
|
19270
|
+
const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
|
|
19271
|
+
(0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(configPath), { recursive: true });
|
|
19272
|
+
(0, import_node_fs42.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
|
|
19273
|
+
`);
|
|
19274
|
+
}
|
|
19275
|
+
function launchFromResolved(server) {
|
|
19276
|
+
return {
|
|
19277
|
+
command: server.command,
|
|
19278
|
+
args: server.args,
|
|
19279
|
+
env: {
|
|
19280
|
+
...server.env ?? {},
|
|
19281
|
+
SIDEBOARD_APP_DATA: appDataDir()
|
|
19282
|
+
}
|
|
19283
|
+
};
|
|
19284
|
+
}
|
|
19285
|
+
async function registerPackagedUserMcpClients() {
|
|
19286
|
+
const launch = launchFromResolved(await resolveSideboardMcpServer());
|
|
19287
|
+
const cursor = userCursorMcpConfigPath();
|
|
19288
|
+
writeMergedMcpServersJson(cursor, launch);
|
|
19289
|
+
const claude = userClaudeMcpConfigPath();
|
|
19290
|
+
if ((0, import_node_fs42.existsSync)(claude)) {
|
|
19291
|
+
writeMergedMcpServersJson(claude, launch);
|
|
19292
|
+
return { cursor, claude };
|
|
19293
|
+
}
|
|
19294
|
+
return { cursor };
|
|
19295
|
+
}
|
|
19296
|
+
|
|
18822
19297
|
// src/slack/oauth.ts
|
|
18823
19298
|
var import_node_crypto10 = require("crypto");
|
|
18824
19299
|
init_app_settings();
|
|
@@ -19593,15 +20068,10 @@ function connectSession2(ws, opts, log) {
|
|
|
19593
20068
|
}
|
|
19594
20069
|
|
|
19595
20070
|
// src/slack/listen.ts
|
|
19596
|
-
var SLACK_LISTEN_BUSY_REPLY = [
|
|
19597
|
-
"Sideboard is busy with an in-progress turn.",
|
|
19598
|
-
"I did not start a new request.",
|
|
19599
|
-
'Send "stop" to interrupt, or try again when idle.'
|
|
19600
|
-
].join(" ");
|
|
19601
20071
|
var SLACK_LISTEN_STOPPED_REPLY = "Sideboard stopped the in-progress turn. Send another message when you want to continue.";
|
|
19602
20072
|
var SLACK_LISTEN_TIMEOUT_REPLY = [
|
|
19603
20073
|
"Sideboard timed out waiting for the local agent turn to finish.",
|
|
19604
|
-
'Send
|
|
20074
|
+
'Send another message to interrupt and retry, or send "stop".'
|
|
19605
20075
|
].join(" ");
|
|
19606
20076
|
var handleChain = Promise.resolve();
|
|
19607
20077
|
function enqueueHandle(fn) {
|
|
@@ -19615,6 +20085,30 @@ function enqueueHandle(fn) {
|
|
|
19615
20085
|
function refreshWorkspaces2() {
|
|
19616
20086
|
return getOrchestrator().listWorkspaces();
|
|
19617
20087
|
}
|
|
20088
|
+
function slackInboundSuperseded(opts) {
|
|
20089
|
+
if (opts.inboundGeneration === void 0 || !opts.currentInboundGeneration) {
|
|
20090
|
+
return false;
|
|
20091
|
+
}
|
|
20092
|
+
return opts.currentInboundGeneration() !== opts.inboundGeneration;
|
|
20093
|
+
}
|
|
20094
|
+
function interruptSlackCoordinatorForInbound(msg, agent, log = () => void 0) {
|
|
20095
|
+
const userId = msg.userId?.trim();
|
|
20096
|
+
if (!userId) return false;
|
|
20097
|
+
const coordinator = ensureSlackCoordinator(msg.teamId, userId, agent);
|
|
20098
|
+
const fresh = readThread(coordinator.id) ?? coordinator;
|
|
20099
|
+
if (fresh.status !== "running" && fresh.status !== "queued") return false;
|
|
20100
|
+
try {
|
|
20101
|
+
getOrchestrator().stop(fresh.id, { clearQueue: true });
|
|
20102
|
+
log(
|
|
20103
|
+
`interrupt ${msg.kind} ${msg.ts} \u2192 coordinator ${fresh.id.slice(0, 8)} (${fresh.status})`
|
|
20104
|
+
);
|
|
20105
|
+
return true;
|
|
20106
|
+
} catch (err) {
|
|
20107
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
20108
|
+
log(`interrupt ${msg.ts}: ${errMsg}`);
|
|
20109
|
+
return false;
|
|
20110
|
+
}
|
|
20111
|
+
}
|
|
19618
20112
|
function formatSlackInboundPrompt(msg) {
|
|
19619
20113
|
const kind = msg.kind === "mention" ? "Slack @mention" : "Slack DM";
|
|
19620
20114
|
return `${kind}
|
|
@@ -19745,7 +20239,13 @@ async function relayCoordinatorReplyToSlack(threadId, opts) {
|
|
|
19745
20239
|
}
|
|
19746
20240
|
async function handleSlackInbound(msg, opts) {
|
|
19747
20241
|
const log = opts.onLog ?? (() => void 0);
|
|
19748
|
-
|
|
20242
|
+
if (!opts.skipAck) {
|
|
20243
|
+
await ackSlackInboundSeen(msg, opts);
|
|
20244
|
+
}
|
|
20245
|
+
if (slackInboundSuperseded(opts)) {
|
|
20246
|
+
log(`skip superseded ${msg.kind} ${msg.ts}`);
|
|
20247
|
+
return;
|
|
20248
|
+
}
|
|
19749
20249
|
const agent = coerceOrchestratorAgent(opts.agent ?? getDefaultAgent());
|
|
19750
20250
|
const workspaces = refreshWorkspaces2();
|
|
19751
20251
|
for (const ws of workspaces) {
|
|
@@ -19757,25 +20257,31 @@ async function handleSlackInbound(msg, opts) {
|
|
|
19757
20257
|
log(`skip ${msg.kind} ${msg.ts}: missing Slack user id`);
|
|
19758
20258
|
return;
|
|
19759
20259
|
}
|
|
20260
|
+
if (slackInboundSuperseded(opts)) {
|
|
20261
|
+
log(`skip superseded ${msg.kind} ${msg.ts}`);
|
|
20262
|
+
return;
|
|
20263
|
+
}
|
|
19760
20264
|
const coordinator = ensureSlackCoordinator(msg.teamId, userId, agent);
|
|
19761
|
-
|
|
20265
|
+
let fresh = readThread(coordinator.id) ?? coordinator;
|
|
19762
20266
|
if (isSlackStopCommand(msg.text)) {
|
|
19763
20267
|
try {
|
|
19764
|
-
getOrchestrator().stop(fresh.id);
|
|
20268
|
+
getOrchestrator().stop(fresh.id, { clearQueue: true });
|
|
19765
20269
|
log(`stop ${msg.kind} ${msg.ts} \u2192 coordinator ${fresh.id.slice(0, 8)}`);
|
|
19766
20270
|
} catch (err) {
|
|
19767
20271
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
19768
20272
|
log(`stop ${msg.ts}: ${errMsg}`);
|
|
19769
20273
|
}
|
|
20274
|
+
if (slackInboundSuperseded(opts)) {
|
|
20275
|
+
log(`skip superseded stop reply ${msg.ts}`);
|
|
20276
|
+
return;
|
|
20277
|
+
}
|
|
19770
20278
|
await postSlackReply(msg, SLACK_LISTEN_STOPPED_REPLY, opts);
|
|
19771
20279
|
log(`replied stopped ${msg.ts}`);
|
|
19772
20280
|
return;
|
|
19773
20281
|
}
|
|
19774
20282
|
if (fresh.status === "running" || fresh.status === "queued") {
|
|
19775
|
-
|
|
19776
|
-
|
|
19777
|
-
log(`replied busy ${msg.ts}`);
|
|
19778
|
-
return;
|
|
20283
|
+
interruptSlackCoordinatorForInbound(msg, agent, log);
|
|
20284
|
+
fresh = readThread(coordinator.id) ?? coordinator;
|
|
19779
20285
|
}
|
|
19780
20286
|
log(
|
|
19781
20287
|
`run ${msg.kind} ${msg.ts} user ${userId} \u2192 coordinator ${fresh.id.slice(0, 8)} (${inventory.length} workspace${inventory.length === 1 ? "" : "s"})`
|
|
@@ -19792,8 +20298,21 @@ async function handleSlackInbound(msg, opts) {
|
|
|
19792
20298
|
try {
|
|
19793
20299
|
await orch.send(fresh.id, prompt);
|
|
19794
20300
|
await orch.waitForTurn(fresh.id, 14 * 60 * 1e3);
|
|
20301
|
+
if (slackInboundSuperseded(opts)) {
|
|
20302
|
+
log(`turn finished ${msg.ts} (superseded)`);
|
|
20303
|
+
return;
|
|
20304
|
+
}
|
|
20305
|
+
const after = readThread(fresh.id);
|
|
20306
|
+
if (after?.status === "stopped") {
|
|
20307
|
+
log(`turn finished ${msg.ts} (interrupted, skip post)`);
|
|
20308
|
+
return;
|
|
20309
|
+
}
|
|
19795
20310
|
reply = orch.getTurnResult(fresh.id).text.trim();
|
|
19796
20311
|
} catch (err) {
|
|
20312
|
+
if (slackInboundSuperseded(opts)) {
|
|
20313
|
+
log(`turn error ${msg.ts} (superseded)`);
|
|
20314
|
+
return;
|
|
20315
|
+
}
|
|
19797
20316
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
19798
20317
|
const timedOut = /timed out|timeout/i.test(errMsg);
|
|
19799
20318
|
const errorReply = timedOut ? SLACK_LISTEN_TIMEOUT_REPLY : `Sideboard coordinator error: ${errMsg}`;
|
|
@@ -19841,19 +20360,35 @@ async function runSlackListen(opts = {}) {
|
|
|
19841
20360
|
const log = opts.onLog ?? console.log;
|
|
19842
20361
|
const connected = listSlackWorkspacesRaw();
|
|
19843
20362
|
const orch = getOrchestrator();
|
|
20363
|
+
const agent = coerceOrchestratorAgent(opts.agent ?? getDefaultAgent());
|
|
20364
|
+
let inboundGeneration = 0;
|
|
19844
20365
|
const off = orch.on((event) => {
|
|
19845
20366
|
if (event.type !== "turn_finished") return;
|
|
19846
20367
|
void relayCoordinatorReplyToSlack(event.threadId, opts);
|
|
19847
20368
|
});
|
|
19848
|
-
const onInbound = (msg) =>
|
|
20369
|
+
const onInbound = (msg) => {
|
|
19849
20370
|
if (!isInboundForThisDesktop(msg)) {
|
|
19850
20371
|
log(
|
|
19851
20372
|
`skip ${msg.kind} ${msg.ts}: Slack user ${msg.userId ?? "?"} is not connected on this Mac`
|
|
19852
20373
|
);
|
|
19853
20374
|
return;
|
|
19854
20375
|
}
|
|
19855
|
-
|
|
19856
|
-
|
|
20376
|
+
const generation = ++inboundGeneration;
|
|
20377
|
+
void ackSlackInboundSeen(msg, opts);
|
|
20378
|
+
interruptSlackCoordinatorForInbound(msg, agent, log);
|
|
20379
|
+
return enqueueHandle(async () => {
|
|
20380
|
+
if (generation !== inboundGeneration) {
|
|
20381
|
+
log(`skip superseded ${msg.kind} ${msg.ts}`);
|
|
20382
|
+
return;
|
|
20383
|
+
}
|
|
20384
|
+
await handleSlackInbound(msg, {
|
|
20385
|
+
...opts,
|
|
20386
|
+
skipAck: true,
|
|
20387
|
+
inboundGeneration: generation,
|
|
20388
|
+
currentInboundGeneration: () => inboundGeneration
|
|
20389
|
+
});
|
|
20390
|
+
});
|
|
20391
|
+
};
|
|
19857
20392
|
try {
|
|
19858
20393
|
const relay = (opts.relayUrl ?? slackRelayUrl()).trim();
|
|
19859
20394
|
if (!relay) {
|
|
@@ -20125,9 +20660,9 @@ var import_node_http3 = require("http");
|
|
|
20125
20660
|
var import_ws3 = require("ws");
|
|
20126
20661
|
|
|
20127
20662
|
// src/slack/relay-static.ts
|
|
20128
|
-
var
|
|
20663
|
+
var import_node_fs43 = require("fs");
|
|
20129
20664
|
var import_promises = require("fs/promises");
|
|
20130
|
-
var
|
|
20665
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
20131
20666
|
var TYPES = {
|
|
20132
20667
|
".css": "text/css; charset=utf-8",
|
|
20133
20668
|
".html": "text/html; charset=utf-8",
|
|
@@ -20158,9 +20693,9 @@ function resolveStaticPath(root, requestUrl) {
|
|
|
20158
20693
|
return null;
|
|
20159
20694
|
}
|
|
20160
20695
|
if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
|
|
20161
|
-
const rootResolved =
|
|
20162
|
-
const candidate =
|
|
20163
|
-
if (candidate !== rootResolved && !candidate.startsWith(rootResolved +
|
|
20696
|
+
const rootResolved = import_node_path40.default.resolve(root);
|
|
20697
|
+
const candidate = import_node_path40.default.resolve(rootResolved, `.${pathname}`);
|
|
20698
|
+
if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path40.default.sep)) {
|
|
20164
20699
|
return null;
|
|
20165
20700
|
}
|
|
20166
20701
|
return candidate;
|
|
@@ -20174,7 +20709,7 @@ async function fileSize(file) {
|
|
|
20174
20709
|
}
|
|
20175
20710
|
}
|
|
20176
20711
|
function sendFile(req, res, file, size) {
|
|
20177
|
-
const ext =
|
|
20712
|
+
const ext = import_node_path40.default.extname(file).toLowerCase();
|
|
20178
20713
|
res.writeHead(200, {
|
|
20179
20714
|
"Content-Type": TYPES[ext] ?? "application/octet-stream",
|
|
20180
20715
|
"Content-Length": size,
|
|
@@ -20184,7 +20719,7 @@ function sendFile(req, res, file, size) {
|
|
|
20184
20719
|
res.end();
|
|
20185
20720
|
return true;
|
|
20186
20721
|
}
|
|
20187
|
-
(0,
|
|
20722
|
+
(0, import_node_fs43.createReadStream)(file).pipe(res);
|
|
20188
20723
|
return true;
|
|
20189
20724
|
}
|
|
20190
20725
|
async function tryServeStatic(req, res, root) {
|
|
@@ -20193,7 +20728,7 @@ async function tryServeStatic(req, res, root) {
|
|
|
20193
20728
|
if (!candidate) return false;
|
|
20194
20729
|
const direct = await fileSize(candidate);
|
|
20195
20730
|
if (direct != null) return sendFile(req, res, candidate, direct);
|
|
20196
|
-
const asIndex =
|
|
20731
|
+
const asIndex = import_node_path40.default.join(candidate, "index.html");
|
|
20197
20732
|
const indexSize = await fileSize(asIndex);
|
|
20198
20733
|
if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
|
|
20199
20734
|
return false;
|
|
@@ -20456,7 +20991,6 @@ async function startSlackRelayServer(opts) {
|
|
|
20456
20991
|
SIDEBOARD_FORCE_STOP,
|
|
20457
20992
|
SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
20458
20993
|
SIDEBOARD_MCP_PROFILE_ENV,
|
|
20459
|
-
SLACK_LISTEN_BUSY_REPLY,
|
|
20460
20994
|
SLACK_LISTEN_STOPPED_REPLY,
|
|
20461
20995
|
SLACK_LISTEN_TIMEOUT_REPLY,
|
|
20462
20996
|
SLACK_OAUTH_CANCELLED,
|
|
@@ -20526,6 +21060,7 @@ async function startSlackRelayServer(opts) {
|
|
|
20526
21060
|
cleanupOrphanWorktrees,
|
|
20527
21061
|
cloneRepoIntoSideboard,
|
|
20528
21062
|
codexAdapter,
|
|
21063
|
+
codexSandboxWritableRootsArgs,
|
|
20529
21064
|
codexUnattendedGitConfigArgs,
|
|
20530
21065
|
coerceOrchestratorAgent,
|
|
20531
21066
|
collectTakenTeamSlugs,
|
|
@@ -20642,6 +21177,7 @@ async function startSlackRelayServer(opts) {
|
|
|
20642
21177
|
getPr,
|
|
20643
21178
|
getPrChecks,
|
|
20644
21179
|
getPrDetails,
|
|
21180
|
+
getPrForHeadBranch,
|
|
20645
21181
|
getPrMeta,
|
|
20646
21182
|
getPrStack,
|
|
20647
21183
|
getRepoSetupInfo,
|
|
@@ -20672,12 +21208,14 @@ async function startSlackRelayServer(opts) {
|
|
|
20672
21208
|
initializeGitRepository,
|
|
20673
21209
|
inspectGitWorktree,
|
|
20674
21210
|
installAgent,
|
|
21211
|
+
interruptSlackCoordinatorForInbound,
|
|
20675
21212
|
isAskUserToolName,
|
|
20676
21213
|
isBrightsyConnected,
|
|
20677
21214
|
isBrightsyNdjsonLine,
|
|
20678
21215
|
isCloudCoordinatorThread,
|
|
20679
21216
|
isConductorBundledCli,
|
|
20680
21217
|
isCursorAutoModel,
|
|
21218
|
+
isDefaultishSourceRef,
|
|
20681
21219
|
isDirty,
|
|
20682
21220
|
isGhRateLimitError,
|
|
20683
21221
|
isGlobalRepoPath,
|
|
@@ -20744,8 +21282,10 @@ async function startSlackRelayServer(opts) {
|
|
|
20744
21282
|
maybeCompactContext,
|
|
20745
21283
|
mcpAllowTools,
|
|
20746
21284
|
mcpAuthWarnings,
|
|
21285
|
+
mergeAgentGitAuthEnv,
|
|
20747
21286
|
mergePr,
|
|
20748
21287
|
mergePrStack,
|
|
21288
|
+
mergeSideboardIntoMcpServersJson,
|
|
20749
21289
|
mergeUsage,
|
|
20750
21290
|
nextPastedTextName,
|
|
20751
21291
|
nextThinkingEffort,
|
|
@@ -20796,6 +21336,7 @@ async function startSlackRelayServer(opts) {
|
|
|
20796
21336
|
recordSlackOutboundWatch,
|
|
20797
21337
|
refreshGitHubAuth,
|
|
20798
21338
|
refreshSlackReplyBadges,
|
|
21339
|
+
registerPackagedUserMcpClients,
|
|
20799
21340
|
releaseCaffeinateHoldForThread,
|
|
20800
21341
|
removeWorkspace,
|
|
20801
21342
|
removeWorktree,
|
|
@@ -20804,9 +21345,11 @@ async function startSlackRelayServer(opts) {
|
|
|
20804
21345
|
requestReview,
|
|
20805
21346
|
requireAgent,
|
|
20806
21347
|
resetGhStackDetectCache,
|
|
21348
|
+
resetGithubAgentTokenMemo,
|
|
20807
21349
|
resolveAgentExecutable,
|
|
20808
21350
|
resolveAgentGitAuthEnv,
|
|
20809
21351
|
resolveClaudeExecutable,
|
|
21352
|
+
resolveCodexGitWritableRoots,
|
|
20810
21353
|
resolveCommandBinarySync,
|
|
20811
21354
|
resolveConductorCursorAgentId,
|
|
20812
21355
|
resolveCursorModelId,
|
|
@@ -20823,6 +21366,7 @@ async function startSlackRelayServer(opts) {
|
|
|
20823
21366
|
resolveNewThreadOptions,
|
|
20824
21367
|
resolvePlanMarkdown,
|
|
20825
21368
|
resolvePrSelector,
|
|
21369
|
+
resolvePrSelectors,
|
|
20826
21370
|
resolveQuotaFallbackAgent,
|
|
20827
21371
|
resolveRepoRoot,
|
|
20828
21372
|
resolveReviewGuidelines,
|
|
@@ -20845,6 +21389,7 @@ async function startSlackRelayServer(opts) {
|
|
|
20845
21389
|
sanitizeMcpServerName,
|
|
20846
21390
|
saveAppSettings,
|
|
20847
21391
|
saveLinearOAuth,
|
|
21392
|
+
scrubGithubTokensFromChildEnv,
|
|
20848
21393
|
secureFileUnlocksWith,
|
|
20849
21394
|
setCaffeinateHold,
|
|
20850
21395
|
setHttpFetchImpl,
|
|
@@ -20915,7 +21460,10 @@ async function startSlackRelayServer(opts) {
|
|
|
20915
21460
|
updateLinearIssue,
|
|
20916
21461
|
updateOpencodeSettings,
|
|
20917
21462
|
updateThread,
|
|
21463
|
+
userClaudeMcpConfigPath,
|
|
21464
|
+
userCursorMcpConfigPath,
|
|
20918
21465
|
validateLinearApiKey,
|
|
21466
|
+
warmGithubAgentAuth,
|
|
20919
21467
|
withAgentInstructions,
|
|
20920
21468
|
withExportedPath,
|
|
20921
21469
|
withThreadLock,
|