@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.
- package/dist/{agents-EWFD765A.js → agents-JBD7IAGK.js} +10 -6
- package/dist/{agents-MD7SCFYX.js → agents-PE3RHQS5.js} +10 -6
- package/dist/{chunk-BBEH2CJE.js → chunk-47RBLBRK.js} +22 -7
- package/dist/{chunk-IFAU2DEY.js → chunk-6Q7H6SMX.js} +22 -7
- package/dist/{chunk-5AG5BUQN.js → chunk-AE5VBOFE.js} +14 -3
- package/dist/{chunk-DZYMNW2A.js → chunk-BTL7EMGT.js} +4 -4
- package/dist/{chunk-TXQ6K2GR.js → chunk-D4DPQ552.js} +14 -3
- package/dist/{chunk-PESJDZTB.js → chunk-DPDGMMGI.js} +2 -2
- package/dist/{chunk-R7GUDEPY.js → chunk-EEBDVLDK.js} +22 -20
- package/dist/{chunk-LRBRQFBU.js → chunk-N5LMEP65.js} +1 -1
- package/dist/{chunk-DNPP7QMK.js → chunk-OICHV4DH.js} +2 -2
- package/dist/{chunk-HTOTTJJX.js → chunk-QQC2D4MY.js} +2 -2
- package/dist/{chunk-I2KGRAXC.js → chunk-REKGFVUX.js} +22 -20
- package/dist/{chunk-YTNLOJPK.js → chunk-ROXEENBT.js} +2 -2
- package/dist/{chunk-EVD4KNKR.js → chunk-VROPG6QF.js} +1 -1
- package/dist/{chunk-AKPEXIKK.js → chunk-VX6ACNXS.js} +1 -1
- package/dist/{connected-teams-CHXO5FFA.js → connected-teams-35EIRJCP.js} +2 -2
- package/dist/{connected-teams-GJTESSTX.js → connected-teams-ZRS53OAT.js} +2 -2
- package/dist/{coordinator-prompt-ILSULI7C.js → coordinator-prompt-HD6IMCKS.js} +3 -3
- package/dist/{coordinator-prompt-E5UGSJES.js → coordinator-prompt-YZYZ5P6P.js} +3 -3
- package/dist/{global-workspace-44UG64NA.js → global-workspace-7P5NG3JZ.js} +4 -4
- package/dist/{global-workspace-5PM5LA6E.js → global-workspace-Z6GF7D2K.js} +4 -4
- package/dist/index.cjs +401 -163
- package/dist/index.d.cts +33 -3
- package/dist/index.d.ts +33 -3
- package/dist/index.js +368 -157
- package/dist/mcp/run-stdio.cjs +397 -163
- package/dist/mcp/run-stdio.js +363 -156
- package/dist/{run-74S2NZWB.js → run-A4RHY7HH.js} +1 -1
- package/dist/{run-JLN5JK7Q.js → run-V2WZUMJA.js} +1 -1
- package/dist/{workspaces-OVBCSS5Y.js → workspaces-BWJNGEE6.js} +5 -5
- package/dist/{workspaces-RXFXQRRF.js → workspaces-O6EZGKQK.js} +5 -5
- package/dist/{worktree-S2N63FLV.js → worktree-VDXLUOWR.js} +2 -2
- package/dist/{worktree-K2JB53R5.js → worktree-ZPSKEZFE.js} +2 -2
- package/package.json +1 -1
package/dist/mcp/run-stdio.js
CHANGED
|
@@ -16,14 +16,14 @@ import {
|
|
|
16
16
|
resolveQuotaFallbackAgent,
|
|
17
17
|
sideboardMcpProfile,
|
|
18
18
|
summarizeTurnStderr
|
|
19
|
-
} from "../chunk-
|
|
20
|
-
import "../chunk-
|
|
19
|
+
} from "../chunk-47RBLBRK.js";
|
|
20
|
+
import "../chunk-VROPG6QF.js";
|
|
21
21
|
import {
|
|
22
22
|
addWorkspace,
|
|
23
23
|
ensureWorkspace,
|
|
24
24
|
removeWorkspace,
|
|
25
25
|
syncWorkspacesFromThreads
|
|
26
|
-
} from "../chunk-
|
|
26
|
+
} from "../chunk-QQC2D4MY.js";
|
|
27
27
|
import {
|
|
28
28
|
extractPresentedPlan,
|
|
29
29
|
readPlanFile,
|
|
@@ -38,13 +38,13 @@ import {
|
|
|
38
38
|
isGlobalThread,
|
|
39
39
|
isOrchestratorThread,
|
|
40
40
|
orchestratorSessionPoisonedByBuiltins
|
|
41
|
-
} from "../chunk-
|
|
41
|
+
} from "../chunk-OICHV4DH.js";
|
|
42
42
|
import {
|
|
43
43
|
coordinatorSystemPrompt,
|
|
44
44
|
coordinatorTurnReminder,
|
|
45
45
|
enrichWorkspacesWithGithub,
|
|
46
46
|
ensureGlobalCoordinatorCwd
|
|
47
|
-
} from "../chunk-
|
|
47
|
+
} from "../chunk-N5LMEP65.js";
|
|
48
48
|
import {
|
|
49
49
|
addPrStackLayer,
|
|
50
50
|
allocateTeamName,
|
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
takenSlugsFromThread,
|
|
82
82
|
threadDisplayLabel,
|
|
83
83
|
worktreeNameFromPath
|
|
84
|
-
} from "../chunk-
|
|
84
|
+
} from "../chunk-REKGFVUX.js";
|
|
85
85
|
import {
|
|
86
86
|
ATTACHMENTS_DIR,
|
|
87
87
|
LEGACY_ATTACHMENTS_DIR,
|
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
gh,
|
|
106
106
|
git,
|
|
107
107
|
run
|
|
108
|
-
} from "../chunk-
|
|
108
|
+
} from "../chunk-AE5VBOFE.js";
|
|
109
109
|
import {
|
|
110
110
|
childEnvWithAppSettings,
|
|
111
111
|
getLinearApiKey,
|
|
@@ -391,9 +391,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
391
391
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
392
392
|
);
|
|
393
393
|
}
|
|
394
|
-
const { isGlobalThread: isGlobalThread2 } = await import("../global-workspace-
|
|
394
|
+
const { isGlobalThread: isGlobalThread2 } = await import("../global-workspace-Z6GF7D2K.js");
|
|
395
395
|
if (isGlobalThread2(thread)) {
|
|
396
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("../coordinator-prompt-
|
|
396
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("../coordinator-prompt-YZYZ5P6P.js");
|
|
397
397
|
ensureGlobalCoordinatorCwd2(
|
|
398
398
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
399
399
|
);
|
|
@@ -1209,7 +1209,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
1209
1209
|
return readThread(thread.id) ?? thread;
|
|
1210
1210
|
}
|
|
1211
1211
|
async function listLinearIssues(agent, repoPath) {
|
|
1212
|
-
const { getAdapter: getAdapter2 } = await import("../agents-
|
|
1212
|
+
const { getAdapter: getAdapter2 } = await import("../agents-PE3RHQS5.js");
|
|
1213
1213
|
await requireAgent(agent, { requireLinear: true });
|
|
1214
1214
|
const adapter = getAdapter2(agent);
|
|
1215
1215
|
if (!adapter.listLinearIssues) {
|
|
@@ -2058,7 +2058,7 @@ async function adoptThread(input) {
|
|
|
2058
2058
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
2059
2059
|
}
|
|
2060
2060
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
2061
|
-
const { stdout: branch } = await import("../run-
|
|
2061
|
+
const { stdout: branch } = await import("../run-A4RHY7HH.js").then(
|
|
2062
2062
|
({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], input.worktreePath)
|
|
2063
2063
|
);
|
|
2064
2064
|
const thread = createEmptyThread({
|
|
@@ -2073,7 +2073,7 @@ async function adoptThread(input) {
|
|
|
2073
2073
|
messages: input.messages ?? []
|
|
2074
2074
|
});
|
|
2075
2075
|
writeThread(thread);
|
|
2076
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-
|
|
2076
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-O6EZGKQK.js");
|
|
2077
2077
|
await ensureWorkspace2(repoPath);
|
|
2078
2078
|
return thread;
|
|
2079
2079
|
}
|
|
@@ -2630,24 +2630,25 @@ function capPatch(patch, maxHunk) {
|
|
|
2630
2630
|
|
|
2631
2631
|
\u2026 truncated (${patch.length - maxHunk} more chars)`;
|
|
2632
2632
|
}
|
|
2633
|
+
var mergeBaseCache = /* @__PURE__ */ new Map();
|
|
2634
|
+
var MERGE_BASE_TTL_MS = 45e3;
|
|
2633
2635
|
async function resolveMergeBase(worktreePath, base, repoPath) {
|
|
2634
2636
|
const baseRef = await resolveDiffBaseRef(worktreePath, base, repoPath);
|
|
2637
|
+
const cacheKey = `${worktreePath}\0${baseRef}`;
|
|
2638
|
+
const hit = mergeBaseCache.get(cacheKey);
|
|
2639
|
+
if (hit && Date.now() - hit.at < MERGE_BASE_TTL_MS) return hit.value;
|
|
2635
2640
|
const { stdout } = await git(["merge-base", baseRef, "HEAD"], worktreePath, {
|
|
2636
2641
|
reject: false
|
|
2637
2642
|
});
|
|
2638
|
-
const mb = stdout.trim();
|
|
2639
|
-
|
|
2643
|
+
const mb = stdout.trim() || baseRef;
|
|
2644
|
+
mergeBaseCache.set(cacheKey, { at: Date.now(), value: mb });
|
|
2645
|
+
return mb;
|
|
2640
2646
|
}
|
|
2641
2647
|
async function countUnpushedCommits(worktreePath) {
|
|
2642
2648
|
const head = await git(["rev-parse", "--abbrev-ref", "HEAD"], worktreePath, {
|
|
2643
2649
|
reject: false
|
|
2644
2650
|
});
|
|
2645
2651
|
const branch = head.stdout.trim();
|
|
2646
|
-
if (branch && branch !== "HEAD") {
|
|
2647
|
-
await git(["fetch", "origin", branch, "--quiet"], worktreePath, {
|
|
2648
|
-
reject: false
|
|
2649
|
-
});
|
|
2650
|
-
}
|
|
2651
2652
|
const upstream = await git(
|
|
2652
2653
|
["rev-list", "--count", "@{upstream}..HEAD"],
|
|
2653
2654
|
worktreePath,
|
|
@@ -2680,11 +2681,37 @@ function splitCombinedDiff(stdout) {
|
|
|
2680
2681
|
}
|
|
2681
2682
|
return map;
|
|
2682
2683
|
}
|
|
2684
|
+
function syntheticAddPatch(path, content, maxHunk) {
|
|
2685
|
+
const lines = content.split("\n");
|
|
2686
|
+
const body = lines.map((l) => `+${l}`).join("\n");
|
|
2687
|
+
const header = `diff --git a/${path} b/${path}
|
|
2688
|
+
new file mode 100644
|
|
2689
|
+
--- /dev/null
|
|
2690
|
+
+++ b/${path}
|
|
2691
|
+
@@ -0,0 +1,${lines.length} @@
|
|
2692
|
+
`;
|
|
2693
|
+
return {
|
|
2694
|
+
path,
|
|
2695
|
+
status: "A",
|
|
2696
|
+
patch: capPatch(`${header}${body}`, maxHunk),
|
|
2697
|
+
additions: lines.length,
|
|
2698
|
+
deletions: 0
|
|
2699
|
+
};
|
|
2700
|
+
}
|
|
2683
2701
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
2702
|
+
const abs = join7(worktreePath, path);
|
|
2703
|
+
try {
|
|
2704
|
+
const st = statSync2(abs);
|
|
2705
|
+
if (st.isFile() && st.size > maxHunk) {
|
|
2706
|
+
const buf = readFileSync5(abs).subarray(0, maxHunk);
|
|
2707
|
+
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
2708
|
+
}
|
|
2709
|
+
} catch {
|
|
2710
|
+
}
|
|
2684
2711
|
const { stdout: patch } = await git(
|
|
2685
|
-
["diff", "--no-index", "--", "/dev/null", path],
|
|
2712
|
+
["diff", "--no-ext-diff", "--no-color", "--no-index", "--", "/dev/null", path],
|
|
2686
2713
|
worktreePath,
|
|
2687
|
-
{ reject: false }
|
|
2714
|
+
{ reject: false, timeoutMs: 4e3 }
|
|
2688
2715
|
);
|
|
2689
2716
|
const normalized = patch.replace(/^diff --git a\/.+? b\/.+?$/m, `diff --git a/${path} b/${path}`).replace(/^--- .*$/m, "--- /dev/null").replace(/^\+\+\+ .*$/m, `+++ b/${path}`);
|
|
2690
2717
|
const addLines = normalized.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++")).length;
|
|
@@ -2696,22 +2723,97 @@ async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
|
2696
2723
|
deletions: 0
|
|
2697
2724
|
};
|
|
2698
2725
|
}
|
|
2699
|
-
async function listUntrackedPaths(worktreePath) {
|
|
2700
|
-
const
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
{ reject: false }
|
|
2704
|
-
);
|
|
2726
|
+
async function listUntrackedPaths(worktreePath, path) {
|
|
2727
|
+
const args = ["ls-files", "-z", "--others", "--exclude-standard"];
|
|
2728
|
+
if (path) args.push("--", path);
|
|
2729
|
+
const { stdout } = await git(args, worktreePath, { reject: false });
|
|
2705
2730
|
return stdout.split("\0").filter(Boolean).filter((p) => !isSideboardScratchPath(p));
|
|
2706
2731
|
}
|
|
2707
|
-
async function listUntrackedFiles(worktreePath, maxHunk) {
|
|
2708
|
-
const
|
|
2709
|
-
if (
|
|
2710
|
-
return Promise.all(
|
|
2732
|
+
async function listUntrackedFiles(worktreePath, maxHunk, paths) {
|
|
2733
|
+
const list = paths ?? await listUntrackedPaths(worktreePath);
|
|
2734
|
+
if (list.length === 0) return [];
|
|
2735
|
+
return Promise.all(list.map((path) => untrackedPatch(worktreePath, path, maxHunk)));
|
|
2736
|
+
}
|
|
2737
|
+
function untrackedStubs(paths) {
|
|
2738
|
+
return paths.map((path) => ({
|
|
2739
|
+
path,
|
|
2740
|
+
status: "A",
|
|
2741
|
+
patch: "",
|
|
2742
|
+
additions: 0,
|
|
2743
|
+
deletions: 0
|
|
2744
|
+
}));
|
|
2745
|
+
}
|
|
2746
|
+
function pathspec(path) {
|
|
2747
|
+
return path ? ["--", path] : [];
|
|
2748
|
+
}
|
|
2749
|
+
function gitDiff(args, cwd, opts) {
|
|
2750
|
+
return git(["diff", "--no-ext-diff", "--no-color", ...args], cwd, {
|
|
2751
|
+
reject: false,
|
|
2752
|
+
timeoutMs: opts?.timeoutMs
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2755
|
+
function fileFromPatch(path, patch, maxHunk) {
|
|
2756
|
+
let status = "M";
|
|
2757
|
+
if (/^new file mode /m.test(patch) || /^--- \/dev\/null/m.test(patch)) {
|
|
2758
|
+
status = "A";
|
|
2759
|
+
} else if (/^deleted file mode /m.test(patch) || /^\+\+\+ \/dev\/null/m.test(patch)) {
|
|
2760
|
+
status = "D";
|
|
2761
|
+
} else if (/^rename from /m.test(patch)) {
|
|
2762
|
+
status = "R";
|
|
2763
|
+
}
|
|
2764
|
+
const additions = patch.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++")).length;
|
|
2765
|
+
const deletions = patch.split("\n").filter((l) => l.startsWith("-") && !l.startsWith("---")).length;
|
|
2766
|
+
return {
|
|
2767
|
+
path,
|
|
2768
|
+
status,
|
|
2769
|
+
patch: capPatch(patch, maxHunk),
|
|
2770
|
+
additions,
|
|
2771
|
+
deletions
|
|
2772
|
+
};
|
|
2773
|
+
}
|
|
2774
|
+
async function gitDiffParts(worktreePath, diffArgs, includePatches, path) {
|
|
2775
|
+
const extra = pathspec(path);
|
|
2776
|
+
if (includePatches) {
|
|
2777
|
+
const diff = await gitDiff([...diffArgs, ...extra], worktreePath, {
|
|
2778
|
+
timeoutMs: 4e3
|
|
2779
|
+
});
|
|
2780
|
+
return { nameStatus: "", numstat: "", combinedDiff: diff.stdout };
|
|
2781
|
+
}
|
|
2782
|
+
const [ns, num] = await Promise.all([
|
|
2783
|
+
gitDiff(["--name-status", ...diffArgs, ...extra], worktreePath),
|
|
2784
|
+
gitDiff(["--numstat", ...diffArgs, ...extra], worktreePath)
|
|
2785
|
+
]);
|
|
2786
|
+
return {
|
|
2787
|
+
nameStatus: ns.stdout,
|
|
2788
|
+
numstat: num.stdout,
|
|
2789
|
+
combinedDiff: ""
|
|
2790
|
+
};
|
|
2791
|
+
}
|
|
2792
|
+
function formatStat(files) {
|
|
2793
|
+
if (files.length === 0) return "(no changes)";
|
|
2794
|
+
const additions = files.reduce((n2, f) => n2 + (f.additions ?? 0), 0);
|
|
2795
|
+
const deletions = files.reduce((n2, f) => n2 + (f.deletions ?? 0), 0);
|
|
2796
|
+
const n = files.length;
|
|
2797
|
+
return `${n} file${n === 1 ? "" : "s"} changed, ${additions} insertions(+), ${deletions} deletions(-)`;
|
|
2798
|
+
}
|
|
2799
|
+
function emptyScopeStats() {
|
|
2800
|
+
const z2 = emptyStat();
|
|
2801
|
+
return {
|
|
2802
|
+
commits: z2,
|
|
2803
|
+
uncommitted: z2,
|
|
2804
|
+
staged: z2,
|
|
2805
|
+
unstaged: z2,
|
|
2806
|
+
last_turn: z2
|
|
2807
|
+
};
|
|
2711
2808
|
}
|
|
2712
2809
|
function filesFromDiff(nameStatus, numstat, combinedDiff, maxHunk) {
|
|
2713
|
-
const counts = parseNumstat(numstat);
|
|
2714
2810
|
const patches = splitCombinedDiff(combinedDiff);
|
|
2811
|
+
if (!nameStatus.trim() && patches.size > 0) {
|
|
2812
|
+
return [...patches.entries()].map(
|
|
2813
|
+
([path, patch]) => fileFromPatch(path, patch, maxHunk)
|
|
2814
|
+
);
|
|
2815
|
+
}
|
|
2816
|
+
const counts = parseNumstat(numstat);
|
|
2715
2817
|
const files = [];
|
|
2716
2818
|
for (const { status, path } of parseNameStatus(nameStatus)) {
|
|
2717
2819
|
const n = counts.get(path);
|
|
@@ -2733,11 +2835,11 @@ async function computeScopeStats(worktreePath, mergeBase, lastTurnBase, untracke
|
|
|
2733
2835
|
{ stdout: unstagedNum },
|
|
2734
2836
|
lastTurnNum
|
|
2735
2837
|
] = await Promise.all([
|
|
2736
|
-
mergeBase ?
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
lastTurnBase ?
|
|
2838
|
+
mergeBase ? gitDiff(["--numstat", mergeBase], worktreePath) : Promise.resolve({ stdout: "" }),
|
|
2839
|
+
gitDiff(["--numstat", "HEAD"], worktreePath),
|
|
2840
|
+
gitDiff(["--numstat", "--cached"], worktreePath),
|
|
2841
|
+
gitDiff(["--numstat"], worktreePath),
|
|
2842
|
+
lastTurnBase ? gitDiff(["--numstat", lastTurnBase], worktreePath) : Promise.resolve({ stdout: "" })
|
|
2741
2843
|
]);
|
|
2742
2844
|
return {
|
|
2743
2845
|
commits: mergeBase ? statFromNumstat(commitsNum, untrackedCount) : emptyStat(),
|
|
@@ -2756,7 +2858,7 @@ async function listBranchCommits(worktreePath, repoPath, opts) {
|
|
|
2756
2858
|
if (head.exitCode !== 0) return [];
|
|
2757
2859
|
let base = opts?.base;
|
|
2758
2860
|
try {
|
|
2759
|
-
base = base ?? await resolveDefaultBranch(repoPath);
|
|
2861
|
+
base = base ?? await resolveDefaultBranch(repoPath, { network: false });
|
|
2760
2862
|
} catch {
|
|
2761
2863
|
base = "HEAD";
|
|
2762
2864
|
}
|
|
@@ -2786,7 +2888,121 @@ async function listBranchCommits(worktreePath, repoPath, opts) {
|
|
|
2786
2888
|
}
|
|
2787
2889
|
return commits;
|
|
2788
2890
|
}
|
|
2891
|
+
var SHA_RE = /^[0-9a-f]{7,40}$/i;
|
|
2892
|
+
function emptyPathDiff(scope, base, hasLastTurnBase, commitSha = null) {
|
|
2893
|
+
return {
|
|
2894
|
+
scope,
|
|
2895
|
+
commitSha: scope === "commits" ? commitSha : null,
|
|
2896
|
+
base,
|
|
2897
|
+
files: [],
|
|
2898
|
+
stat: formatStat([]),
|
|
2899
|
+
dirty: false,
|
|
2900
|
+
unpushed: 0,
|
|
2901
|
+
hasLastTurnBase,
|
|
2902
|
+
commits: [],
|
|
2903
|
+
scopeStats: emptyScopeStats()
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
async function getPathDiff(worktreePath, repoPath, opts) {
|
|
2907
|
+
const { path, scope, commitSha, lastTurnBase, hasLastTurnBase, includePatches, maxHunk } = opts;
|
|
2908
|
+
if (scope === "last_turn" && !lastTurnBase) {
|
|
2909
|
+
return emptyPathDiff(scope, "last turn", false);
|
|
2910
|
+
}
|
|
2911
|
+
let diffArgs;
|
|
2912
|
+
let labelBase;
|
|
2913
|
+
if (scope === "staged") {
|
|
2914
|
+
diffArgs = ["--cached"];
|
|
2915
|
+
labelBase = "staged";
|
|
2916
|
+
} else if (scope === "unstaged") {
|
|
2917
|
+
diffArgs = [];
|
|
2918
|
+
labelBase = "unstaged";
|
|
2919
|
+
} else if (scope === "uncommitted") {
|
|
2920
|
+
diffArgs = ["HEAD"];
|
|
2921
|
+
labelBase = "HEAD";
|
|
2922
|
+
} else if (scope === "last_turn") {
|
|
2923
|
+
diffArgs = [lastTurnBase];
|
|
2924
|
+
labelBase = "last turn";
|
|
2925
|
+
} else if (scope === "commits" && commitSha) {
|
|
2926
|
+
diffArgs = [`${commitSha}^!`];
|
|
2927
|
+
labelBase = commitSha.slice(0, 7);
|
|
2928
|
+
} else if (scope === "commits" && opts.base && SHA_RE.test(opts.base)) {
|
|
2929
|
+
diffArgs = [opts.base];
|
|
2930
|
+
labelBase = opts.base.slice(0, 7);
|
|
2931
|
+
} else if (scope === "commits") {
|
|
2932
|
+
let base = opts.base;
|
|
2933
|
+
try {
|
|
2934
|
+
base = base ?? await resolveDefaultBranch(repoPath, { network: false });
|
|
2935
|
+
} catch {
|
|
2936
|
+
base = "HEAD";
|
|
2937
|
+
}
|
|
2938
|
+
const mergeBase = await resolveMergeBase(worktreePath, base, repoPath);
|
|
2939
|
+
diffArgs = [mergeBase];
|
|
2940
|
+
labelBase = mergeBase;
|
|
2941
|
+
} else {
|
|
2942
|
+
diffArgs = ["HEAD"];
|
|
2943
|
+
labelBase = "HEAD";
|
|
2944
|
+
}
|
|
2945
|
+
const diff = await gitDiff(
|
|
2946
|
+
includePatches ? [...diffArgs, "--", path] : ["--name-status", ...diffArgs, "--", path],
|
|
2947
|
+
worktreePath,
|
|
2948
|
+
{ timeoutMs: 4e3 }
|
|
2949
|
+
);
|
|
2950
|
+
const filesMap = /* @__PURE__ */ new Map();
|
|
2951
|
+
if (includePatches) {
|
|
2952
|
+
const parsed = filesFromDiff("", "", diff.stdout, maxHunk);
|
|
2953
|
+
for (const file of parsed) filesMap.set(file.path, file);
|
|
2954
|
+
if (diff.stdout.trim() && !filesMap.has(path)) {
|
|
2955
|
+
filesMap.set(path, fileFromPatch(path, diff.stdout, maxHunk));
|
|
2956
|
+
}
|
|
2957
|
+
} else {
|
|
2958
|
+
for (const file of filesFromDiff(diff.stdout, "", "", maxHunk)) {
|
|
2959
|
+
filesMap.set(file.path, file);
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
if (filesMap.size === 0) {
|
|
2963
|
+
const maybe = await listUntrackedPaths(worktreePath, path);
|
|
2964
|
+
if (maybe.length > 0) {
|
|
2965
|
+
const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, maybe) : untrackedStubs(maybe);
|
|
2966
|
+
for (const file of extra) filesMap.set(file.path, file);
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
const files = [...filesMap.values()].sort((a, b) => a.path.localeCompare(b.path));
|
|
2970
|
+
return {
|
|
2971
|
+
scope,
|
|
2972
|
+
commitSha: scope === "commits" ? commitSha : null,
|
|
2973
|
+
base: labelBase,
|
|
2974
|
+
files,
|
|
2975
|
+
stat: formatStat(files),
|
|
2976
|
+
dirty: files.length > 0,
|
|
2977
|
+
unpushed: 0,
|
|
2978
|
+
hasLastTurnBase,
|
|
2979
|
+
commits: [],
|
|
2980
|
+
scopeStats: emptyScopeStats(),
|
|
2981
|
+
mergeBase: SHA_RE.test(diffArgs[0] ?? "") ? diffArgs[0] : null
|
|
2982
|
+
};
|
|
2983
|
+
}
|
|
2789
2984
|
async function getDiff(worktreePath, repoPath, opts) {
|
|
2985
|
+
const maxHunk = opts?.maxHunkChars ?? 8e3;
|
|
2986
|
+
const scope = opts?.scope ?? "commits";
|
|
2987
|
+
const lastTurnBase = opts?.lastTurnBase?.trim() || null;
|
|
2988
|
+
const hasLastTurnBase = Boolean(lastTurnBase);
|
|
2989
|
+
const commitSha = opts?.commitSha?.trim() || null;
|
|
2990
|
+
const includePatches = opts?.includePatches ?? true;
|
|
2991
|
+
const pathFilter = opts?.path?.trim() || null;
|
|
2992
|
+
const fileOnly = Boolean(pathFilter);
|
|
2993
|
+
const includeMeta = (opts?.includeMeta ?? true) && !fileOnly;
|
|
2994
|
+
if (fileOnly && pathFilter && !includeMeta) {
|
|
2995
|
+
return getPathDiff(worktreePath, repoPath, {
|
|
2996
|
+
path: pathFilter,
|
|
2997
|
+
scope,
|
|
2998
|
+
commitSha,
|
|
2999
|
+
lastTurnBase,
|
|
3000
|
+
hasLastTurnBase,
|
|
3001
|
+
base: opts?.base,
|
|
3002
|
+
includePatches,
|
|
3003
|
+
maxHunk
|
|
3004
|
+
});
|
|
3005
|
+
}
|
|
2790
3006
|
const status = await inspectGitWorktree(worktreePath);
|
|
2791
3007
|
if (status === "missing_worktree") {
|
|
2792
3008
|
throw new Error("Worktree not found");
|
|
@@ -2794,18 +3010,19 @@ async function getDiff(worktreePath, repoPath, opts) {
|
|
|
2794
3010
|
if (status === "not_git") {
|
|
2795
3011
|
throw new Error("Not a Git repository");
|
|
2796
3012
|
}
|
|
2797
|
-
const
|
|
2798
|
-
const
|
|
2799
|
-
const
|
|
2800
|
-
const hasLastTurnBase = Boolean(lastTurnBase);
|
|
2801
|
-
const commitSha = opts?.commitSha?.trim() || null;
|
|
2802
|
-
const head = await git(["rev-parse", "--verify", "HEAD"], worktreePath, {
|
|
3013
|
+
const wantUntracked = opts?.includeUntracked !== void 0 ? opts.includeUntracked : !fileOnly && (scope === "commits" && !commitSha || scope === "uncommitted" || scope === "unstaged" || scope === "last_turn");
|
|
3014
|
+
const needsMergeBase = scope === "commits" && !commitSha || includeMeta;
|
|
3015
|
+
const headP = git(["rev-parse", "--verify", "HEAD"], worktreePath, {
|
|
2803
3016
|
reject: false
|
|
2804
3017
|
});
|
|
3018
|
+
const untrackedP = wantUntracked ? listUntrackedPaths(worktreePath, pathFilter) : Promise.resolve([]);
|
|
3019
|
+
const head = await headP;
|
|
2805
3020
|
const hasHead = head.exitCode === 0;
|
|
2806
|
-
const untrackedPaths = await listUntrackedPaths(worktreePath);
|
|
2807
3021
|
if (!hasHead) {
|
|
2808
|
-
const
|
|
3022
|
+
const untrackedPaths2 = await untrackedP;
|
|
3023
|
+
const files2 = scope === "staged" ? [] : includePatches ? (await listUntrackedFiles(worktreePath, maxHunk, untrackedPaths2)).sort(
|
|
3024
|
+
(a, b) => a.path.localeCompare(b.path)
|
|
3025
|
+
) : untrackedStubs(untrackedPaths2).sort(
|
|
2809
3026
|
(a, b) => a.path.localeCompare(b.path)
|
|
2810
3027
|
);
|
|
2811
3028
|
const untrackedStat = {
|
|
@@ -2819,7 +3036,7 @@ async function getDiff(worktreePath, repoPath, opts) {
|
|
|
2819
3036
|
commitSha: null,
|
|
2820
3037
|
base: "(no commits)",
|
|
2821
3038
|
files: files2,
|
|
2822
|
-
stat: files2
|
|
3039
|
+
stat: formatStat(files2),
|
|
2823
3040
|
dirty: files2.length > 0,
|
|
2824
3041
|
unpushed: 0,
|
|
2825
3042
|
hasLastTurnBase,
|
|
@@ -2833,137 +3050,122 @@ async function getDiff(worktreePath, repoPath, opts) {
|
|
|
2833
3050
|
}
|
|
2834
3051
|
};
|
|
2835
3052
|
}
|
|
2836
|
-
let
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
await
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
3053
|
+
let mergeBase = "HEAD";
|
|
3054
|
+
let baseLabel = "HEAD";
|
|
3055
|
+
if (needsMergeBase) {
|
|
3056
|
+
let base = opts?.base;
|
|
3057
|
+
try {
|
|
3058
|
+
base = base ?? await resolveDefaultBranch(repoPath, { network: false });
|
|
3059
|
+
} catch {
|
|
3060
|
+
base = "HEAD";
|
|
3061
|
+
}
|
|
3062
|
+
mergeBase = await resolveMergeBase(worktreePath, base, repoPath);
|
|
3063
|
+
baseLabel = await resolveDiffBaseRef(worktreePath, base, repoPath);
|
|
3064
|
+
}
|
|
3065
|
+
const includeUntracked = wantUntracked;
|
|
3066
|
+
const metaPromise = includeMeta ? Promise.all([
|
|
3067
|
+
computeScopeStats(
|
|
3068
|
+
worktreePath,
|
|
3069
|
+
mergeBase,
|
|
3070
|
+
lastTurnBase,
|
|
3071
|
+
// Cheap: don't wait on the untracked walk just to pad the badge.
|
|
3072
|
+
0
|
|
3073
|
+
),
|
|
3074
|
+
listBranchCommits(worktreePath, repoPath, { base: baseLabel }),
|
|
3075
|
+
isDirty(worktreePath),
|
|
3076
|
+
countUnpushedCommits(worktreePath)
|
|
3077
|
+
]).then(([scopeStats, commits, dirty, unpushed]) => ({
|
|
3078
|
+
scopeStats,
|
|
3079
|
+
commits,
|
|
3080
|
+
dirty,
|
|
3081
|
+
unpushed
|
|
3082
|
+
})) : Promise.resolve({
|
|
3083
|
+
scopeStats: emptyScopeStats(),
|
|
3084
|
+
commits: [],
|
|
3085
|
+
dirty: false,
|
|
3086
|
+
unpushed: 0
|
|
3087
|
+
});
|
|
3088
|
+
if (scope === "last_turn" && !lastTurnBase) {
|
|
3089
|
+
const meta2 = await metaPromise;
|
|
3090
|
+
return {
|
|
3091
|
+
scope,
|
|
3092
|
+
commitSha: null,
|
|
3093
|
+
base: "last turn",
|
|
3094
|
+
files: [],
|
|
3095
|
+
stat: "(no last agent turn)",
|
|
3096
|
+
dirty: meta2.dirty,
|
|
3097
|
+
unpushed: meta2.unpushed,
|
|
3098
|
+
hasLastTurnBase: false,
|
|
3099
|
+
commits: meta2.commits,
|
|
3100
|
+
scopeStats: meta2.scopeStats
|
|
3101
|
+
};
|
|
2849
3102
|
}
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
worktreePath,
|
|
2853
|
-
mergeBase,
|
|
2854
|
-
lastTurnBase,
|
|
2855
|
-
untrackedPaths.length
|
|
2856
|
-
);
|
|
2857
|
-
const includeUntracked = scope === "commits" && !commitSha || scope === "uncommitted" || scope === "unstaged" || scope === "last_turn";
|
|
2858
|
-
let nameStatus = "";
|
|
2859
|
-
let numstat = "";
|
|
2860
|
-
let combinedDiff = "";
|
|
2861
|
-
let labelBase = base;
|
|
3103
|
+
let diffArgs;
|
|
3104
|
+
let labelBase = baseLabel;
|
|
2862
3105
|
if (scope === "staged") {
|
|
2863
|
-
|
|
2864
|
-
git(["diff", "--name-status", "--cached"], worktreePath, { reject: false }),
|
|
2865
|
-
git(["diff", "--numstat", "--cached"], worktreePath, { reject: false }),
|
|
2866
|
-
git(["diff", "--cached"], worktreePath, { reject: false })
|
|
2867
|
-
]);
|
|
2868
|
-
nameStatus = ns.stdout;
|
|
2869
|
-
numstat = num.stdout;
|
|
2870
|
-
combinedDiff = diff.stdout;
|
|
3106
|
+
diffArgs = ["--cached"];
|
|
2871
3107
|
labelBase = "staged";
|
|
2872
3108
|
} else if (scope === "unstaged") {
|
|
2873
|
-
|
|
2874
|
-
git(["diff", "--name-status"], worktreePath, { reject: false }),
|
|
2875
|
-
git(["diff", "--numstat"], worktreePath, { reject: false }),
|
|
2876
|
-
git(["diff"], worktreePath, { reject: false })
|
|
2877
|
-
]);
|
|
2878
|
-
nameStatus = ns.stdout;
|
|
2879
|
-
numstat = num.stdout;
|
|
2880
|
-
combinedDiff = diff.stdout;
|
|
3109
|
+
diffArgs = [];
|
|
2881
3110
|
labelBase = "unstaged";
|
|
2882
3111
|
} else if (scope === "uncommitted") {
|
|
2883
|
-
|
|
2884
|
-
git(["diff", "--name-status", "HEAD"], worktreePath, { reject: false }),
|
|
2885
|
-
git(["diff", "--numstat", "HEAD"], worktreePath, { reject: false }),
|
|
2886
|
-
git(["diff", "HEAD"], worktreePath, { reject: false })
|
|
2887
|
-
]);
|
|
2888
|
-
nameStatus = ns.stdout;
|
|
2889
|
-
numstat = num.stdout;
|
|
2890
|
-
combinedDiff = diff.stdout;
|
|
3112
|
+
diffArgs = ["HEAD"];
|
|
2891
3113
|
labelBase = "HEAD";
|
|
2892
3114
|
} else if (scope === "last_turn") {
|
|
2893
|
-
|
|
2894
|
-
const commits2 = await listBranchCommits(worktreePath, repoPath, { base });
|
|
2895
|
-
return {
|
|
2896
|
-
scope,
|
|
2897
|
-
commitSha: null,
|
|
2898
|
-
base: "last turn",
|
|
2899
|
-
files: [],
|
|
2900
|
-
stat: "(no last agent turn)",
|
|
2901
|
-
dirty: await isDirty(worktreePath),
|
|
2902
|
-
unpushed: await countUnpushedCommits(worktreePath),
|
|
2903
|
-
hasLastTurnBase: false,
|
|
2904
|
-
commits: commits2,
|
|
2905
|
-
scopeStats
|
|
2906
|
-
};
|
|
2907
|
-
}
|
|
2908
|
-
const [ns, num, diff] = await Promise.all([
|
|
2909
|
-
git(["diff", "--name-status", lastTurnBase], worktreePath, { reject: false }),
|
|
2910
|
-
git(["diff", "--numstat", lastTurnBase], worktreePath, { reject: false }),
|
|
2911
|
-
git(["diff", lastTurnBase], worktreePath, { reject: false })
|
|
2912
|
-
]);
|
|
2913
|
-
nameStatus = ns.stdout;
|
|
2914
|
-
numstat = num.stdout;
|
|
2915
|
-
combinedDiff = diff.stdout;
|
|
3115
|
+
diffArgs = [lastTurnBase];
|
|
2916
3116
|
labelBase = "last turn";
|
|
2917
3117
|
} else if (scope === "commits" && commitSha) {
|
|
2918
|
-
|
|
2919
|
-
const [ns, num, diff] = await Promise.all([
|
|
2920
|
-
git(["diff", "--name-status", range], worktreePath, { reject: false }),
|
|
2921
|
-
git(["diff", "--numstat", range], worktreePath, { reject: false }),
|
|
2922
|
-
git(["diff", range], worktreePath, { reject: false })
|
|
2923
|
-
]);
|
|
2924
|
-
nameStatus = ns.stdout;
|
|
2925
|
-
numstat = num.stdout;
|
|
2926
|
-
combinedDiff = diff.stdout;
|
|
3118
|
+
diffArgs = [`${commitSha}^!`];
|
|
2927
3119
|
labelBase = commitSha.slice(0, 7);
|
|
2928
3120
|
} else {
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
3121
|
+
diffArgs = [mergeBase];
|
|
3122
|
+
labelBase = baseLabel;
|
|
3123
|
+
}
|
|
3124
|
+
const partsPromise = gitDiffParts(
|
|
3125
|
+
worktreePath,
|
|
3126
|
+
diffArgs,
|
|
3127
|
+
includePatches,
|
|
3128
|
+
pathFilter
|
|
3129
|
+
);
|
|
3130
|
+
const [parts, meta, untrackedPaths] = await Promise.all([
|
|
3131
|
+
partsPromise,
|
|
3132
|
+
metaPromise,
|
|
3133
|
+
untrackedP
|
|
3134
|
+
]);
|
|
2940
3135
|
const filesMap = /* @__PURE__ */ new Map();
|
|
2941
|
-
for (const file of filesFromDiff(
|
|
3136
|
+
for (const file of filesFromDiff(
|
|
3137
|
+
parts.nameStatus,
|
|
3138
|
+
parts.numstat,
|
|
3139
|
+
parts.combinedDiff,
|
|
3140
|
+
maxHunk
|
|
3141
|
+
)) {
|
|
2942
3142
|
filesMap.set(file.path, file);
|
|
2943
3143
|
}
|
|
2944
3144
|
if (includeUntracked) {
|
|
2945
|
-
const
|
|
2946
|
-
for (const file of
|
|
3145
|
+
const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, untrackedPaths) : untrackedStubs(untrackedPaths);
|
|
3146
|
+
for (const file of extra) {
|
|
2947
3147
|
if (!filesMap.has(file.path)) filesMap.set(file.path, file);
|
|
2948
3148
|
}
|
|
3149
|
+
} else if (fileOnly && pathFilter && !filesMap.has(pathFilter)) {
|
|
3150
|
+
const maybe = await listUntrackedPaths(worktreePath, pathFilter);
|
|
3151
|
+
if (maybe.length > 0) {
|
|
3152
|
+
const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, maybe) : untrackedStubs(maybe);
|
|
3153
|
+
for (const file of extra) filesMap.set(file.path, file);
|
|
3154
|
+
}
|
|
2949
3155
|
}
|
|
2950
3156
|
const files = [...filesMap.values()].sort((a, b) => a.path.localeCompare(b.path));
|
|
2951
|
-
const { stdout: statOut } = await git(
|
|
2952
|
-
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],
|
|
2953
|
-
worktreePath,
|
|
2954
|
-
{ reject: false }
|
|
2955
|
-
);
|
|
2956
3157
|
return {
|
|
2957
3158
|
scope,
|
|
2958
3159
|
commitSha: scope === "commits" ? commitSha : null,
|
|
2959
3160
|
base: labelBase,
|
|
2960
3161
|
files,
|
|
2961
|
-
stat:
|
|
2962
|
-
dirty:
|
|
2963
|
-
unpushed:
|
|
3162
|
+
stat: formatStat(files),
|
|
3163
|
+
dirty: fileOnly || !includeMeta ? files.length > 0 : meta.dirty,
|
|
3164
|
+
unpushed: meta.unpushed,
|
|
2964
3165
|
hasLastTurnBase,
|
|
2965
|
-
commits,
|
|
2966
|
-
scopeStats
|
|
3166
|
+
commits: meta.commits,
|
|
3167
|
+
scopeStats: meta.scopeStats,
|
|
3168
|
+
mergeBase: needsMergeBase ? mergeBase : null
|
|
2967
3169
|
};
|
|
2968
3170
|
}
|
|
2969
3171
|
async function listWorktreeFiles(worktreePath, opts) {
|
|
@@ -3179,7 +3381,7 @@ async function previewLand(thread) {
|
|
|
3179
3381
|
const target = await resolveDefaultBranch(thread.repoPath);
|
|
3180
3382
|
if (thread.branchName === target || thread.branchName === "main" || thread.branchName === "master") {
|
|
3181
3383
|
}
|
|
3182
|
-
const { stdout: head } = await import("../run-
|
|
3384
|
+
const { stdout: head } = await import("../run-A4RHY7HH.js").then(
|
|
3183
3385
|
({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], thread.worktreePath)
|
|
3184
3386
|
);
|
|
3185
3387
|
const current = head.trim();
|
|
@@ -3218,7 +3420,7 @@ async function confirmLand(thread, opts) {
|
|
|
3218
3420
|
if (preview.dirty) {
|
|
3219
3421
|
committed = await commitAll(thread.worktreePath, meta.commitMessage);
|
|
3220
3422
|
}
|
|
3221
|
-
const { git: git2 } = await import("../run-
|
|
3423
|
+
const { git: git2 } = await import("../run-A4RHY7HH.js");
|
|
3222
3424
|
const { stdout: headOut } = await git2(
|
|
3223
3425
|
["rev-parse", "--abbrev-ref", "HEAD"],
|
|
3224
3426
|
thread.worktreePath,
|
|
@@ -4902,6 +5104,11 @@ var Orchestrator = class {
|
|
|
4902
5104
|
return getDiff(thread.worktreePath, thread.repoPath, {
|
|
4903
5105
|
scope: opts?.scope,
|
|
4904
5106
|
commitSha: opts?.commitSha,
|
|
5107
|
+
base: opts?.base,
|
|
5108
|
+
includePatches: opts?.includePatches,
|
|
5109
|
+
includeMeta: opts?.includeMeta,
|
|
5110
|
+
includeUntracked: opts?.includeUntracked,
|
|
5111
|
+
path: opts?.path,
|
|
4905
5112
|
lastTurnBase: this.turnBaselines.get(thread.id) ?? null
|
|
4906
5113
|
});
|
|
4907
5114
|
}
|
|
@@ -5253,7 +5460,7 @@ var Orchestrator = class {
|
|
|
5253
5460
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
5254
5461
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
5255
5462
|
try {
|
|
5256
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-
|
|
5463
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-O6EZGKQK.js");
|
|
5257
5464
|
await ensureWorkspace2(thread.repoPath);
|
|
5258
5465
|
} catch {
|
|
5259
5466
|
}
|
|
@@ -5295,7 +5502,7 @@ var Orchestrator = class {
|
|
|
5295
5502
|
return restored2;
|
|
5296
5503
|
}
|
|
5297
5504
|
if (!existsSync13(thread.worktreePath)) {
|
|
5298
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("../worktree-
|
|
5505
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("../worktree-VDXLUOWR.js");
|
|
5299
5506
|
const { execa: execa6 } = await import("execa");
|
|
5300
5507
|
const slug = thread.worktreePath.split("/").pop();
|
|
5301
5508
|
const dest = thread.worktreePath;
|