@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.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  listWorkspaces,
5
5
  removeWorkspace,
6
6
  syncWorkspacesFromThreads
7
- } from "./chunk-PESJDZTB.js";
7
+ } from "./chunk-DPDGMMGI.js";
8
8
  import {
9
9
  BRIGHTSY_MCP_ALLOWED_TOOLS,
10
10
  CLAUDE_MODEL_CATALOG,
@@ -58,7 +58,7 @@ import {
58
58
  sideboardMcpProfile,
59
59
  threadRequestsBrightsyMcp,
60
60
  writeInjectedMcpConfig
61
- } from "./chunk-IFAU2DEY.js";
61
+ } from "./chunk-6Q7H6SMX.js";
62
62
  import {
63
63
  CLOUD_COORDINATOR_BUSY_REPLY,
64
64
  CLOUD_COORDINATOR_STOPPED_REPLY,
@@ -82,7 +82,7 @@ import {
82
82
  orchestratorSessionPoisonedByBuiltins,
83
83
  parseForceStopMessage,
84
84
  takenTeamSlugsForOrchestration
85
- } from "./chunk-YTNLOJPK.js";
85
+ } from "./chunk-ROXEENBT.js";
86
86
  import {
87
87
  brightsyConfigPath,
88
88
  brightsyMcpServerName,
@@ -94,7 +94,7 @@ import {
94
94
  loadBrightsyConfig,
95
95
  saveBrightsyConfig,
96
96
  switchBrightsyAccount
97
- } from "./chunk-DZYMNW2A.js";
97
+ } from "./chunk-BTL7EMGT.js";
98
98
  import {
99
99
  LEGACY_PLAN_FILE_REL,
100
100
  PLAN_FILE_NAME,
@@ -124,7 +124,7 @@ import {
124
124
  enrichWorkspacesWithGithub,
125
125
  ensureGlobalCoordinatorCwd,
126
126
  formatWorkspaceInventory
127
- } from "./chunk-AKPEXIKK.js";
127
+ } from "./chunk-VX6ACNXS.js";
128
128
  import {
129
129
  HARNESS_ENV_KEYS,
130
130
  appSettingsPath,
@@ -232,7 +232,7 @@ import {
232
232
  worktreeDisplayLabel,
233
233
  worktreeDisplayLabelForGroup,
234
234
  worktreeNameFromPath
235
- } from "./chunk-R7GUDEPY.js";
235
+ } from "./chunk-EEBDVLDK.js";
236
236
  import {
237
237
  ATTACHMENTS_DIR,
238
238
  LEGACY_ATTACHMENTS_DIR,
@@ -284,16 +284,18 @@ import {
284
284
  worktreesRoot
285
285
  } from "./chunk-M37RITA6.js";
286
286
  import {
287
+ conductorBundledBinDir,
287
288
  enrichPathWithNpmGlobalBin,
288
289
  ensureAgentPath,
289
290
  gh,
290
291
  git,
292
+ isConductorBundledCli,
291
293
  posixShellSingleQuote,
292
294
  resolveCommandBinarySync,
293
295
  resolveGhAuthToken,
294
296
  run,
295
297
  withExportedPath
296
- } from "./chunk-TXQ6K2GR.js";
298
+ } from "./chunk-D4DPQ552.js";
297
299
 
298
300
  // src/integrations/github.ts
299
301
  async function getGitHubStatus() {
@@ -722,9 +724,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
722
724
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
723
725
  );
724
726
  }
