webmux 0.23.0 → 0.24.1
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/backend/dist/server.js +199 -117
- package/bin/webmux.js +180 -108
- package/frontend/dist/assets/index-BRoz1T_W.js +151 -0
- package/frontend/dist/assets/{index-Dxe_PLr0.css → index-D9R5ycW2.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-C5K6jdn8.js +0 -150
package/backend/dist/server.js
CHANGED
|
@@ -8968,6 +8968,9 @@ class BunGitGateway {
|
|
|
8968
8968
|
readWorktreeStatus(cwd) {
|
|
8969
8969
|
return readGitWorktreeStatus(cwd);
|
|
8970
8970
|
}
|
|
8971
|
+
readStatus(cwd) {
|
|
8972
|
+
return runGit(["status", "--short", "--untracked-files=all"], cwd);
|
|
8973
|
+
}
|
|
8971
8974
|
createWorktree(opts) {
|
|
8972
8975
|
const args = ["worktree", "add"];
|
|
8973
8976
|
if (opts.mode === "new") {
|
|
@@ -9211,6 +9214,18 @@ function toErrorMessage2(error) {
|
|
|
9211
9214
|
function stringifyStartupEnvValue(value) {
|
|
9212
9215
|
return typeof value === "boolean" ? String(value) : value;
|
|
9213
9216
|
}
|
|
9217
|
+
function prefixAgentBranch(agent, branch) {
|
|
9218
|
+
return `${agent}-${branch}`;
|
|
9219
|
+
}
|
|
9220
|
+
function buildCreateWorktreeTargets(branch, agentSelection) {
|
|
9221
|
+
if (agentSelection === "both") {
|
|
9222
|
+
return [
|
|
9223
|
+
{ branch: prefixAgentBranch("claude", branch), agent: "claude" },
|
|
9224
|
+
{ branch: prefixAgentBranch("codex", branch), agent: "codex" }
|
|
9225
|
+
];
|
|
9226
|
+
}
|
|
9227
|
+
return [{ branch, agent: agentSelection }];
|
|
9228
|
+
}
|
|
9214
9229
|
|
|
9215
9230
|
class LifecycleError extends Error {
|
|
9216
9231
|
status;
|
|
@@ -9225,114 +9240,47 @@ class LifecycleService {
|
|
|
9225
9240
|
constructor(deps) {
|
|
9226
9241
|
this.deps = deps;
|
|
9227
9242
|
}
|
|
9228
|
-
async
|
|
9243
|
+
async createWorktrees(input) {
|
|
9229
9244
|
const mode = input.mode ?? "new";
|
|
9230
|
-
const
|
|
9231
|
-
if (
|
|
9232
|
-
throw new LifecycleError("
|
|
9233
|
-
}
|
|
9234
|
-
if (requestedBaseBranch && mode === "existing") {
|
|
9235
|
-
throw new LifecycleError("Base branch is only supported for new worktrees", 400);
|
|
9245
|
+
const agentSelection = input.agent ?? this.deps.config.workspace.defaultAgent;
|
|
9246
|
+
if (agentSelection === "both" && mode === "existing") {
|
|
9247
|
+
throw new LifecycleError("Creating both agents is only supported for new worktrees", 400);
|
|
9236
9248
|
}
|
|
9237
9249
|
const branch = await this.resolveBranch(input.branch, input.prompt, mode);
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
}
|
|
9241
|
-
const baseBranch = mode === "new" ? requestedBaseBranch || this.deps.config.workspace.mainBranch : undefined;
|
|
9242
|
-
const branchAvailability = this.resolveBranchAvailability(branch, mode);
|
|
9243
|
-
const { profileName, profile } = this.resolveProfile(input.profile);
|
|
9244
|
-
const agent = this.resolveAgent(input.agent);
|
|
9245
|
-
const worktreePath = this.resolveWorktreePath(branch);
|
|
9246
|
-
const createProgressBase = {
|
|
9247
|
-
branch,
|
|
9248
|
-
...baseBranch ? { baseBranch } : {},
|
|
9249
|
-
path: worktreePath,
|
|
9250
|
-
profile: profileName,
|
|
9251
|
-
agent
|
|
9252
|
-
};
|
|
9253
|
-
const deleteBranchOnRollback = mode === "new" || branchAvailability.deleteBranchOnRollback;
|
|
9254
|
-
let initialized = null;
|
|
9250
|
+
const targets = buildCreateWorktreeTargets(branch, agentSelection);
|
|
9251
|
+
const createdBranches = [];
|
|
9255
9252
|
try {
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
mode,
|
|
9266
|
-
...baseBranch ? { baseBranch } : {},
|
|
9267
|
-
...branchAvailability.startPoint ? { startPoint: branchAvailability.startPoint } : {},
|
|
9268
|
-
profile: profileName,
|
|
9269
|
-
agent,
|
|
9270
|
-
runtime: profile.runtime,
|
|
9271
|
-
startupEnvValues: await this.buildStartupEnvValues(input.envOverrides),
|
|
9272
|
-
allocatedPorts: await this.allocatePorts(),
|
|
9273
|
-
runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: worktreePath },
|
|
9274
|
-
controlUrl: this.controlUrl(),
|
|
9275
|
-
controlToken: await this.deps.getControlToken(),
|
|
9276
|
-
deleteBranchOnRollback
|
|
9277
|
-
}, {
|
|
9278
|
-
git: this.deps.git
|
|
9279
|
-
});
|
|
9280
|
-
await this.reportCreateProgress({
|
|
9281
|
-
...createProgressBase,
|
|
9282
|
-
phase: "running_post_create_hook"
|
|
9283
|
-
});
|
|
9284
|
-
await this.runLifecycleHook({
|
|
9285
|
-
name: "postCreate",
|
|
9286
|
-
command: this.deps.config.lifecycleHooks.postCreate,
|
|
9287
|
-
meta: initialized.meta,
|
|
9288
|
-
worktreePath
|
|
9289
|
-
});
|
|
9290
|
-
initialized = await this.refreshManagedArtifactsFromMeta({
|
|
9291
|
-
gitDir: initialized.paths.gitDir,
|
|
9292
|
-
meta: initialized.meta,
|
|
9293
|
-
worktreePath
|
|
9294
|
-
});
|
|
9295
|
-
await this.reportCreateProgress({
|
|
9296
|
-
...createProgressBase,
|
|
9297
|
-
phase: "preparing_runtime"
|
|
9298
|
-
});
|
|
9299
|
-
await ensureAgentRuntimeArtifacts({
|
|
9300
|
-
gitDir: initialized.paths.gitDir,
|
|
9301
|
-
worktreePath
|
|
9302
|
-
});
|
|
9303
|
-
await this.reportCreateProgress({
|
|
9304
|
-
...createProgressBase,
|
|
9305
|
-
phase: "starting_session"
|
|
9306
|
-
});
|
|
9307
|
-
await this.materializeRuntimeSession({
|
|
9308
|
-
branch,
|
|
9309
|
-
profile,
|
|
9310
|
-
agent,
|
|
9311
|
-
initialized,
|
|
9312
|
-
worktreePath,
|
|
9313
|
-
prompt: input.prompt,
|
|
9314
|
-
launchMode: "fresh"
|
|
9315
|
-
});
|
|
9316
|
-
await this.reportCreateProgress({
|
|
9317
|
-
...createProgressBase,
|
|
9318
|
-
phase: "reconciling"
|
|
9319
|
-
});
|
|
9320
|
-
await this.deps.reconciliation.reconcile(this.deps.projectRoot, { force: true });
|
|
9321
|
-
return {
|
|
9322
|
-
branch,
|
|
9323
|
-
worktreeId: initialized.meta.worktreeId
|
|
9324
|
-
};
|
|
9253
|
+
for (const target of targets) {
|
|
9254
|
+
const created = await this.createResolvedWorktree({
|
|
9255
|
+
...input,
|
|
9256
|
+
mode,
|
|
9257
|
+
branch: target.branch,
|
|
9258
|
+
agent: target.agent
|
|
9259
|
+
});
|
|
9260
|
+
createdBranches.push(created.branch);
|
|
9261
|
+
}
|
|
9325
9262
|
} catch (error) {
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
throw this.wrapOperationError(new Error(`${toErrorMessage2(error)}; ${cleanupError}`));
|
|
9330
|
-
}
|
|
9263
|
+
const rollbackError = await this.rollbackCreatedWorktrees(createdBranches);
|
|
9264
|
+
if (rollbackError) {
|
|
9265
|
+
throw this.wrapOperationError(new Error(`${toErrorMessage2(error)}; ${rollbackError}`));
|
|
9331
9266
|
}
|
|
9332
9267
|
throw this.wrapOperationError(error);
|
|
9333
|
-
} finally {
|
|
9334
|
-
await this.finishCreateProgress(branch);
|
|
9335
9268
|
}
|
|
9269
|
+
return {
|
|
9270
|
+
primaryBranch: createdBranches[0],
|
|
9271
|
+
branches: createdBranches
|
|
9272
|
+
};
|
|
9273
|
+
}
|
|
9274
|
+
async createWorktree(input) {
|
|
9275
|
+
const mode = input.mode ?? "new";
|
|
9276
|
+
const branch = await this.resolveBranch(input.branch, input.prompt, mode);
|
|
9277
|
+
const agent = this.resolveAgent(input.agent);
|
|
9278
|
+
return await this.createResolvedWorktree({
|
|
9279
|
+
...input,
|
|
9280
|
+
mode,
|
|
9281
|
+
branch,
|
|
9282
|
+
agent
|
|
9283
|
+
});
|
|
9336
9284
|
}
|
|
9337
9285
|
async openWorktree(branch) {
|
|
9338
9286
|
try {
|
|
@@ -9733,6 +9681,123 @@ class LifecycleService {
|
|
|
9733
9681
|
async finishCreateProgress(branch) {
|
|
9734
9682
|
await this.deps.onCreateFinished?.(branch);
|
|
9735
9683
|
}
|
|
9684
|
+
async rollbackCreatedWorktrees(branches) {
|
|
9685
|
+
const cleanupErrors = [];
|
|
9686
|
+
for (const branch of [...branches].reverse()) {
|
|
9687
|
+
try {
|
|
9688
|
+
await this.removeWorktree(branch);
|
|
9689
|
+
} catch (error) {
|
|
9690
|
+
cleanupErrors.push(`rollback failed for ${branch}: ${toErrorMessage2(error)}`);
|
|
9691
|
+
}
|
|
9692
|
+
}
|
|
9693
|
+
return cleanupErrors.length > 0 ? cleanupErrors.join("; ") : null;
|
|
9694
|
+
}
|
|
9695
|
+
async createResolvedWorktree(input) {
|
|
9696
|
+
const requestedBaseBranch = input.baseBranch?.trim();
|
|
9697
|
+
if (requestedBaseBranch && !isValidBranchName(requestedBaseBranch)) {
|
|
9698
|
+
throw new LifecycleError("Invalid base branch name", 400);
|
|
9699
|
+
}
|
|
9700
|
+
if (requestedBaseBranch && input.mode === "existing") {
|
|
9701
|
+
throw new LifecycleError("Base branch is only supported for new worktrees", 400);
|
|
9702
|
+
}
|
|
9703
|
+
if (requestedBaseBranch && requestedBaseBranch === input.branch) {
|
|
9704
|
+
throw new LifecycleError("Base branch must differ from branch name", 400);
|
|
9705
|
+
}
|
|
9706
|
+
const baseBranch = input.mode === "new" ? requestedBaseBranch || this.deps.config.workspace.mainBranch : undefined;
|
|
9707
|
+
const branchAvailability = this.resolveBranchAvailability(input.branch, input.mode);
|
|
9708
|
+
const { profileName, profile } = this.resolveProfile(input.profile);
|
|
9709
|
+
const worktreePath = this.resolveWorktreePath(input.branch);
|
|
9710
|
+
const createProgressBase = {
|
|
9711
|
+
branch: input.branch,
|
|
9712
|
+
...baseBranch ? { baseBranch } : {},
|
|
9713
|
+
path: worktreePath,
|
|
9714
|
+
profile: profileName,
|
|
9715
|
+
agent: input.agent
|
|
9716
|
+
};
|
|
9717
|
+
const deleteBranchOnRollback = input.mode === "new" || branchAvailability.deleteBranchOnRollback;
|
|
9718
|
+
let initialized = null;
|
|
9719
|
+
try {
|
|
9720
|
+
await this.reportCreateProgress({
|
|
9721
|
+
...createProgressBase,
|
|
9722
|
+
phase: "creating_worktree"
|
|
9723
|
+
});
|
|
9724
|
+
await mkdir4(dirname4(worktreePath), { recursive: true });
|
|
9725
|
+
initialized = await createManagedWorktree({
|
|
9726
|
+
repoRoot: this.deps.projectRoot,
|
|
9727
|
+
worktreePath,
|
|
9728
|
+
branch: input.branch,
|
|
9729
|
+
mode: input.mode,
|
|
9730
|
+
...baseBranch ? { baseBranch } : {},
|
|
9731
|
+
...branchAvailability.startPoint ? { startPoint: branchAvailability.startPoint } : {},
|
|
9732
|
+
profile: profileName,
|
|
9733
|
+
agent: input.agent,
|
|
9734
|
+
runtime: profile.runtime,
|
|
9735
|
+
startupEnvValues: await this.buildStartupEnvValues(input.envOverrides),
|
|
9736
|
+
allocatedPorts: await this.allocatePorts(),
|
|
9737
|
+
runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: worktreePath },
|
|
9738
|
+
controlUrl: this.controlUrl(),
|
|
9739
|
+
controlToken: await this.deps.getControlToken(),
|
|
9740
|
+
deleteBranchOnRollback
|
|
9741
|
+
}, {
|
|
9742
|
+
git: this.deps.git
|
|
9743
|
+
});
|
|
9744
|
+
await this.reportCreateProgress({
|
|
9745
|
+
...createProgressBase,
|
|
9746
|
+
phase: "running_post_create_hook"
|
|
9747
|
+
});
|
|
9748
|
+
await this.runLifecycleHook({
|
|
9749
|
+
name: "postCreate",
|
|
9750
|
+
command: this.deps.config.lifecycleHooks.postCreate,
|
|
9751
|
+
meta: initialized.meta,
|
|
9752
|
+
worktreePath
|
|
9753
|
+
});
|
|
9754
|
+
initialized = await this.refreshManagedArtifactsFromMeta({
|
|
9755
|
+
gitDir: initialized.paths.gitDir,
|
|
9756
|
+
meta: initialized.meta,
|
|
9757
|
+
worktreePath
|
|
9758
|
+
});
|
|
9759
|
+
await this.reportCreateProgress({
|
|
9760
|
+
...createProgressBase,
|
|
9761
|
+
phase: "preparing_runtime"
|
|
9762
|
+
});
|
|
9763
|
+
await ensureAgentRuntimeArtifacts({
|
|
9764
|
+
gitDir: initialized.paths.gitDir,
|
|
9765
|
+
worktreePath
|
|
9766
|
+
});
|
|
9767
|
+
await this.reportCreateProgress({
|
|
9768
|
+
...createProgressBase,
|
|
9769
|
+
phase: "starting_session"
|
|
9770
|
+
});
|
|
9771
|
+
await this.materializeRuntimeSession({
|
|
9772
|
+
branch: input.branch,
|
|
9773
|
+
profile,
|
|
9774
|
+
agent: input.agent,
|
|
9775
|
+
initialized,
|
|
9776
|
+
worktreePath,
|
|
9777
|
+
prompt: input.prompt,
|
|
9778
|
+
launchMode: "fresh"
|
|
9779
|
+
});
|
|
9780
|
+
await this.reportCreateProgress({
|
|
9781
|
+
...createProgressBase,
|
|
9782
|
+
phase: "reconciling"
|
|
9783
|
+
});
|
|
9784
|
+
await this.deps.reconciliation.reconcile(this.deps.projectRoot, { force: true });
|
|
9785
|
+
return {
|
|
9786
|
+
branch: input.branch,
|
|
9787
|
+
worktreeId: initialized.meta.worktreeId
|
|
9788
|
+
};
|
|
9789
|
+
} catch (error) {
|
|
9790
|
+
if (initialized) {
|
|
9791
|
+
const cleanupError = await this.cleanupFailedCreate(input.branch, worktreePath, profile.runtime, deleteBranchOnRollback);
|
|
9792
|
+
if (cleanupError) {
|
|
9793
|
+
throw this.wrapOperationError(new Error(`${toErrorMessage2(error)}; ${cleanupError}`));
|
|
9794
|
+
}
|
|
9795
|
+
}
|
|
9796
|
+
throw this.wrapOperationError(error);
|
|
9797
|
+
} finally {
|
|
9798
|
+
await this.finishCreateProgress(input.branch);
|
|
9799
|
+
}
|
|
9800
|
+
}
|
|
9736
9801
|
wrapOperationError(error) {
|
|
9737
9802
|
if (error instanceof LifecycleError) {
|
|
9738
9803
|
return error;
|
|
@@ -10849,6 +10914,7 @@ class BunPortProbe {
|
|
|
10849
10914
|
|
|
10850
10915
|
// backend/src/services/auto-name-service.ts
|
|
10851
10916
|
var MAX_BRANCH_LENGTH = 40;
|
|
10917
|
+
var DEFAULT_AUTO_NAME_MODEL = "claude-haiku-4-5-20251001";
|
|
10852
10918
|
var DEFAULT_SYSTEM_PROMPT = [
|
|
10853
10919
|
"Generate a concise git branch name from the task description.",
|
|
10854
10920
|
"Return only the branch name.",
|
|
@@ -10899,11 +10965,12 @@ function buildClaudeArgs(model, systemPrompt, prompt) {
|
|
|
10899
10965
|
systemPrompt,
|
|
10900
10966
|
"--output-format",
|
|
10901
10967
|
"text",
|
|
10902
|
-
"--no-session-persistence"
|
|
10968
|
+
"--no-session-persistence",
|
|
10969
|
+
"--model",
|
|
10970
|
+
model || DEFAULT_AUTO_NAME_MODEL,
|
|
10971
|
+
"--effort",
|
|
10972
|
+
"low"
|
|
10903
10973
|
];
|
|
10904
|
-
if (model) {
|
|
10905
|
-
args.push("--model", model);
|
|
10906
|
-
}
|
|
10907
10974
|
args.push(prompt);
|
|
10908
10975
|
return args;
|
|
10909
10976
|
}
|
|
@@ -10949,8 +11016,11 @@ class AutoNameService {
|
|
|
10949
11016
|
throw new Error(`'${cli}' CLI not found. Install it or check your PATH.`);
|
|
10950
11017
|
}
|
|
10951
11018
|
if (result.exitCode !== 0) {
|
|
10952
|
-
const
|
|
10953
|
-
|
|
11019
|
+
const stderr = result.stderr.trim();
|
|
11020
|
+
const stdout = result.stdout.trim();
|
|
11021
|
+
const output2 = stderr || stdout || `exit ${result.exitCode}`;
|
|
11022
|
+
const command = args.join(" ");
|
|
11023
|
+
throw new Error(`${cli} failed (command: ${command}): ${output2}`);
|
|
10954
11024
|
}
|
|
10955
11025
|
const output = result.stdout.trim();
|
|
10956
11026
|
if (!output) {
|
|
@@ -11770,13 +11840,17 @@ async function apiCreateWorktree(req) {
|
|
|
11770
11840
|
const baseBranch = typeof body.baseBranch === "string" && body.baseBranch.trim() ? body.baseBranch.trim() : undefined;
|
|
11771
11841
|
const prompt = typeof body.prompt === "string" && body.prompt.trim() ? body.prompt.trim() : undefined;
|
|
11772
11842
|
const profile = typeof body.profile === "string" ? body.profile : undefined;
|
|
11773
|
-
const agent = body.agent === "claude" || body.agent === "codex" ? body.agent : undefined;
|
|
11843
|
+
const agent = body.agent === "claude" || body.agent === "codex" || body.agent === "both" ? body.agent : undefined;
|
|
11774
11844
|
const createLinearTicket = body.createLinearTicket === true;
|
|
11775
11845
|
const linearTitle = typeof body.linearTitle === "string" && body.linearTitle.trim() ? body.linearTitle.trim() : undefined;
|
|
11776
11846
|
const mode = body.mode === "new" || body.mode === "existing" ? body.mode : undefined;
|
|
11847
|
+
const agentSelection = agent ?? config.workspace.defaultAgent;
|
|
11777
11848
|
if (body.mode !== undefined && body.mode !== "new" && body.mode !== "existing") {
|
|
11778
11849
|
return errorResponse("Invalid worktree create mode", 400);
|
|
11779
11850
|
}
|
|
11851
|
+
if (body.agent !== undefined && body.agent !== "claude" && body.agent !== "codex" && body.agent !== "both") {
|
|
11852
|
+
return errorResponse("Invalid agent selection", 400);
|
|
11853
|
+
}
|
|
11780
11854
|
if (baseBranch && !isValidBranchName(baseBranch)) {
|
|
11781
11855
|
return errorResponse("Invalid base branch name", 400);
|
|
11782
11856
|
}
|
|
@@ -11814,26 +11888,32 @@ async function apiCreateWorktree(req) {
|
|
|
11814
11888
|
return errorResponse(linearResult.error, 502);
|
|
11815
11889
|
}
|
|
11816
11890
|
resolvedBranch = linearResult.data.branchName;
|
|
11817
|
-
ensureBranchNotCreating(resolvedBranch);
|
|
11818
11891
|
log.info(`[linear] created ticket ${linearResult.data.identifier} branch=${linearResult.data.branchName} title="${linearResult.data.title.slice(0, 80)}"`);
|
|
11819
|
-
} else if (resolvedBranch) {
|
|
11820
|
-
ensureBranchNotCreating(resolvedBranch);
|
|
11821
11892
|
}
|
|
11822
|
-
if (resolvedBranch
|
|
11823
|
-
|
|
11893
|
+
if (resolvedBranch) {
|
|
11894
|
+
const targetBranches = buildCreateWorktreeTargets(resolvedBranch, agentSelection).map((target) => target.branch);
|
|
11895
|
+
for (const targetBranch of targetBranches) {
|
|
11896
|
+
ensureBranchNotBusy(targetBranch);
|
|
11897
|
+
}
|
|
11898
|
+
if (baseBranch && targetBranches.some((targetBranch) => targetBranch === baseBranch)) {
|
|
11899
|
+
return errorResponse("Base branch must differ from branch name", 400);
|
|
11900
|
+
}
|
|
11824
11901
|
}
|
|
11825
|
-
log.info(`[worktree:add] mode=${mode ?? "new"}${resolvedBranch ? ` branch=${resolvedBranch}` : ""}${baseBranch ? ` base=${baseBranch}` : ""}${profile ? ` profile=${profile}` : ""}
|
|
11826
|
-
const result = await lifecycleService.
|
|
11902
|
+
log.info(`[worktree:add] mode=${mode ?? "new"}${resolvedBranch ? ` branch=${resolvedBranch}` : ""}${baseBranch ? ` base=${baseBranch}` : ""}${profile ? ` profile=${profile}` : ""} agent=${agentSelection}${createLinearTicket ? " linearTicket=true" : ""}${prompt ? ` prompt="${prompt.slice(0, 80)}"` : ""}`);
|
|
11903
|
+
const result = await lifecycleService.createWorktrees({
|
|
11827
11904
|
mode,
|
|
11828
11905
|
branch: resolvedBranch,
|
|
11829
11906
|
baseBranch,
|
|
11830
11907
|
prompt,
|
|
11831
11908
|
profile,
|
|
11832
|
-
agent,
|
|
11909
|
+
agent: agentSelection,
|
|
11833
11910
|
envOverrides
|
|
11834
11911
|
});
|
|
11835
|
-
log.debug(`[worktree:add] done
|
|
11836
|
-
return jsonResponse({
|
|
11912
|
+
log.debug(`[worktree:add] done branches=${result.branches.join(",")}`);
|
|
11913
|
+
return jsonResponse({
|
|
11914
|
+
primaryBranch: result.primaryBranch,
|
|
11915
|
+
branches: result.branches
|
|
11916
|
+
}, 201);
|
|
11837
11917
|
}
|
|
11838
11918
|
async function apiDeleteWorktree(name) {
|
|
11839
11919
|
return withRemovingBranch(name, async () => {
|
|
@@ -11959,11 +12039,13 @@ async function apiGetWorktreeDiff(name) {
|
|
|
11959
12039
|
if (!state)
|
|
11960
12040
|
return errorResponse(`Worktree not found: ${name}`, 404);
|
|
11961
12041
|
const uncommitted = git.readDiff(state.path);
|
|
12042
|
+
const gitStatus = git.readStatus(state.path);
|
|
11962
12043
|
const unpushedCommits = git.listUnpushedCommits(state.path);
|
|
11963
12044
|
const truncated = uncommitted.length > MAX_DIFF_BYTES;
|
|
11964
12045
|
return jsonResponse({
|
|
11965
12046
|
uncommitted: truncated ? uncommitted.slice(0, MAX_DIFF_BYTES) : uncommitted,
|
|
11966
12047
|
uncommittedTruncated: truncated,
|
|
12048
|
+
gitStatus,
|
|
11967
12049
|
unpushedCommits
|
|
11968
12050
|
});
|
|
11969
12051
|
}
|