@sideboard-ai/core 0.1.66 → 0.1.68

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.
Files changed (35) hide show
  1. package/dist/{agents-EWFD765A.js → agents-JBD7IAGK.js} +10 -6
  2. package/dist/{agents-MD7SCFYX.js → agents-PE3RHQS5.js} +10 -6
  3. package/dist/{chunk-BBEH2CJE.js → chunk-47RBLBRK.js} +22 -7
  4. package/dist/{chunk-IFAU2DEY.js → chunk-6Q7H6SMX.js} +22 -7
  5. package/dist/{chunk-5AG5BUQN.js → chunk-AE5VBOFE.js} +14 -3
  6. package/dist/{chunk-DZYMNW2A.js → chunk-BTL7EMGT.js} +4 -4
  7. package/dist/{chunk-TXQ6K2GR.js → chunk-D4DPQ552.js} +14 -3
  8. package/dist/{chunk-PESJDZTB.js → chunk-DPDGMMGI.js} +2 -2
  9. package/dist/{chunk-R7GUDEPY.js → chunk-EEBDVLDK.js} +22 -20
  10. package/dist/{chunk-LRBRQFBU.js → chunk-N5LMEP65.js} +1 -1
  11. package/dist/{chunk-DNPP7QMK.js → chunk-OICHV4DH.js} +2 -2
  12. package/dist/{chunk-HTOTTJJX.js → chunk-QQC2D4MY.js} +2 -2
  13. package/dist/{chunk-I2KGRAXC.js → chunk-REKGFVUX.js} +22 -20
  14. package/dist/{chunk-YTNLOJPK.js → chunk-ROXEENBT.js} +2 -2
  15. package/dist/{chunk-EVD4KNKR.js → chunk-VROPG6QF.js} +1 -1
  16. package/dist/{chunk-AKPEXIKK.js → chunk-VX6ACNXS.js} +1 -1
  17. package/dist/{connected-teams-CHXO5FFA.js → connected-teams-35EIRJCP.js} +2 -2
  18. package/dist/{connected-teams-GJTESSTX.js → connected-teams-ZRS53OAT.js} +2 -2
  19. package/dist/{coordinator-prompt-ILSULI7C.js → coordinator-prompt-HD6IMCKS.js} +3 -3
  20. package/dist/{coordinator-prompt-E5UGSJES.js → coordinator-prompt-YZYZ5P6P.js} +3 -3
  21. package/dist/{global-workspace-44UG64NA.js → global-workspace-7P5NG3JZ.js} +4 -4
  22. package/dist/{global-workspace-5PM5LA6E.js → global-workspace-Z6GF7D2K.js} +4 -4
  23. package/dist/index.cjs +401 -163
  24. package/dist/index.d.cts +33 -3
  25. package/dist/index.d.ts +33 -3
  26. package/dist/index.js +368 -157
  27. package/dist/mcp/run-stdio.cjs +397 -163
  28. package/dist/mcp/run-stdio.js +363 -156
  29. package/dist/{run-74S2NZWB.js → run-A4RHY7HH.js} +1 -1
  30. package/dist/{run-JLN5JK7Q.js → run-V2WZUMJA.js} +1 -1
  31. package/dist/{workspaces-OVBCSS5Y.js → workspaces-BWJNGEE6.js} +5 -5
  32. package/dist/{workspaces-RXFXQRRF.js → workspaces-O6EZGKQK.js} +5 -5
  33. package/dist/{worktree-S2N63FLV.js → worktree-VDXLUOWR.js} +2 -2
  34. package/dist/{worktree-K2JB53R5.js → worktree-ZPSKEZFE.js} +2 -2
  35. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -2163,6 +2163,13 @@ function prependPathDir(env, dir) {
2163
2163
  }
2164
2164
  env.PATH = [dir, ...parts].join(import_node_path5.delimiter);
2165
2165
  }