725
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-44UG64NA.js");
727
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-7P5NG3JZ.js");
726
728
  if (isGlobalThread2(thread)) {
727
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-ILSULI7C.js");
729
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-HD6IMCKS.js");
728
730
  ensureGlobalCoordinatorCwd2(
729
731
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
730
732
  );
@@ -1510,24 +1512,25 @@ function capPatch(patch, maxHunk) {
1510
1512
 
1511
1513
  \u2026 truncated (${patch.length - maxHunk} more chars)`;
1512
1514
  }
1515
+ var mergeBaseCache = /* @__PURE__ */ new Map();
1516
+ var MERGE_BASE_TTL_MS = 45e3;
1513
1517
  async function resolveMergeBase(worktreePath, base, repoPath) {
1514
1518
  const baseRef = await resolveDiffBaseRef(worktreePath, base, repoPath);
1519
+ const cacheKey = `${worktreePath}\0${baseRef}`;
1520
+ const hit = mergeBaseCache.get(cacheKey);
1521
+ if (hit && Date.now() - hit.at < MERGE_BASE_TTL_MS) return hit.value;
1515
1522
  const { stdout } = await git(["merge-base", baseRef, "HEAD"], worktreePath, {
1516
1523
  reject: false
1517
1524
  });
1518
- const mb = stdout.trim();
1519
- return mb || baseRef;
1525
+ const mb = stdout.trim() || baseRef;
1526
+ mergeBaseCache.set(cacheKey, { at: Date.now(), value: mb });
1527
+ return mb;
1520
1528
  }
1521
1529
  async function countUnpushedCommits(worktreePath) {
1522
1530
  const head = await git(["rev-parse", "--abbrev-ref", "HEAD"], worktreePath, {
1523
1531
  reject: false
1524
1532
  });
1525
1533
  const branch = head.stdout.trim();
1526
- if (branch && branch !== "HEAD") {
1527
- await git(["fetch", "origin", branch, "--quiet"], worktreePath, {
1528
- reject: false
1529
- });
1530
- }
1531
1534
  const upstream = await git(
1532
1535
  ["rev-list", "--count", "@{upstream}..HEAD"],
1533
1536
  worktreePath,
@@ -1560,11 +1563,37 @@ function splitCombinedDiff(stdout) {
1560
1563
  }
1561
1564
  return map;
1562
1565
  }
1566
+ function syntheticAddPatch(path, content, maxHunk) {
1567
+ const lines = content.split("\n");
1568
+ const body = lines.map((l) => `+${l}`).join("\n");
1569
+ const header = `diff --git a/${path} b/${path}
1570
+ new file mode 100644
1571
+ --- /dev/null
1572
+ +++ b/${path}
1573
+ @@ -0,0 +1,${lines.length} @@
1574
+ `;
1575
+ return {
1576
+ path,
1577
+ status: "A",
1578
+ patch: capPatch(`${header}${body}`, maxHunk),
1579
+ additions: lines.length,
1580
+ deletions: 0
1581
+ };
1582
+ }
1563
1583
  async function untrackedPatch(worktreePath, path, maxHunk) {
1584
+ const abs = join4(worktreePath, path);
1585
+ try {
1586
+ const st = statSync2(abs);
1587
+ if (st.isFile() && st.size > maxHunk) {
1588
+ const buf = readFileSync4(abs).subarray(0, maxHunk);
1589
+ return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
1590
+ }
1591
+ } catch {
1592
+ }
1564
1593
  const { stdout: patch } = await git(
1565
- ["diff", "--no-index", "--", "/dev/null", path],
1594
+ ["diff", "--no-ext-diff", "--no-color", "--no-index", "--", "/dev/null", path],
1566
1595
  worktreePath,
1567
- { reject: false }
1596
+ { reject: false, timeoutMs: 4e3 }
1568
1597
  );
1569
1598
  const normalized = patch.replace(/^diff --git a\/.+? b\/.+?$/m, `diff --git a/${path} b/${path}`).replace(/^--- .*$/m, "--- /dev/null").replace(/^\+\+\+ .*$/m, `+++ b/${path}`);
1570
1599
  const addLines = normalized.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++")).length;
@@ -1576,22 +1605,97 @@ async function untrackedPatch(worktreePath, path, maxHunk) {
1576
1605
  deletions: 0
1577
1606
  };
1578
1607
  }
1579
- async function listUntrackedPaths(worktreePath) {
1580
- const { stdout } = await git(
1581
- ["ls-files", "-z", "--others", "--exclude-standard"],
1582
- worktreePath,
1583
- { reject: false }
1584
- );
1608
+ async function listUntrackedPaths(worktreePath, path) {
1609
+ const args = ["ls-files", "-z", "--others", "--exclude-standard"];
1610
+ if (path) args.push("--", path);
1611
+ const { stdout } = await git(args, worktreePath, { reject: false });
1585
1612
  return stdout.split("\0").filter(Boolean).filter((p) => !isSideboardScratchPath(p));
1586
1613
  }
1587
- async function listUntrackedFiles(worktreePath, maxHunk) {
1588
- const paths = await listUntrackedPaths(worktreePath);
1589
- if (paths.length === 0) return [];
1590
- return Promise.all(paths.map((path) => untrackedPatch(worktreePath, path, maxHunk)));
1614
+ async function listUntrackedFiles(worktreePath, maxHunk, paths) {
1615
+ const list = paths ?? await listUntrackedPaths(worktreePath);
1616
+ if (list.length === 0) return [];
1617
+ return Promise.all(list.map((path) => untrackedPatch(worktreePath, path, maxHunk)));
1618
+ }
1619
+ function untrackedStubs(paths) {
1620
+ return paths.map((path) => ({
1621
+ path,
1622
+ status: "A",
1623
+ patch: "",
1624
+ additions: 0,
1625
+ deletions: 0
1626
+ }));
1627
+ }
1628
+ function pathspec(path) {
1629
+ return path ? ["--", path] : [];
1630
+ }
1631
+ function gitDiff(args, cwd, opts) {
1632
+ return git(["diff", "--no-ext-diff", "--no-color", ...args], cwd, {
1633
+ reject: false,
1634
+ timeoutMs: opts?.timeoutMs
1635
+ });
1636
+ }
1637
+ function fileFromPatch(path, patch, maxHunk) {
1638
+ let status = "M";
1639
+ if (/^new file mode /m.test(patch) || /^--- \/dev\/null/m.test(patch)) {
1640
+ status = "A";
1641
+ } else if (/^deleted file mode /m.test(patch) || /^\+\+\+ \/dev\/null/m.test(patch)) {
1642
+ status = "D";
1643
+ } else if (/^rename from /m.test(patch)) {
1644
+ status = "R";
1645
+ }
1646
+ const additions = patch.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++")).length;
1647
+ const deletions = patch.split("\n").filter((l) => l.startsWith("-") && !l.startsWith("---")).length;
1648
+ return {
1649
+ path,
1650
+ status,
1651
+ patch: capPatch(patch, maxHunk),
1652
+ additions,
1653
+ deletions
1654
+ };
1655
+ }
1656
+ async function gitDiffParts(worktreePath, diffArgs, includePatches, path) {
1657
+ const extra = pathspec(path);
1658
+ if (includePatches) {
1659
+ const diff = await gitDiff([...diffArgs, ...extra], worktreePath, {
1660
+ timeoutMs: 4e3
1661
+ });
1662
+ return { nameStatus: "", numstat: "", combinedDiff: diff.stdout };
1663
+ }
1664
+ const [ns, num] = await Promise.all([
1665
+ gitDiff(["--name-status", ...diffArgs, ...extra], worktreePath),
1666
+ gitDiff(["--numstat", ...diffArgs, ...extra], worktreePath)
1667
+ ]);
1668
+ return {
1669
+ nameStatus: ns.stdout,
1670
+ numstat: num.stdout,
1671
+ combinedDiff: ""
1672
+ };
1673
+ }
1674
+ function formatStat(files) {
1675
+ if (files.length === 0) return "(no changes)";
1676
+ const additions = files.reduce((n2, f) => n2 + (f.additions ?? 0), 0);
1677
+ const deletions = files.reduce((n2, f) => n2 + (f.deletions ?? 0), 0);
1678
+ const n = files.length;
1679
+ return `${n} file${n === 1 ? "" : "s"} changed, ${additions} insertions(+), ${deletions} deletions(-)`;
1680
+ }
1681
+ function emptyScopeStats() {
1682
+ const z2 = emptyStat();
1683
+ return {
1684
+ commits: z2,
1685
+ uncommitted: z2,
1686
+ staged: z2,
1687
+ unstaged: z2,
1688
+ last_turn: z2
1689
+ };
1591
1690
  }
1592
1691
  function filesFromDiff(nameStatus, numstat, combinedDiff, maxHunk) {
1593
- const counts = parseNumstat(numstat);
1594
1692
  const patches = splitCombinedDiff(combinedDiff);
1693
+ if (!nameStatus.trim() && patches.size > 0) {
1694
+ return [...patches.entries()].map(
1695
+ ([path, patch]) => fileFromPatch(path, patch, maxHunk)
1696
+ );
1697
+ }
1698
+ const counts = parseNumstat(numstat);
1595
1699
  const files = [];
1596
1700
  for (const { status, path } of parseNameStatus(nameStatus)) {
1597
1701
  const n = counts.get(path);
@@ -1613,11 +1717,11 @@ async function computeScopeStats(worktreePath, mergeBase, lastTurnBase, untracke
1613
1717
  { stdout: unstagedNum },
1614
1718
  lastTurnNum
1615
1719
  ] = await Promise.all([
1616
- mergeBase ? git(["diff", "--numstat", mergeBase], worktreePath, { reject: false }) : Promise.resolve({ stdout: "" }),
1617
- git(["diff", "--numstat", "HEAD"], worktreePath, { reject: false }),
1618
- git(["diff", "--numstat", "--cached"], worktreePath, { reject: false }),
1619
- git(["diff", "--numstat"], worktreePath, { reject: false }),
1620
- lastTurnBase ? git(["diff", "--numstat", lastTurnBase], worktreePath, { reject: false }) : Promise.resolve({ stdout: "" })
1720
+ mergeBase ? gitDiff(["--numstat", mergeBase], worktreePath) : Promise.resolve({ stdout: "" }),
1721
+ gitDiff(["--numstat", "HEAD"], worktreePath),
1722
+ gitDiff(["--numstat", "--cached"], worktreePath),
1723
+ gitDiff(["--numstat"], worktreePath),
1724
+ lastTurnBase ? gitDiff(["--numstat", lastTurnBase], worktreePath) : Promise.resolve({ stdout: "" })
1621
1725
  ]);
1622
1726
  return {
1623
1727
  commits: mergeBase ? statFromNumstat(commitsNum, untrackedCount) : emptyStat(),
@@ -1636,7 +1740,7 @@ async function listBranchCommits(worktreePath, repoPath, opts) {
1636
1740
  if (head.exitCode !== 0) return [];
1637
1741
  let base = opts?.base;
1638
1742
  try {
1639
- base = base ?? await resolveDefaultBranch(repoPath);
1743
+ base = base ?? await resolveDefaultBranch(repoPath, { network: false });
1640
1744
  } catch {
1641
1745
  base = "HEAD";
1642
1746
  }
@@ -1666,7 +1770,121 @@ async function listBranchCommits(worktreePath, repoPath, opts) {
1666
1770
  }
1667
1771
  return commits;
1668
1772
  }
1773
+ var SHA_RE = /^[0-9a-f]{7,40}$/i;
1774
+ function emptyPathDiff(scope, base, hasLastTurnBase, commitSha = null) {
1775
+ return {
1776
+ scope,
1777
+ commitSha: scope === "commits" ? commitSha : null,
1778
+ base,
1779
+ files: [],
1780
+ stat: formatStat([]),
1781
+ dirty: false,
1782
+ unpushed: 0,
1783
+ hasLastTurnBase,
1784
+ commits: [],
1785
+ scopeStats: emptyScopeStats()
1786
+ };
1787
+ }
1788
+ async function getPathDiff(worktreePath, repoPath, opts) {
1789
+ const { path, scope, commitSha, lastTurnBase, hasLastTurnBase, includePatches, maxHunk } = opts;
1790
+ if (scope === "last_turn" && !lastTurnBase) {
1791
+ return emptyPathDiff(scope, "last turn", false);
1792
+ }
1793
+ let diffArgs;
1794
+ let labelBase;
1795
+ if (scope === "staged") {
1796
+ diffArgs = ["--cached"];
1797
+ labelBase = "staged";
1798
+ } else if (scope === "unstaged") {
1799
+ diffArgs = [];
1800
+ labelBase = "unstaged";
1801
+ } else if (scope === "uncommitted") {
1802
+ diffArgs = ["HEAD"];
1803
+ labelBase = "HEAD";
1804
+ } else if (scope === "last_turn") {
1805
+ diffArgs = [lastTurnBase];
1806
+ labelBase = "last turn";
1807
+ } else if (scope === "commits" && commitSha) {
1808
+ diffArgs = [`${commitSha}^!`];
1809
+ labelBase = commitSha.slice(0, 7);
1810
+ } else if (scope === "commits" && opts.base && SHA_RE.test(opts.base)) {
1811
+ diffArgs = [opts.base];
1812
+ labelBase = opts.base.slice(0, 7);
1813
+ } else if (scope === "commits") {
1814
+ let base = opts.base;
1815
+ try {
1816
+ base = base ?? await resolveDefaultBranch(repoPath, { network: false });
1817
+ } catch {
1818
+ base = "HEAD";
1819
+ }
1820
+ const mergeBase = await resolveMergeBase(worktreePath, base, repoPath);
1821
+ diffArgs = [mergeBase];
1822
+ labelBase = mergeBase;
1823
+ } else {
1824
+ diffArgs = ["HEAD"];
1825
+ labelBase = "HEAD";
1826
+ }
1827
+ const diff = await gitDiff(
1828
+ includePatches ? [...diffArgs, "--", path] : ["--name-status", ...diffArgs, "--", path],
1829
+ worktreePath,
1830
+ { timeoutMs: 4e3 }
1831
+ );
1832
+ const filesMap = /* @__PURE__ */ new Map();
1833
+ if (includePatches) {
1834
+ const parsed = filesFromDiff("", "", diff.stdout, maxHunk);
1835
+ for (const file of parsed) filesMap.set(file.path, file);
1836
+ if (diff.stdout.trim() && !filesMap.has(path)) {
1837
+ filesMap.set(path, fileFromPatch(path, diff.stdout, maxHunk));
1838
+ }
1839
+ } else {
1840
+ for (const file of filesFromDiff(diff.stdout, "", "", maxHunk)) {
1841
+ filesMap.set(file.path, file);
1842
+ }
1843
+ }
1844
+ if (filesMap.size === 0) {
1845
+ const maybe = await listUntrackedPaths(worktreePath, path);
1846
+ if (maybe.length > 0) {
1847
+ const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, maybe) : untrackedStubs(maybe);
1848
+ for (const file of extra) filesMap.set(file.path, file);
1849
+ }
1850
+ }
1851
+ const files = [...filesMap.values()].sort((a, b) => a.path.localeCompare(b.path));
1852
+ return {
1853
+ scope,
1854
+ commitSha: scope === "commits" ? commitSha : null,
1855
+ base: labelBase,
1856
+ files,
1857
+ stat: formatStat(files),
1858
+ dirty: files.length > 0,
1859
+ unpushed: 0,
1860
+ hasLastTurnBase,
1861
+ commits: [],
1862
+ scopeStats: emptyScopeStats(),
1863
+ mergeBase: SHA_RE.test(diffArgs[0] ?? "") ? diffArgs[0] : null
1864
+ };
1865
+ }
1669
1866
  async function getDiff(worktreePath, repoPath, opts) {
1867
+ const maxHunk = opts?.maxHunkChars ?? 8e3;
1868
+ const scope = opts?.scope ?? "commits";
1869
+ const lastTurnBase = opts?.lastTurnBase?.trim() || null;
1870
+ const hasLastTurnBase = Boolean(lastTurnBase);
1871
+ const commitSha = opts?.commitSha?.trim() || null;
1872
+ const includePatches = opts?.includePatches ?? true;
1873
+ const pathFilter = opts?.path?.trim() || null;
1874
+ const fileOnly = Boolean(pathFilter);
1875
+ const includeMeta = (opts?.includeMeta ?? true) && !fileOnly;
1876
+ if (fileOnly && pathFilter && !includeMeta) {
1877
+ return getPathDiff(worktreePath, repoPath, {
1878
+ path: pathFilter,
1879
+ scope,
1880
+ commitSha,
1881
+ lastTurnBase,
1882
+ hasLastTurnBase,
1883
+ base: opts?.base,
1884
+ includePatches,
1885
+ maxHunk
1886
+ });
1887
+ }
1670
1888
  const status = await inspectGitWorktree(worktreePath);
1671
1889
  if (status === "missing_worktree") {
1672
1890
  throw new Error("Worktree not found");
@@ -1674,18 +1892,19 @@ async function getDiff(worktreePath, repoPath, opts) {
1674
1892
  if (status === "not_git") {
1675
1893
  throw new Error("Not a Git repository");
1676
1894
  }
1677
- const maxHunk = opts?.maxHunkChars ?? 8e3;
1678
- const scope = opts?.scope ?? "commits";
1679
- const lastTurnBase = opts?.lastTurnBase?.trim() || null;
1680
- const hasLastTurnBase = Boolean(lastTurnBase);
1681
- const commitSha = opts?.commitSha?.trim() || null;
1682
- const head = await git(["rev-parse", "--verify", "HEAD"], worktreePath, {
1895
+ const wantUntracked = opts?.includeUntracked !== void 0 ? opts.includeUntracked : !fileOnly && (scope === "commits" && !commitSha || scope === "uncommitted" || scope === "unstaged" || scope === "last_turn");
1896
+ const needsMergeBase = scope === "commits" && !commitSha || includeMeta;
1897
+ const headP = git(["rev-parse", "--verify", "HEAD"], worktreePath, {
1683
1898
  reject: false
1684
1899
  });
1900
+ const untrackedP = wantUntracked ? listUntrackedPaths(worktreePath, pathFilter) : Promise.resolve([]);
1901
+ const head = await headP;
1685
1902
  const hasHead = head.exitCode === 0;
1686
- const untrackedPaths = await listUntrackedPaths(worktreePath);
1687
1903
  if (!hasHead) {
1688
- const files2 = scope === "staged" ? [] : (await listUntrackedFiles(worktreePath, maxHunk)).sort(
1904
+ const untrackedPaths2 = await untrackedP;
1905
+ const files2 = scope === "staged" ? [] : includePatches ? (await listUntrackedFiles(worktreePath, maxHunk, untrackedPaths2)).sort(
1906
+ (a, b) => a.path.localeCompare(b.path)
1907
+ ) : untrackedStubs(untrackedPaths2).sort(
1689
1908
  (a, b) => a.path.localeCompare(b.path)
1690
1909
  );
1691
1910
  const untrackedStat = {
@@ -1699,7 +1918,7 @@ async function getDiff(worktreePath, repoPath, opts) {
1699
1918
  commitSha: null,
1700
1919
  base: "(no commits)",
1701
1920
  files: files2,
1702
- stat: files2.length ? files2.map((f) => ` ${f.path} | untracked`).join("\n") : "(no changes)",
1921
+ stat: formatStat(files2),
1703
1922
  dirty: files2.length > 0,
1704
1923
  unpushed: 0,
1705
1924
  hasLastTurnBase,
@@ -1713,137 +1932,122 @@ async function getDiff(worktreePath, repoPath, opts) {
1713
1932
  }
1714
1933
  };
1715
1934
  }
1716
- let base = opts?.base;
1717
- try {
1718
- base = base ?? await resolveDefaultBranch(repoPath);
1719
- } catch {
1720
- base = "HEAD";
1721
- }
1722
- base = await resolveDiffBaseRef(worktreePath, base, repoPath);
1723
- if (base.startsWith("origin/")) {
1724
- const short = base.slice("origin/".length);
1725
- await git(["fetch", "origin", short, "--quiet"], worktreePath, {
1726
- reject: false
1727
- });
1728
- base = await resolveDiffBaseRef(worktreePath, short, repoPath);
1935
+ let mergeBase = "HEAD";
1936
+ let baseLabel = "HEAD";
1937
+ if (needsMergeBase) {
1938
+ let base = opts?.base;
1939
+ try {
1940
+ base = base ?? await resolveDefaultBranch(repoPath, { network: false });
1941
+ } catch {
1942
+ base = "HEAD";
1943
+ }
1944
+ mergeBase = await resolveMergeBase(worktreePath, base, repoPath);
1945
+ baseLabel = await resolveDiffBaseRef(worktreePath, base, repoPath);
1946
+ }
1947
+ const includeUntracked = wantUntracked;
1948
+ const metaPromise = includeMeta ? Promise.all([
1949
+ computeScopeStats(
1950
+ worktreePath,
1951
+ mergeBase,
1952
+ lastTurnBase,
1953
+ // Cheap: don't wait on the untracked walk just to pad the badge.
1954
+ 0
1955
+ ),
1956
+ listBranchCommits(worktreePath, repoPath, { base: baseLabel }),
1957
+ isDirty(worktreePath),
1958
+ countUnpushedCommits(worktreePath)
1959
+ ]).then(([scopeStats, commits, dirty, unpushed]) => ({
1960
+ scopeStats,
1961
+ commits,
1962
+ dirty,
1963
+ unpushed
1964
+ })) : Promise.resolve({
1965
+ scopeStats: emptyScopeStats(),
1966
+ commits: [],
1967
+ dirty: false,
1968
+ unpushed: 0
1969
+ });
1970
+ if (scope === "last_turn" && !lastTurnBase) {
1971
+ const meta2 = await metaPromise;
1972
+ return {
1973
+ scope,
1974
+ commitSha: null,
1975
+ base: "last turn",
1976
+ files: [],
1977
+ stat: "(no last agent turn)",
1978
+ dirty: meta2.dirty,
1979
+ unpushed: meta2.unpushed,
1980
+ hasLastTurnBase: false,
1981
+ commits: meta2.commits,
1982
+ scopeStats: meta2.scopeStats
1983
+ };
1729
1984
  }
1730
- const mergeBase = await resolveMergeBase(worktreePath, base, repoPath);
1731
- const scopeStats = await computeScopeStats(
1732
- worktreePath,
1733
- mergeBase,
1734
- lastTurnBase,
1735
- untrackedPaths.length
1736
- );
1737
- const includeUntracked = scope === "commits" && !commitSha || scope === "uncommitted" || scope === "unstaged" || scope === "last_turn";
1738
- let nameStatus = "";
1739
- let numstat = "";
1740
- let combinedDiff = "";
1741
- let labelBase = base;
1985
+ let diffArgs;
1986
+ let labelBase = baseLabel;
1742
1987
  if (scope === "staged") {
1743
- const [ns, num, diff] = await Promise.all([
1744
- git(["diff", "--name-status", "--cached"], worktreePath, { reject: false }),
1745
- git(["diff", "--numstat", "--cached"], worktreePath, { reject: false }),
1746
- git(["diff", "--cached"], worktreePath, { reject: false })
1747
- ]);
1748
- nameStatus = ns.stdout;
1749
- numstat = num.stdout;
1750
- combinedDiff = diff.stdout;
1988
+ diffArgs = ["--cached"];
1751
1989
  labelBase = "staged";
1752
1990
  } else if (scope === "unstaged") {
1753
- const [ns, num, diff] = await Promise.all([
1754
- git(["diff", "--name-status"], worktreePath, { reject: false }),
1755
- git(["diff", "--numstat"], worktreePath, { reject: false }),
1756
- git(["diff"], worktreePath, { reject: false })
1757
- ]);
1758
- nameStatus = ns.stdout;
1759
- numstat = num.stdout;
1760
- combinedDiff = diff.stdout;
1991
+ diffArgs = [];
1761
1992
  labelBase = "unstaged";
1762
1993
  } else if (scope === "uncommitted") {
1763
- const [ns, num, diff] = await Promise.all([
1764
- git(["diff", "--name-status", "HEAD"], worktreePath, { reject: false }),
1765
- git(["diff", "--numstat", "HEAD"], worktreePath, { reject: false }),
1766
- git(["diff", "HEAD"], worktreePath, { reject: false })
1767
- ]);
1768
- nameStatus = ns.stdout;
1769
- numstat = num.stdout;
1770
- combinedDiff = diff.stdout;
1994
+ diffArgs = ["HEAD"];
1771
1995
  labelBase = "HEAD";
1772
1996
  } else if (scope === "last_turn") {
1773
- if (!lastTurnBase) {
1774
- const commits2 = await listBranchCommits(worktreePath, repoPath, { base });
1775
- return {
1776
- scope,
1777
- commitSha: null,
1778
- base: "last turn",
1779
- files: [],
1780
- stat: "(no last agent turn)",
1781
- dirty: await isDirty(worktreePath),
1782
- unpushed: await countUnpushedCommits(worktreePath),
1783
- hasLastTurnBase: false,
1784
- commits: commits2,
1785
- scopeStats
1786
- };
1787
- }
1788
- const [ns, num, diff] = await Promise.all([
1789
- git(["diff", "--name-status", lastTurnBase], worktreePath, { reject: false }),
1790
- git(["diff", "--numstat", lastTurnBase], worktreePath, { reject: false }),
1791
- git(["diff", lastTurnBase], worktreePath, { reject: false })
1792
- ]);
1793
- nameStatus = ns.stdout;
1794
- numstat = num.stdout;
1795
- combinedDiff = diff.stdout;
1997
+ diffArgs = [lastTurnBase];
1796
1998
  labelBase = "last turn";
1797
1999
  } else if (scope === "commits" && commitSha) {
1798
- const range = `${commitSha}^!`;
1799
- const [ns, num, diff] = await Promise.all([
1800
- git(["diff", "--name-status", range], worktreePath, { reject: false }),
1801
- git(["diff", "--numstat", range], worktreePath, { reject: false }),
1802
- git(["diff", range], worktreePath, { reject: false })
1803
- ]);
1804
- nameStatus = ns.stdout;
1805
- numstat = num.stdout;
1806
- combinedDiff = diff.stdout;
2000
+ diffArgs = [`${commitSha}^!`];
1807
2001
  labelBase = commitSha.slice(0, 7);
1808
2002
  } else {
1809
- const [ns, num, diff] = await Promise.all([
1810
- git(["diff", "--name-status", mergeBase], worktreePath, { reject: false }),
1811
- git(["diff", "--numstat", mergeBase], worktreePath, { reject: false }),
1812
- git(["diff", mergeBase], worktreePath, { reject: false })
1813
- ]);
1814
- nameStatus = ns.stdout;
1815
- numstat = num.stdout;
1816
- combinedDiff = diff.stdout;
1817
- labelBase = base;
1818
- }
1819
- const commits = await listBranchCommits(worktreePath, repoPath, { base });
2003
+ diffArgs = [mergeBase];
2004
+ labelBase = baseLabel;
2005
+ }
2006
+ const partsPromise = gitDiffParts(
2007
+ worktreePath,
2008
+ diffArgs,
2009
+ includePatches,
2010
+ pathFilter
2011
+ );
2012
+ const [parts, meta, untrackedPaths] = await Promise.all([
2013
+ partsPromise,
2014
+ metaPromise,
2015
+ untrackedP
2016
+ ]);
1820
2017
  const filesMap = /* @__PURE__ */ new Map();
1821
- for (const file of filesFromDiff(nameStatus, numstat, combinedDiff, maxHunk)) {
2018
+ for (const file of filesFromDiff(
2019
+ parts.nameStatus,
2020
+ parts.numstat,
2021
+ parts.combinedDiff,
2022
+ maxHunk
2023
+ )) {
1822
2024
  filesMap.set(file.path, file);
1823
2025
  }
1824
2026
  if (includeUntracked) {
1825
- const untrackedFiles = await listUntrackedFiles(worktreePath, maxHunk);
1826
- for (const file of untrackedFiles) {
2027
+ const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, untrackedPaths) : untrackedStubs(untrackedPaths);
2028
+ for (const file of extra) {
1827
2029
  if (!filesMap.has(file.path)) filesMap.set(file.path, file);
1828
2030
  }
2031
+ } else if (fileOnly && pathFilter && !filesMap.has(pathFilter)) {
2032
+ const maybe = await listUntrackedPaths(worktreePath, pathFilter);
2033
+ if (maybe.length > 0) {
2034
+ const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, maybe) : untrackedStubs(maybe);
2035
+ for (const file of extra) filesMap.set(file.path, file);
2036
+ }
1829
2037
  }
1830
2038
  const files = [...filesMap.values()].sort((a, b) => a.path.localeCompare(b.path));
1831
- const { stdout: statOut } = await git(
1832
- 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],
1833
- worktreePath,
1834
- { reject: false }
1835
- );
1836
2039
  return {
1837
2040
  scope,
1838
2041
  commitSha: scope === "commits" ? commitSha : null,
1839
2042
  base: labelBase,
1840
2043
  files,
1841
- stat: statOut.trim() || (files.length ? `${files.length} file(s)` : "(no changes)"),
1842
- dirty: await isDirty(worktreePath),
1843
- unpushed: await countUnpushedCommits(worktreePath),
2044
+ stat: formatStat(files),
2045
+ dirty: fileOnly || !includeMeta ? files.length > 0 : meta.dirty,
2046
+ unpushed: meta.unpushed,
1844
2047
  hasLastTurnBase,
1845
- commits,
1846
- scopeStats
2048
+ commits: meta.commits,
2049
+ scopeStats: meta.scopeStats,
2050
+ mergeBase: needsMergeBase ? mergeBase : null
1847
2051
  };
1848
2052
  }
1849
2053
  async function listWorktreeFiles(worktreePath, opts) {
@@ -2862,7 +3066,7 @@ async function previewLand(thread) {
2862
3066
  const target = await resolveDefaultBranch(thread.repoPath);
2863
3067
  if (thread.branchName === target || thread.branchName === "main" || thread.branchName === "master") {
2864
3068
  }
2865
- const { stdout: head } = await import("./run-JLN5JK7Q.js").then(
3069
+ const { stdout: head } = await import("./run-V2WZUMJA.js").then(
2866
3070
  ({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], thread.worktreePath)
2867
3071
  );
2868
3072
  const current = head.trim();
@@ -2901,7 +3105,7 @@ async function confirmLand(thread, opts) {
2901
3105
  if (preview.dirty) {
2902
3106
  committed = await commitAll(thread.worktreePath, meta.commitMessage);
2903
3107
  }
2904
- const { git: git2 } = await import("./run-JLN5JK7Q.js");
3108
+ const { git: git2 } = await import("./run-V2WZUMJA.js");
2905
3109
  const { stdout: headOut } = await git2(
2906
3110
  ["rev-parse", "--abbrev-ref", "HEAD"],
2907
3111
  thread.worktreePath,
@@ -2999,7 +3203,7 @@ async function createThread(input, _onSetupLine) {
2999
3203
  return readThread(thread.id) ?? thread;
3000
3204
  }
3001
3205
  async function listLinearIssues(agent, repoPath) {
3002
- const { getAdapter: getAdapter2 } = await import("./agents-EWFD765A.js");
3206
+ const { getAdapter: getAdapter2 } = await import("./agents-JBD7IAGK.js");
3003
3207
  await requireAgent(agent, { requireLinear: true });
3004
3208
  const adapter = getAdapter2(agent);
3005
3209
  if (!adapter.listLinearIssues) {
@@ -3527,7 +3731,7 @@ async function adoptThread(input) {
3527
3731
  throw new Error(`Worktree not found: ${input.worktreePath}`);
3528
3732
  }
3529
3733
  const repoPath = await resolveRepoRoot(input.worktreePath);
3530
- const { stdout: branch } = await import("./run-JLN5JK7Q.js").then(
3734
+ const { stdout: branch } = await import("./run-V2WZUMJA.js").then(
3531
3735
  ({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], input.worktreePath)
3532
3736
  );
3533
3737
  const thread = createEmptyThread({
@@ -3542,7 +3746,7 @@ async function adoptThread(input) {
3542
3746
  messages: input.messages ?? []
3543
3747
  });
3544
3748
  writeThread(thread);
3545
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OVBCSS5Y.js");
3749
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-BWJNGEE6.js");
3546
3750
  await ensureWorkspace2(repoPath);
3547
3751
  return thread;
3548
3752
  }
@@ -5485,6 +5689,11 @@ var Orchestrator = class {
5485
5689
  return getDiff(thread.worktreePath, thread.repoPath, {
5486
5690
  scope: opts?.scope,
5487
5691
  commitSha: opts?.commitSha,
5692
+ base: opts?.base,
5693
+ includePatches: opts?.includePatches,
5694
+ includeMeta: opts?.includeMeta,
5695
+ includeUntracked: opts?.includeUntracked,
5696
+ path: opts?.path,
5488
5697
  lastTurnBase: this.turnBaselines.get(thread.id) ?? null
5489
5698
  });
5490
5699
  }
@@ -5836,7 +6045,7 @@ var Orchestrator = class {
5836
6045
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
5837
6046
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
5838
6047
  try {
5839
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OVBCSS5Y.js");
6048
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-BWJNGEE6.js");
5840
6049
  await ensureWorkspace2(thread.repoPath);
5841
6050
  } catch {
5842
6051
  }
@@ -5878,7 +6087,7 @@ var Orchestrator = class {
5878
6087
  return restored2;
5879
6088
  }
5880
6089
  if (!existsSync13(thread.worktreePath)) {
5881
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-K2JB53R5.js");
6090
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-ZPSKEZFE.js");
5882
6091
  const { execa: execa6 } = await import("execa");
5883
6092
  const slug = thread.worktreePath.split("/").pop();
5884
6093
  const dest = thread.worktreePath;
@@ -5987,7 +6196,7 @@ async function startOrchestration(opts) {
5987
6196
  sourceRef: "default",
5988
6197
  ...createOpts
5989
6198
  }).catch(async () => {
5990
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-K2JB53R5.js");
6199
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-ZPSKEZFE.js");
5991
6200
  const repo = await resolveRepoRoot2(repoPath);
5992
6201
  const def = await resolveDefaultBranch2(repo);
5993
6202
  return createThread({
@@ -7507,6 +7716,7 @@ export {
7507
7716
  coerceOrchestratorAgent,
7508
7717
  collectTakenTeamSlugs,
7509
7718
  commitAll,
7719
+ conductorBundledBinDir,
7510
7720
  conductorDbPath,
7511
7721
  confirmLand,
7512
7722
  connectBrightsyTeam,
@@ -7618,6 +7828,7 @@ export {
7618
7828
  isBrightsyConnected,
7619
7829
  isBrightsyNdjsonLine,
7620
7830
  isCloudCoordinatorThread,
7831
+ isConductorBundledCli,
7621
7832
  isCursorAutoModel,
7622
7833
  isDirty,
7623
7834
  isGhRateLimitError,