2166
+ function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os4.homedir)()) {
2167
+ return (0, import_node_path5.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
2168
+ }
2169
+ function isConductorBundledCli(filePath) {
2170
+ const p = (filePath ?? "").replace(/\\/g, "/");
2171
+ return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
2172
+ }
2166
2173
  function ensureAgentPath(env = process.env) {
2167
2174
  const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
2168
2175
  const current = env.PATH ?? "";
@@ -2171,7 +2178,9 @@ function ensureAgentPath(env = process.env) {
2171
2178
  const extras = [
2172
2179
  ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path5.join)(home, rel)),
2173
2180
  "/opt/homebrew/bin",
2174
- "/usr/local/bin"
2181
+ "/usr/local/bin",
2182
+ // Keep after Homebrew/npm so a user-installed CLI still wins.
2183
+ conductorBundledBinDir(home)
2175
2184
  ];
2176
2185
  for (const dir of extras.reverse()) {
2177
2186
  if (!dir || seen.has(dir) || !(0, import_node_fs5.existsSync)(dir)) continue;
@@ -2218,7 +2227,7 @@ function withExportedPath(command, pathValue) {
2218
2227
  const trimmed = command.trim();
2219
2228
  if (!trimmed) return trimmed;
2220
2229
  if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
2221
- return `export PATH=${posixShellSingleQuote(pathValue)}; ${trimmed}`;
2230
+ return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
2222
2231
  }
2223
2232
  var import_node_fs5, import_node_child_process, import_node_os4, import_node_path5, EXTRA_BIN_DIRS;
2224
2233
  var init_path = __esm({
@@ -2286,7 +2295,7 @@ async function git(args, cwd, opts) {
2286
2295
  prefix.push("-c", `${key}=${value}`);
2287
2296
  }
2288
2297
  }
2289
- return run("git", [...prefix, ...args], {
2298
+ return run("git", ["--no-pager", ...prefix, ...args], {
2290
2299
  cwd,
2291
2300
  reject: opts?.reject,
2292
2301
  timeoutMs: opts?.timeoutMs,
@@ -2789,7 +2798,7 @@ async function originGhRepoEnv(cwd) {
2789
2798
  const slug = await resolveGithubRepoSlug(cwd);
2790
2799
  return slug ? { GH_REPO: slug } : {};
2791
2800
  }
2792
- async function resolveDefaultBranch(repoPath) {
2801
+ async function resolveDefaultBranch(repoPath, opts) {
2793
2802
  const viaOrigin = await git(
2794
2803
  ["symbolic-ref", "refs/remotes/origin/HEAD"],
2795
2804
  repoPath,
@@ -2798,22 +2807,24 @@ async function resolveDefaultBranch(repoPath) {
2798
2807
  if (viaOrigin.exitCode === 0 && viaOrigin.stdout.trim()) {
2799
2808
  return viaOrigin.stdout.trim().replace(/^refs\/remotes\/origin\//, "");
2800
2809
  }
2801
- const slug = await resolveGithubRepoSlug(repoPath);
2802
- const viaGh = await gh(
2803
- [
2804
- "repo",
2805
- "view",
2806
- ...slug ? ["--repo", slug] : [],
2807
- "--json",
2808
- "defaultBranchRef",
2809
- "--jq",
2810
- ".defaultBranchRef.name"
2811
- ],
2812
- repoPath,
2813
- { reject: false }
2814
- );
2815
- if (viaGh.exitCode === 0 && viaGh.stdout.trim()) {
2816
- return viaGh.stdout.trim();
2810
+ if (opts?.network !== false) {
2811
+ const slug = await resolveGithubRepoSlug(repoPath);
2812
+ const viaGh = await gh(
2813
+ [
2814
+ "repo",
2815
+ "view",
2816
+ ...slug ? ["--repo", slug] : [],
2817
+ "--json",
2818
+ "defaultBranchRef",
2819
+ "--jq",
2820
+ ".defaultBranchRef.name"
2821
+ ],
2822
+ repoPath,
2823
+ { reject: false, timeoutMs: 8e3 }
2824
+ );
2825
+ if (viaGh.exitCode === 0 && viaGh.stdout.trim()) {
2826
+ return viaGh.stdout.trim();
2827
+ }
2817
2828
  }
2818
2829
  for (const candidate of ["main", "master"]) {
2819
2830
  const check = await git(
@@ -3465,11 +3476,11 @@ async function listWorktrees(repoPath) {
3465
3476
  return entries;
3466
3477
  }
3467
3478
  async function isDirty(worktreePath) {
3468
- const { stdout } = await git(["status", "--porcelain", "-uall"], worktreePath);
3479
+ const { stdout } = await git(["status", "--porcelain"], worktreePath);
3469
3480
  for (const line of stdout.split("\n")) {
3470
3481
  if (!line.trim()) continue;
3471
3482
  const rel = porcelainStatusPath(line);
3472
- if (!rel || isSideboardScratchPath(rel)) continue;
3483
+ if (!rel || isSideboardScratchPath(rel) || rel === ".sideboard") continue;
3473
3484
  return true;
3474
3485
  }
3475
3486
  return false;
@@ -7078,6 +7089,11 @@ async function openInSystemTerminal(command) {
7078
7089
  `No terminal found to run: ${trimmed}. Install gnome-terminal (or similar), or run the command manually.`
7079
7090
  );
7080
7091
  }
7092
+ async function whichCli(bin) {
7093
+ const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
7094
+ if (which.exitCode !== 0) return null;
7095
+ return which.stdout.trim().split(/\r?\n/).find(Boolean) ?? null;
7096
+ }
7081
7097
  async function installAgent(agent) {
7082
7098
  const info = getAgentSetupInfo(agent);
7083
7099
  if (info.kind === "bundled-sdk" || info.kind === "api-key") {
@@ -7099,6 +7115,17 @@ async function installAgent(agent) {
7099
7115
  };
7100
7116
  }
7101
7117
  enrichPathWithNpmGlobalBin();
7118
+ const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
7119
+ if (cliBin) {
7120
+ const existing = await whichCli(cliBin);
7121
+ if (existing) {
7122
+ return {
7123
+ ok: true,
7124
+ command: existing,
7125
+ message: isConductorBundledCli(existing) ? `Using Conductor\u2019s ${cliBin} at ${existing}. No extra install \u2014 Log in only if auth is missing.` : `Already on PATH: ${existing}`
7126
+ };
7127
+ }
7128
+ }
7102
7129
  const result = await run("npm", ["install", "-g", info.npmPackage], { reject: false });
7103
7130
  const ok = result.exitCode === 0;
7104
7131
  if (!ok) {
@@ -7125,11 +7152,9 @@ async function installAgent(agent) {
7125
7152
  }
7126
7153
  }
7127
7154
  enrichPathWithNpmGlobalBin();
7128
- const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
7129
7155
  let binPath = null;
7130
7156
  if (cliBin) {
7131
- const which = await run("which", [cliBin], { reject: false, timeoutMs: 3e3 });
7132
- binPath = which.exitCode === 0 ? which.stdout.trim().split(/\r?\n/).find(Boolean) ?? null : null;
7157
+ binPath = await whichCli(cliBin);
7133
7158
  }
7134
7159
  return {
7135
7160
  ok: true,
@@ -7239,6 +7264,7 @@ __export(agents_exports, {
7239
7264
  claudeAdapter: () => claudeAdapter,
7240
7265
  codexAdapter: () => codexAdapter,
7241
7266
  coerceOrchestratorAgent: () => coerceOrchestratorAgent,
7267
+ conductorBundledBinDir: () => conductorBundledBinDir,
7242
7268
  cursorAdapter: () => cursorAdapter,
7243
7269
  cursorSdkMessageToEvents: () => cursorSdkMessageToEvents,
7244
7270
  decodeBrightsyTarget: () => decodeBrightsyTarget,
@@ -7248,6 +7274,7 @@ __export(agents_exports, {
7248
7274
  getAdapter: () => getAdapter,
7249
7275
  getAgentSetupInfo: () => getAgentSetupInfo,
7250
7276
  installAgent: () => installAgent,
7277
+ isConductorBundledCli: () => isConductorBundledCli,
7251
7278
  isCursorAutoModel: () => isCursorAutoModel,
7252
7279
  isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
7253
7280
  isSessionQuotaLimit: () => isSessionQuotaLimit,
@@ -7593,6 +7620,7 @@ __export(index_exports, {
7593
7620
  coerceOrchestratorAgent: () => coerceOrchestratorAgent,
7594
7621
  collectTakenTeamSlugs: () => collectTakenTeamSlugs,
7595
7622
  commitAll: () => commitAll,
7623
+ conductorBundledBinDir: () => conductorBundledBinDir,
7596
7624
  conductorDbPath: () => conductorDbPath,
7597
7625
  confirmLand: () => confirmLand,
7598
7626
  connectBrightsyTeam: () => connectBrightsyTeam,
@@ -7704,6 +7732,7 @@ __export(index_exports, {
7704
7732
  isBrightsyConnected: () => isBrightsyConnected,
7705
7733
  isBrightsyNdjsonLine: () => isBrightsyNdjsonLine,
7706
7734
  isCloudCoordinatorThread: () => isCloudCoordinatorThread,
7735
+ isConductorBundledCli: () => isConductorBundledCli,
7707
7736
  isCursorAutoModel: () => isCursorAutoModel,
7708
7737
  isDirty: () => isDirty,
7709
7738
  isGhRateLimitError: () => isGhRateLimitError,
@@ -9154,24 +9183,25 @@ function capPatch(patch, maxHunk) {
9154
9183
 
9155
9184
  \u2026 truncated (${patch.length - maxHunk} more chars)`;
9156
9185
  }
9186
+ var mergeBaseCache = /* @__PURE__ */ new Map();
9187
+ var MERGE_BASE_TTL_MS = 45e3;
9157
9188
  async function resolveMergeBase(worktreePath, base, repoPath) {
9158
9189
  const baseRef = await resolveDiffBaseRef(worktreePath, base, repoPath);
9190
+ const cacheKey = `${worktreePath}\0${baseRef}`;
9191
+ const hit = mergeBaseCache.get(cacheKey);
9192
+ if (hit && Date.now() - hit.at < MERGE_BASE_TTL_MS) return hit.value;
9159
9193
  const { stdout } = await git(["merge-base", baseRef, "HEAD"], worktreePath, {
9160
9194
  reject: false
9161
9195
  });
9162
- const mb = stdout.trim();
9163
- return mb || baseRef;
9196
+ const mb = stdout.trim() || baseRef;
9197
+ mergeBaseCache.set(cacheKey, { at: Date.now(), value: mb });
9198
+ return mb;
9164
9199
  }
9165
9200
  async function countUnpushedCommits(worktreePath) {
9166
9201
  const head = await git(["rev-parse", "--abbrev-ref", "HEAD"], worktreePath, {
9167
9202
  reject: false
9168
9203
  });
9169
9204
  const branch = head.stdout.trim();
9170
- if (branch && branch !== "HEAD") {
9171
- await git(["fetch", "origin", branch, "--quiet"], worktreePath, {
9172
- reject: false
9173
- });
9174
- }
9175
9205
  const upstream = await git(
9176
9206
  ["rev-list", "--count", "@{upstream}..HEAD"],
9177
9207
  worktreePath,
@@ -9204,11 +9234,37 @@ function splitCombinedDiff(stdout) {
9204
9234
  }
9205
9235
  return map;
9206
9236
  }
9237
+ function syntheticAddPatch(path, content, maxHunk) {
9238
+ const lines = content.split("\n");
9239
+ const body = lines.map((l) => `+${l}`).join("\n");
9240
+ const header = `diff --git a/${path} b/${path}
9241
+ new file mode 100644
9242
+ --- /dev/null
9243
+ +++ b/${path}
9244
+ @@ -0,0 +1,${lines.length} @@
9245
+ `;
9246
+ return {
9247
+ path,
9248
+ status: "A",
9249
+ patch: capPatch(`${header}${body}`, maxHunk),
9250
+ additions: lines.length,
9251
+ deletions: 0
9252
+ };
9253
+ }
9207
9254
  async function untrackedPatch(worktreePath, path, maxHunk) {
9255
+ const abs = (0, import_node_path17.join)(worktreePath, path);
9256
+ try {
9257
+ const st = (0, import_node_fs20.statSync)(abs);
9258
+ if (st.isFile() && st.size > maxHunk) {
9259
+ const buf = (0, import_node_fs20.readFileSync)(abs).subarray(0, maxHunk);
9260
+ return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
9261
+ }
9262
+ } catch {
9263
+ }
9208
9264
  const { stdout: patch } = await git(
9209
- ["diff", "--no-index", "--", "/dev/null", path],
9265
+ ["diff", "--no-ext-diff", "--no-color", "--no-index", "--", "/dev/null", path],
9210
9266
  worktreePath,
9211
- { reject: false }
9267
+ { reject: false, timeoutMs: 4e3 }
9212
9268
  );
9213
9269
  const normalized = patch.replace(/^diff --git a\/.+? b\/.+?$/m, `diff --git a/${path} b/${path}`).replace(/^--- .*$/m, "--- /dev/null").replace(/^\+\+\+ .*$/m, `+++ b/${path}`);
9214
9270
  const addLines = normalized.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++")).length;
@@ -9220,22 +9276,97 @@ async function untrackedPatch(worktreePath, path, maxHunk) {
9220
9276
  deletions: 0
9221
9277
  };
9222
9278
  }
9223
- async function listUntrackedPaths(worktreePath) {
9224
- const { stdout } = await git(
9225
- ["ls-files", "-z", "--others", "--exclude-standard"],
9226
- worktreePath,
9227
- { reject: false }
9228
- );
9279
+ async function listUntrackedPaths(worktreePath, path) {
9280
+ const args = ["ls-files", "-z", "--others", "--exclude-standard"];
9281
+ if (path) args.push("--", path);
9282
+ const { stdout } = await git(args, worktreePath, { reject: false });
9229
9283
  return stdout.split("\0").filter(Boolean).filter((p) => !isSideboardScratchPath(p));
9230
9284
  }
9231
- async function listUntrackedFiles(worktreePath, maxHunk) {
9232
- const paths = await listUntrackedPaths(worktreePath);
9233
- if (paths.length === 0) return [];
9234
- return Promise.all(paths.map((path) => untrackedPatch(worktreePath, path, maxHunk)));
9285
+ async function listUntrackedFiles(worktreePath, maxHunk, paths) {
9286
+ const list = paths ?? await listUntrackedPaths(worktreePath);
9287
+ if (list.length === 0) return [];
9288
+ return Promise.all(list.map((path) => untrackedPatch(worktreePath, path, maxHunk)));
9289
+ }
9290
+ function untrackedStubs(paths) {
9291
+ return paths.map((path) => ({
9292
+ path,
9293
+ status: "A",
9294
+ patch: "",
9295
+ additions: 0,
9296
+ deletions: 0
9297
+ }));
9298
+ }
9299
+ function pathspec(path) {
9300
+ return path ? ["--", path] : [];
9301
+ }
9302
+ function gitDiff(args, cwd, opts) {
9303
+ return git(["diff", "--no-ext-diff", "--no-color", ...args], cwd, {
9304
+ reject: false,
9305
+ timeoutMs: opts?.timeoutMs
9306
+ });
9307
+ }
9308
+ function fileFromPatch(path, patch, maxHunk) {
9309
+ let status = "M";
9310
+ if (/^new file mode /m.test(patch) || /^--- \/dev\/null/m.test(patch)) {
9311
+ status = "A";
9312
+ } else if (/^deleted file mode /m.test(patch) || /^\+\+\+ \/dev\/null/m.test(patch)) {
9313
+ status = "D";
9314
+ } else if (/^rename from /m.test(patch)) {
9315
+ status = "R";
9316
+ }
9317
+ const additions = patch.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++")).length;
9318
+ const deletions = patch.split("\n").filter((l) => l.startsWith("-") && !l.startsWith("---")).length;
9319
+ return {
9320
+ path,
9321
+ status,
9322
+ patch: capPatch(patch, maxHunk),
9323
+ additions,
9324
+ deletions
9325
+ };
9326
+ }
9327
+ async function gitDiffParts(worktreePath, diffArgs, includePatches, path) {
9328
+ const extra = pathspec(path);
9329
+ if (includePatches) {
9330
+ const diff = await gitDiff([...diffArgs, ...extra], worktreePath, {
9331
+ timeoutMs: 4e3
9332
+ });
9333
+ return { nameStatus: "", numstat: "", combinedDiff: diff.stdout };
9334
+ }
9335
+ const [ns, num2] = await Promise.all([
9336
+ gitDiff(["--name-status", ...diffArgs, ...extra], worktreePath),
9337
+ gitDiff(["--numstat", ...diffArgs, ...extra], worktreePath)
9338
+ ]);
9339
+ return {
9340
+ nameStatus: ns.stdout,
9341
+ numstat: num2.stdout,
9342
+ combinedDiff: ""
9343
+ };
9344
+ }
9345
+ function formatStat(files) {
9346
+ if (files.length === 0) return "(no changes)";
9347
+ const additions = files.reduce((n2, f) => n2 + (f.additions ?? 0), 0);
9348
+ const deletions = files.reduce((n2, f) => n2 + (f.deletions ?? 0), 0);
9349
+ const n = files.length;
9350
+ return `${n} file${n === 1 ? "" : "s"} changed, ${additions} insertions(+), ${deletions} deletions(-)`;
9351
+ }
9352
+ function emptyScopeStats() {
9353
+ const z2 = emptyStat();
9354
+ return {
9355
+ commits: z2,
9356
+ uncommitted: z2,
9357
+ staged: z2,
9358
+ unstaged: z2,
9359
+ last_turn: z2
9360
+ };
9235
9361
  }
9236
9362
  function filesFromDiff(nameStatus, numstat, combinedDiff, maxHunk) {
9237
- const counts = parseNumstat(numstat);
9238
9363
  const patches = splitCombinedDiff(combinedDiff);
9364
+ if (!nameStatus.trim() && patches.size > 0) {
9365
+ return [...patches.entries()].map(
9366
+ ([path, patch]) => fileFromPatch(path, patch, maxHunk)
9367
+ );
9368
+ }
9369
+ const counts = parseNumstat(numstat);
9239
9370
  const files = [];
9240
9371
  for (const { status, path } of parseNameStatus(nameStatus)) {
9241
9372
  const n = counts.get(path);
@@ -9257,11 +9388,11 @@ async function computeScopeStats(worktreePath, mergeBase, lastTurnBase, untracke
9257
9388
  { stdout: unstagedNum },
9258
9389
  lastTurnNum
9259
9390
  ] = await Promise.all([
9260
- mergeBase ? git(["diff", "--numstat", mergeBase], worktreePath, { reject: false }) : Promise.resolve({ stdout: "" }),
9261
- git(["diff", "--numstat", "HEAD"], worktreePath, { reject: false }),
9262
- git(["diff", "--numstat", "--cached"], worktreePath, { reject: false }),
9263
- git(["diff", "--numstat"], worktreePath, { reject: false }),
9264
- lastTurnBase ? git(["diff", "--numstat", lastTurnBase], worktreePath, { reject: false }) : Promise.resolve({ stdout: "" })
9391
+ mergeBase ? gitDiff(["--numstat", mergeBase], worktreePath) : Promise.resolve({ stdout: "" }),
9392
+ gitDiff(["--numstat", "HEAD"], worktreePath),
9393
+ gitDiff(["--numstat", "--cached"], worktreePath),
9394
+ gitDiff(["--numstat"], worktreePath),
9395
+ lastTurnBase ? gitDiff(["--numstat", lastTurnBase], worktreePath) : Promise.resolve({ stdout: "" })
9265
9396
  ]);
9266
9397
  return {
9267
9398
  commits: mergeBase ? statFromNumstat(commitsNum, untrackedCount) : emptyStat(),
@@ -9280,7 +9411,7 @@ async function listBranchCommits(worktreePath, repoPath, opts) {
9280
9411
  if (head.exitCode !== 0) return [];
9281
9412
  let base = opts?.base;
9282
9413
  try {
9283
- base = base ?? await resolveDefaultBranch(repoPath);
9414
+ base = base ?? await resolveDefaultBranch(repoPath, { network: false });
9284
9415
  } catch {
9285
9416
  base = "HEAD";
9286
9417
  }
@@ -9310,7 +9441,121 @@ async function listBranchCommits(worktreePath, repoPath, opts) {
9310
9441
  }
9311
9442
  return commits;
9312
9443
  }
9444
+ var SHA_RE = /^[0-9a-f]{7,40}$/i;
9445
+ function emptyPathDiff(scope, base, hasLastTurnBase, commitSha = null) {
9446
+ return {
9447
+ scope,
9448
+ commitSha: scope === "commits" ? commitSha : null,
9449
+ base,
9450
+ files: [],
9451
+ stat: formatStat([]),
9452
+ dirty: false,
9453
+ unpushed: 0,
9454
+ hasLastTurnBase,
9455
+ commits: [],
9456
+ scopeStats: emptyScopeStats()
9457
+ };
9458
+ }
9459
+ async function getPathDiff(worktreePath, repoPath, opts) {
9460
+ const { path, scope, commitSha, lastTurnBase, hasLastTurnBase, includePatches, maxHunk } = opts;
9461
+ if (scope === "last_turn" && !lastTurnBase) {
9462
+ return emptyPathDiff(scope, "last turn", false);
9463
+ }
9464
+ let diffArgs;
9465
+ let labelBase;
9466
+ if (scope === "staged") {
9467
+ diffArgs = ["--cached"];
9468
+ labelBase = "staged";
9469
+ } else if (scope === "unstaged") {
9470
+ diffArgs = [];
9471
+ labelBase = "unstaged";
9472
+ } else if (scope === "uncommitted") {
9473
+ diffArgs = ["HEAD"];
9474
+ labelBase = "HEAD";
9475
+ } else if (scope === "last_turn") {
9476
+ diffArgs = [lastTurnBase];
9477
+ labelBase = "last turn";
9478
+ } else if (scope === "commits" && commitSha) {
9479
+ diffArgs = [`${commitSha}^!`];
9480
+ labelBase = commitSha.slice(0, 7);
9481
+ } else if (scope === "commits" && opts.base && SHA_RE.test(opts.base)) {
9482
+ diffArgs = [opts.base];
9483
+ labelBase = opts.base.slice(0, 7);
9484
+ } else if (scope === "commits") {
9485
+ let base = opts.base;
9486
+ try {
9487
+ base = base ?? await resolveDefaultBranch(repoPath, { network: false });
9488
+ } catch {
9489
+ base = "HEAD";
9490
+ }
9491
+ const mergeBase = await resolveMergeBase(worktreePath, base, repoPath);
9492
+ diffArgs = [mergeBase];
9493
+ labelBase = mergeBase;
9494
+ } else {
9495
+ diffArgs = ["HEAD"];
9496
+ labelBase = "HEAD";
9497
+ }
9498
+ const diff = await gitDiff(
9499
+ includePatches ? [...diffArgs, "--", path] : ["--name-status", ...diffArgs, "--", path],
9500
+ worktreePath,
9501
+ { timeoutMs: 4e3 }
9502
+ );
9503
+ const filesMap = /* @__PURE__ */ new Map();
9504
+ if (includePatches) {
9505
+ const parsed = filesFromDiff("", "", diff.stdout, maxHunk);
9506
+ for (const file of parsed) filesMap.set(file.path, file);
9507
+ if (diff.stdout.trim() && !filesMap.has(path)) {
9508
+ filesMap.set(path, fileFromPatch(path, diff.stdout, maxHunk));
9509
+ }
9510
+ } else {
9511
+ for (const file of filesFromDiff(diff.stdout, "", "", maxHunk)) {
9512
+ filesMap.set(file.path, file);
9513
+ }
9514
+ }
9515
+ if (filesMap.size === 0) {
9516
+ const maybe = await listUntrackedPaths(worktreePath, path);
9517
+ if (maybe.length > 0) {
9518
+ const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, maybe) : untrackedStubs(maybe);
9519
+ for (const file of extra) filesMap.set(file.path, file);
9520
+ }
9521
+ }
9522
+ const files = [...filesMap.values()].sort((a, b) => a.path.localeCompare(b.path));
9523
+ return {
9524
+ scope,
9525
+ commitSha: scope === "commits" ? commitSha : null,
9526
+ base: labelBase,
9527
+ files,
9528
+ stat: formatStat(files),
9529
+ dirty: files.length > 0,
9530
+ unpushed: 0,
9531
+ hasLastTurnBase,
9532
+ commits: [],
9533
+ scopeStats: emptyScopeStats(),
9534
+ mergeBase: SHA_RE.test(diffArgs[0] ?? "") ? diffArgs[0] : null
9535
+ };
9536
+ }
9313
9537
  async function getDiff(worktreePath, repoPath, opts) {
9538
+ const maxHunk = opts?.maxHunkChars ?? 8e3;
9539
+ const scope = opts?.scope ?? "commits";
9540
+ const lastTurnBase = opts?.lastTurnBase?.trim() || null;
9541
+ const hasLastTurnBase = Boolean(lastTurnBase);
9542
+ const commitSha = opts?.commitSha?.trim() || null;
9543
+ const includePatches = opts?.includePatches ?? true;
9544
+ const pathFilter = opts?.path?.trim() || null;
9545
+ const fileOnly = Boolean(pathFilter);
9546
+ const includeMeta = (opts?.includeMeta ?? true) && !fileOnly;
9547
+ if (fileOnly && pathFilter && !includeMeta) {
9548
+ return getPathDiff(worktreePath, repoPath, {
9549
+ path: pathFilter,
9550
+ scope,
9551
+ commitSha,
9552
+ lastTurnBase,
9553
+ hasLastTurnBase,
9554
+ base: opts?.base,
9555
+ includePatches,
9556
+ maxHunk
9557
+ });
9558
+ }
9314
9559
  const status = await inspectGitWorktree(worktreePath);
9315
9560
  if (status === "missing_worktree") {
9316
9561
  throw new Error("Worktree not found");
@@ -9318,18 +9563,19 @@ async function getDiff(worktreePath, repoPath, opts) {
9318
9563
  if (status === "not_git") {
9319
9564
  throw new Error("Not a Git repository");
9320
9565
  }
9321
- const maxHunk = opts?.maxHunkChars ?? 8e3;
9322
- const scope = opts?.scope ?? "commits";
9323
- const lastTurnBase = opts?.lastTurnBase?.trim() || null;
9324
- const hasLastTurnBase = Boolean(lastTurnBase);
9325
- const commitSha = opts?.commitSha?.trim() || null;
9326
- const head = await git(["rev-parse", "--verify", "HEAD"], worktreePath, {
9566
+ const wantUntracked = opts?.includeUntracked !== void 0 ? opts.includeUntracked : !fileOnly && (scope === "commits" && !commitSha || scope === "uncommitted" || scope === "unstaged" || scope === "last_turn");
9567
+ const needsMergeBase = scope === "commits" && !commitSha || includeMeta;
9568
+ const headP = git(["rev-parse", "--verify", "HEAD"], worktreePath, {
9327
9569
  reject: false
9328
9570
  });
9571
+ const untrackedP = wantUntracked ? listUntrackedPaths(worktreePath, pathFilter) : Promise.resolve([]);
9572
+ const head = await headP;
9329
9573
  const hasHead = head.exitCode === 0;
9330
- const untrackedPaths = await listUntrackedPaths(worktreePath);
9331
9574
  if (!hasHead) {
9332
- const files2 = scope === "staged" ? [] : (await listUntrackedFiles(worktreePath, maxHunk)).sort(
9575
+ const untrackedPaths2 = await untrackedP;
9576
+ const files2 = scope === "staged" ? [] : includePatches ? (await listUntrackedFiles(worktreePath, maxHunk, untrackedPaths2)).sort(
9577
+ (a, b) => a.path.localeCompare(b.path)
9578
+ ) : untrackedStubs(untrackedPaths2).sort(
9333
9579
  (a, b) => a.path.localeCompare(b.path)
9334
9580
  );
9335
9581
  const untrackedStat = {
@@ -9343,7 +9589,7 @@ async function getDiff(worktreePath, repoPath, opts) {
9343
9589
  commitSha: null,
9344
9590
  base: "(no commits)",
9345
9591
  files: files2,
9346
- stat: files2.length ? files2.map((f) => ` ${f.path} | untracked`).join("\n") : "(no changes)",
9592
+ stat: formatStat(files2),
9347
9593
  dirty: files2.length > 0,
9348
9594
  unpushed: 0,
9349
9595
  hasLastTurnBase,
@@ -9357,137 +9603,122 @@ async function getDiff(worktreePath, repoPath, opts) {
9357
9603
  }
9358
9604
  };
9359
9605
  }
9360
- let base = opts?.base;
9361
- try {
9362
- base = base ?? await resolveDefaultBranch(repoPath);
9363
- } catch {
9364
- base = "HEAD";
9606
+ let mergeBase = "HEAD";
9607
+ let baseLabel = "HEAD";
9608
+ if (needsMergeBase) {
9609
+ let base = opts?.base;
9610
+ try {
9611
+ base = base ?? await resolveDefaultBranch(repoPath, { network: false });
9612
+ } catch {
9613
+ base = "HEAD";
9614
+ }
9615
+ mergeBase = await resolveMergeBase(worktreePath, base, repoPath);
9616
+ baseLabel = await resolveDiffBaseRef(worktreePath, base, repoPath);
9365
9617
  }
9366
- base = await resolveDiffBaseRef(worktreePath, base, repoPath);
9367
- if (base.startsWith("origin/")) {
9368
- const short = base.slice("origin/".length);
9369
- await git(["fetch", "origin", short, "--quiet"], worktreePath, {
9370
- reject: false
9371
- });
9372
- base = await resolveDiffBaseRef(worktreePath, short, repoPath);
9618
+ const includeUntracked = wantUntracked;
9619
+ const metaPromise = includeMeta ? Promise.all([
9620
+ computeScopeStats(
9621
+ worktreePath,
9622
+ mergeBase,
9623
+ lastTurnBase,
9624
+ // Cheap: don't wait on the untracked walk just to pad the badge.
9625
+ 0
9626
+ ),
9627
+ listBranchCommits(worktreePath, repoPath, { base: baseLabel }),
9628
+ isDirty(worktreePath),
9629
+ countUnpushedCommits(worktreePath)
9630
+ ]).then(([scopeStats, commits, dirty, unpushed]) => ({
9631
+ scopeStats,
9632
+ commits,
9633
+ dirty,
9634
+ unpushed
9635
+ })) : Promise.resolve({
9636
+ scopeStats: emptyScopeStats(),
9637
+ commits: [],
9638
+ dirty: false,
9639
+ unpushed: 0
9640
+ });
9641
+ if (scope === "last_turn" && !lastTurnBase) {
9642
+ const meta2 = await metaPromise;
9643
+ return {
9644
+ scope,
9645
+ commitSha: null,
9646
+ base: "last turn",
9647
+ files: [],
9648
+ stat: "(no last agent turn)",
9649
+ dirty: meta2.dirty,
9650
+ unpushed: meta2.unpushed,
9651
+ hasLastTurnBase: false,
9652
+ commits: meta2.commits,
9653
+ scopeStats: meta2.scopeStats
9654
+ };
9373
9655
  }
9374
- const mergeBase = await resolveMergeBase(worktreePath, base, repoPath);
9375
- const scopeStats = await computeScopeStats(
9376
- worktreePath,
9377
- mergeBase,
9378
- lastTurnBase,
9379
- untrackedPaths.length
9380
- );
9381
- const includeUntracked = scope === "commits" && !commitSha || scope === "uncommitted" || scope === "unstaged" || scope === "last_turn";
9382
- let nameStatus = "";
9383
- let numstat = "";
9384
- let combinedDiff = "";
9385
- let labelBase = base;
9656
+ let diffArgs;
9657
+ let labelBase = baseLabel;
9386
9658
  if (scope === "staged") {
9387
- const [ns, num2, diff] = await Promise.all([
9388
- git(["diff", "--name-status", "--cached"], worktreePath, { reject: false }),
9389
- git(["diff", "--numstat", "--cached"], worktreePath, { reject: false }),
9390
- git(["diff", "--cached"], worktreePath, { reject: false })
9391
- ]);
9392
- nameStatus = ns.stdout;
9393
- numstat = num2.stdout;
9394
- combinedDiff = diff.stdout;
9659
+ diffArgs = ["--cached"];
9395
9660
  labelBase = "staged";
9396
9661
  } else if (scope === "unstaged") {
9397
- const [ns, num2, diff] = await Promise.all([
9398
- git(["diff", "--name-status"], worktreePath, { reject: false }),
9399
- git(["diff", "--numstat"], worktreePath, { reject: false }),
9400
- git(["diff"], worktreePath, { reject: false })
9401
- ]);
9402
- nameStatus = ns.stdout;
9403
- numstat = num2.stdout;
9404
- combinedDiff = diff.stdout;
9662
+ diffArgs = [];
9405
9663
  labelBase = "unstaged";
9406
9664
  } else if (scope === "uncommitted") {
9407
- const [ns, num2, diff] = await Promise.all([
9408
- git(["diff", "--name-status", "HEAD"], worktreePath, { reject: false }),
9409
- git(["diff", "--numstat", "HEAD"], worktreePath, { reject: false }),
9410
- git(["diff", "HEAD"], worktreePath, { reject: false })
9411
- ]);
9412
- nameStatus = ns.stdout;
9413
- numstat = num2.stdout;
9414
- combinedDiff = diff.stdout;
9665
+ diffArgs = ["HEAD"];
9415
9666
  labelBase = "HEAD";
9416
9667
  } else if (scope === "last_turn") {
9417
- if (!lastTurnBase) {
9418
- const commits2 = await listBranchCommits(worktreePath, repoPath, { base });
9419
- return {
9420
- scope,
9421
- commitSha: null,
9422
- base: "last turn",
9423
- files: [],
9424
- stat: "(no last agent turn)",
9425
- dirty: await isDirty(worktreePath),
9426
- unpushed: await countUnpushedCommits(worktreePath),
9427
- hasLastTurnBase: false,
9428
- commits: commits2,
9429
- scopeStats
9430
- };
9431
- }
9432
- const [ns, num2, diff] = await Promise.all([
9433
- git(["diff", "--name-status", lastTurnBase], worktreePath, { reject: false }),
9434
- git(["diff", "--numstat", lastTurnBase], worktreePath, { reject: false }),
9435
- git(["diff", lastTurnBase], worktreePath, { reject: false })
9436
- ]);
9437
- nameStatus = ns.stdout;
9438
- numstat = num2.stdout;
9439
- combinedDiff = diff.stdout;
9668
+ diffArgs = [lastTurnBase];
9440
9669
  labelBase = "last turn";
9441
9670
  } else if (scope === "commits" && commitSha) {
9442
- const range = `${commitSha}^!`;
9443
- const [ns, num2, diff] = await Promise.all([
9444
- git(["diff", "--name-status", range], worktreePath, { reject: false }),
9445
- git(["diff", "--numstat", range], worktreePath, { reject: false }),
9446
- git(["diff", range], worktreePath, { reject: false })
9447
- ]);
9448
- nameStatus = ns.stdout;
9449
- numstat = num2.stdout;
9450
- combinedDiff = diff.stdout;
9671
+ diffArgs = [`${commitSha}^!`];
9451
9672
  labelBase = commitSha.slice(0, 7);
9452
9673
  } else {
9453
- const [ns, num2, diff] = await Promise.all([
9454
- git(["diff", "--name-status", mergeBase], worktreePath, { reject: false }),
9455
- git(["diff", "--numstat", mergeBase], worktreePath, { reject: false }),
9456
- git(["diff", mergeBase], worktreePath, { reject: false })
9457
- ]);
9458
- nameStatus = ns.stdout;
9459
- numstat = num2.stdout;
9460
- combinedDiff = diff.stdout;
9461
- labelBase = base;
9674
+ diffArgs = [mergeBase];
9675
+ labelBase = baseLabel;
9462
9676
  }
9463
- const commits = await listBranchCommits(worktreePath, repoPath, { base });
9677
+ const partsPromise = gitDiffParts(
9678
+ worktreePath,
9679
+ diffArgs,
9680
+ includePatches,
9681
+ pathFilter
9682
+ );
9683
+ const [parts, meta, untrackedPaths] = await Promise.all([
9684
+ partsPromise,
9685
+ metaPromise,
9686
+ untrackedP
9687
+ ]);
9464
9688
  const filesMap = /* @__PURE__ */ new Map();
9465
- for (const file of filesFromDiff(nameStatus, numstat, combinedDiff, maxHunk)) {
9689
+ for (const file of filesFromDiff(
9690
+ parts.nameStatus,
9691
+ parts.numstat,
9692
+ parts.combinedDiff,
9693
+ maxHunk
9694
+ )) {
9466
9695
  filesMap.set(file.path, file);
9467
9696
  }
9468
9697
  if (includeUntracked) {
9469
- const untrackedFiles = await listUntrackedFiles(worktreePath, maxHunk);
9470
- for (const file of untrackedFiles) {
9698
+ const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, untrackedPaths) : untrackedStubs(untrackedPaths);
9699
+ for (const file of extra) {
9471
9700
  if (!filesMap.has(file.path)) filesMap.set(file.path, file);
9472
9701
  }
9702
+ } else if (fileOnly && pathFilter && !filesMap.has(pathFilter)) {
9703
+ const maybe = await listUntrackedPaths(worktreePath, pathFilter);
9704
+ if (maybe.length > 0) {
9705
+ const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, maybe) : untrackedStubs(maybe);
9706
+ for (const file of extra) filesMap.set(file.path, file);
9707
+ }
9473
9708
  }
9474
9709
  const files = [...filesMap.values()].sort((a, b) => a.path.localeCompare(b.path));
9475
- const { stdout: statOut } = await git(
9476
- scope === "staged" ? ["diff", "--stat", "--cached"] : scope === "unstaged" ? ["diff", "--stat"] : scope === "uncommitted" ? ["diff", "--stat", "HEAD"] : scope === "last_turn" && lastTurnBase ? ["diff", "--stat", lastTurnBase] : scope === "commits" && commitSha ? ["diff", "--stat", `${commitSha}^!`] : ["diff", "--stat", mergeBase],
9477
- worktreePath,
9478
- { reject: false }
9479
- );
9480
9710
  return {
9481
9711
  scope,
9482
9712
  commitSha: scope === "commits" ? commitSha : null,
9483
9713
  base: labelBase,
9484
9714
  files,
9485
- stat: statOut.trim() || (files.length ? `${files.length} file(s)` : "(no changes)"),
9486
- dirty: await isDirty(worktreePath),
9487
- unpushed: await countUnpushedCommits(worktreePath),
9715
+ stat: formatStat(files),
9716
+ dirty: fileOnly || !includeMeta ? files.length > 0 : meta.dirty,
9717
+ unpushed: meta.unpushed,
9488
9718
  hasLastTurnBase,
9489
- commits,
9490
- scopeStats
9719
+ commits: meta.commits,
9720
+ scopeStats: meta.scopeStats,
9721
+ mergeBase: needsMergeBase ? mergeBase : null
9491
9722
  };
9492
9723
  }
9493
9724
  async function listWorktreeFiles(worktreePath, opts) {
@@ -13183,6 +13414,11 @@ var Orchestrator = class {
13183
13414
  return getDiff(thread.worktreePath, thread.repoPath, {
13184
13415
  scope: opts?.scope,
13185
13416
  commitSha: opts?.commitSha,
13417
+ base: opts?.base,
13418
+ includePatches: opts?.includePatches,
13419
+ includeMeta: opts?.includeMeta,
13420
+ includeUntracked: opts?.includeUntracked,
13421
+ path: opts?.path,
13186
13422
  lastTurnBase: this.turnBaselines.get(thread.id) ?? null
13187
13423
  });
13188
13424
  }
@@ -15235,6 +15471,7 @@ init_injected_mcp();
15235
15471
  coerceOrchestratorAgent,
15236
15472
  collectTakenTeamSlugs,
15237
15473
  commitAll,
15474
+ conductorBundledBinDir,
15238
15475
  conductorDbPath,
15239
15476
  confirmLand,
15240
15477
  connectBrightsyTeam,
@@ -15346,6 +15583,7 @@ init_injected_mcp();
15346
15583
  isBrightsyConnected,
15347
15584
  isBrightsyNdjsonLine,
15348
15585
  isCloudCoordinatorThread,
15586
+ isConductorBundledCli,
15349
15587
  isCursorAutoModel,
15350
15588
  isDirty,
15351
15589
  isGhRateLimitError,