webmux 0.27.0 → 0.27.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/README.md CHANGED
@@ -130,6 +130,8 @@ profiles:
130
130
  You are running inside a sandboxed container.
131
131
  Backend port: ${PORT}. Frontend port: ${FRONTEND_PORT}.
132
132
 
133
+ Custom sandbox images should make `claude` or `codex` available on the container's normal `PATH` (for example with `ENV PATH=/your/tool/bin:$PATH`). webmux does not rely on login-shell dotfiles like `.bashrc` to discover agent binaries inside the container.
134
+
133
135
  integrations:
134
136
  github:
135
137
  autoRemoveOnMerge: true
@@ -8687,12 +8687,16 @@ function allocateServicePorts(existingMetas, services) {
8687
8687
  }
8688
8688
 
8689
8689
  // backend/src/services/agent-service.ts
8690
+ var DOCKER_PATH_FALLBACK = "/root/.local/bin:/usr/local/bin:/root/.bun/bin:/root/.cargo/bin";
8690
8691
  function quoteShell(value) {
8691
8692
  return `'${value.replaceAll("'", "'\\''")}'`;
8692
8693
  }
8693
8694
  function buildRuntimeBootstrap(runtimeEnvPath) {
8694
8695
  return `set -a; . ${quoteShell(runtimeEnvPath)}; set +a`;
8695
8696
  }
8697
+ function buildDockerRuntimeBootstrap(runtimeEnvPath) {
8698
+ return `${buildRuntimeBootstrap(runtimeEnvPath)}; export PATH="$PATH:${DOCKER_PATH_FALLBACK}"`;
8699
+ }
8696
8700
  function buildAgentInvocation(input) {
8697
8701
  if (input.agent === "codex") {
8698
8702
  const yoloFlag2 = input.yolo ? " --yolo" : "";
@@ -8715,11 +8719,11 @@ function buildAgentInvocation(input) {
8715
8719
  }
8716
8720
  return `claude${yoloFlag}${promptSuffix}`;
8717
8721
  }
8718
- function buildAgentCommand(input) {
8719
- return `${buildRuntimeBootstrap(input.runtimeEnvPath)}; ${buildAgentInvocation(input)}`;
8722
+ function buildAgentCommand(input, bootstrap = buildRuntimeBootstrap) {
8723
+ return `${bootstrap(input.runtimeEnvPath)}; ${buildAgentInvocation(input)}`;
8720
8724
  }
8721
8725
  function buildDockerExecCommand(containerName, worktreePath, command) {
8722
- return `docker exec -it -w ${quoteShell(worktreePath)} ${quoteShell(containerName)} bash -lc ${quoteShell(command)}`;
8726
+ return `docker exec -it -w ${quoteShell(worktreePath)} ${quoteShell(containerName)} /bin/sh -c ${quoteShell(command)}`;
8723
8727
  }
8724
8728
  function buildManagedShellCommand(runtimeEnvPath, shellPath = Bun.env.SHELL || "/bin/bash") {
8725
8729
  return `bash -lc ${quoteShell(`${buildRuntimeBootstrap(runtimeEnvPath)}; exec ${quoteShell(shellPath)} -i`)}`;
@@ -8727,11 +8731,11 @@ function buildManagedShellCommand(runtimeEnvPath, shellPath = Bun.env.SHELL || "
8727
8731
  function buildAgentPaneCommand(input) {
8728
8732
  return buildAgentCommand(input);
8729
8733
  }
8730
- function buildDockerShellCommand(containerName, worktreePath, runtimeEnvPath, shellPath = Bun.env.SHELL || "/bin/bash") {
8731
- return buildDockerExecCommand(containerName, worktreePath, `${buildRuntimeBootstrap(runtimeEnvPath)}; exec ${quoteShell(shellPath)} -i`);
8734
+ function buildDockerShellCommand(containerName, worktreePath, runtimeEnvPath, shellPath = "/bin/bash") {
8735
+ return buildDockerExecCommand(containerName, worktreePath, `${buildDockerRuntimeBootstrap(runtimeEnvPath)}; if [ -x ${quoteShell(shellPath)} ]; then exec ${quoteShell(shellPath)} -i; elif [ -x /bin/sh ]; then exec /bin/sh -i; else echo 'webmux: no shell found in container' >&2; exit 127; fi`);
8732
8736
  }
8733
8737
  function buildDockerAgentPaneCommand(input) {
8734
- return buildDockerExecCommand(input.containerName, input.worktreePath, buildAgentCommand(input));
8738
+ return buildAgentCommand(input, buildDockerRuntimeBootstrap);
8735
8739
  }
8736
8740
 
8737
8741
  // backend/src/services/session-service.ts
@@ -9277,12 +9281,33 @@ function generateFallbackBranchName() {
9277
9281
  }
9278
9282
 
9279
9283
  // backend/src/services/lifecycle-service.ts
9284
+ var DOCKER_CONTROL_HOST = "host.docker.internal";
9280
9285
  function toErrorMessage2(error) {
9281
9286
  return error instanceof Error ? error.message : String(error);
9282
9287
  }
9283
9288
  function stringifyStartupEnvValue(value) {
9284
9289
  return typeof value === "boolean" ? String(value) : value;
9285
9290
  }
9291
+ function trimTrailingSlashes(value) {
9292
+ return value.replace(/\/+$/, "");
9293
+ }
9294
+ function isLoopbackHostname(hostname) {
9295
+ return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1" || hostname === "[::1]";
9296
+ }
9297
+ function buildRuntimeControlBaseUrl(controlBaseUrl, runtime) {
9298
+ const trimmed = trimTrailingSlashes(controlBaseUrl);
9299
+ if (runtime !== "docker")
9300
+ return trimmed;
9301
+ try {
9302
+ const url = new URL(trimmed);
9303
+ if (isLoopbackHostname(url.hostname)) {
9304
+ url.hostname = DOCKER_CONTROL_HOST;
9305
+ }
9306
+ return trimTrailingSlashes(url.toString());
9307
+ } catch {
9308
+ return trimmed;
9309
+ }
9310
+ }
9286
9311
  function prefixAgentBranch(agent, branch) {
9287
9312
  return `${agent}-${branch}`;
9288
9313
  }
@@ -9573,7 +9598,7 @@ class LifecycleService {
9573
9598
  allocatedPorts: await this.allocatePorts(),
9574
9599
  runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: resolved.entry.path },
9575
9600
  dotenvValues,
9576
- controlUrl: this.controlUrl(),
9601
+ controlUrl: this.controlUrl(profile.runtime),
9577
9602
  controlToken: await this.deps.getControlToken()
9578
9603
  });
9579
9604
  }
@@ -9594,7 +9619,7 @@ class LifecycleService {
9594
9619
  }, dotenvValues);
9595
9620
  await writeRuntimeEnv(input.gitDir, runtimeEnv);
9596
9621
  const controlEnv = buildControlEnvMap({
9597
- controlUrl: this.controlUrl(),
9622
+ controlUrl: this.controlUrl(input.meta.runtime),
9598
9623
  controlToken: await this.deps.getControlToken(),
9599
9624
  worktreeId: input.meta.worktreeId,
9600
9625
  branch: input.meta.branch
@@ -9656,8 +9681,6 @@ class LifecycleService {
9656
9681
  paneCommands: containerName ? {
9657
9682
  agent: buildDockerAgentPaneCommand({
9658
9683
  agent: input.agent,
9659
- containerName,
9660
- worktreePath: input.worktreePath,
9661
9684
  runtimeEnvPath: input.initialized.paths.runtimeEnvPath,
9662
9685
  yolo: input.profile.yolo === true,
9663
9686
  systemPrompt,
@@ -9718,8 +9741,8 @@ class LifecycleService {
9718
9741
  throw new LifecycleError(`Worktree has uncommitted changes: ${entry.branch ?? entry.path}`, 409);
9719
9742
  }
9720
9743
  }
9721
- controlUrl() {
9722
- return `${this.deps.controlBaseUrl.replace(/\/+$/, "")}/api/runtime/events`;
9744
+ controlUrl(runtime) {
9745
+ return `${buildRuntimeControlBaseUrl(this.deps.controlBaseUrl, runtime)}/api/runtime/events`;
9723
9746
  }
9724
9747
  async removeResolvedWorktree(resolved) {
9725
9748
  await this.runLifecycleHook({
@@ -9822,7 +9845,7 @@ class LifecycleService {
9822
9845
  startupEnvValues: await this.buildStartupEnvValues(input.envOverrides),
9823
9846
  allocatedPorts: await this.allocatePorts(),
9824
9847
  runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: worktreePath },
9825
- controlUrl: this.controlUrl(),
9848
+ controlUrl: this.controlUrl(profile.runtime),
9826
9849
  controlToken: await this.deps.getControlToken(),
9827
9850
  deleteBranchOnRollback
9828
9851
  }, {
package/bin/webmux.js CHANGED
@@ -11562,6 +11562,9 @@ function quoteShell(value) {
11562
11562
  function buildRuntimeBootstrap(runtimeEnvPath) {
11563
11563
  return `set -a; . ${quoteShell(runtimeEnvPath)}; set +a`;
11564
11564
  }
11565
+ function buildDockerRuntimeBootstrap(runtimeEnvPath) {
11566
+ return `${buildRuntimeBootstrap(runtimeEnvPath)}; export PATH="$PATH:${DOCKER_PATH_FALLBACK}"`;
11567
+ }
11565
11568
  function buildAgentInvocation(input) {
11566
11569
  if (input.agent === "codex") {
11567
11570
  const yoloFlag2 = input.yolo ? " --yolo" : "";
@@ -11584,11 +11587,11 @@ function buildAgentInvocation(input) {
11584
11587
  }
11585
11588
  return `claude${yoloFlag}${promptSuffix}`;
11586
11589
  }
11587
- function buildAgentCommand(input) {
11588
- return `${buildRuntimeBootstrap(input.runtimeEnvPath)}; ${buildAgentInvocation(input)}`;
11590
+ function buildAgentCommand(input, bootstrap = buildRuntimeBootstrap) {
11591
+ return `${bootstrap(input.runtimeEnvPath)}; ${buildAgentInvocation(input)}`;
11589
11592
  }
11590
11593
  function buildDockerExecCommand(containerName2, worktreePath, command) {
11591
- return `docker exec -it -w ${quoteShell(worktreePath)} ${quoteShell(containerName2)} bash -lc ${quoteShell(command)}`;
11594
+ return `docker exec -it -w ${quoteShell(worktreePath)} ${quoteShell(containerName2)} /bin/sh -c ${quoteShell(command)}`;
11592
11595
  }
11593
11596
  function buildManagedShellCommand(runtimeEnvPath, shellPath = Bun.env.SHELL || "/bin/bash") {
11594
11597
  return `bash -lc ${quoteShell(`${buildRuntimeBootstrap(runtimeEnvPath)}; exec ${quoteShell(shellPath)} -i`)}`;
@@ -11596,12 +11599,13 @@ function buildManagedShellCommand(runtimeEnvPath, shellPath = Bun.env.SHELL || "
11596
11599
  function buildAgentPaneCommand(input) {
11597
11600
  return buildAgentCommand(input);
11598
11601
  }
11599
- function buildDockerShellCommand(containerName2, worktreePath, runtimeEnvPath, shellPath = Bun.env.SHELL || "/bin/bash") {
11600
- return buildDockerExecCommand(containerName2, worktreePath, `${buildRuntimeBootstrap(runtimeEnvPath)}; exec ${quoteShell(shellPath)} -i`);
11602
+ function buildDockerShellCommand(containerName2, worktreePath, runtimeEnvPath, shellPath = "/bin/bash") {
11603
+ return buildDockerExecCommand(containerName2, worktreePath, `${buildDockerRuntimeBootstrap(runtimeEnvPath)}; if [ -x ${quoteShell(shellPath)} ]; then exec ${quoteShell(shellPath)} -i; elif [ -x /bin/sh ]; then exec /bin/sh -i; else echo 'webmux: no shell found in container' >&2; exit 127; fi`);
11601
11604
  }
11602
11605
  function buildDockerAgentPaneCommand(input) {
11603
- return buildDockerExecCommand(input.containerName, input.worktreePath, buildAgentCommand(input));
11606
+ return buildAgentCommand(input, buildDockerRuntimeBootstrap);
11604
11607
  }
11608
+ var DOCKER_PATH_FALLBACK = "/root/.local/bin:/usr/local/bin:/root/.bun/bin:/root/.cargo/bin";
11605
11609
 
11606
11610
  // backend/src/services/session-service.ts
11607
11611
  import { resolve as resolve6 } from "path";
@@ -11855,6 +11859,26 @@ function toErrorMessage2(error) {
11855
11859
  function stringifyStartupEnvValue(value) {
11856
11860
  return typeof value === "boolean" ? String(value) : value;
11857
11861
  }
11862
+ function trimTrailingSlashes(value) {
11863
+ return value.replace(/\/+$/, "");
11864
+ }
11865
+ function isLoopbackHostname(hostname) {
11866
+ return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1" || hostname === "[::1]";
11867
+ }
11868
+ function buildRuntimeControlBaseUrl(controlBaseUrl, runtime) {
11869
+ const trimmed = trimTrailingSlashes(controlBaseUrl);
11870
+ if (runtime !== "docker")
11871
+ return trimmed;
11872
+ try {
11873
+ const url = new URL(trimmed);
11874
+ if (isLoopbackHostname(url.hostname)) {
11875
+ url.hostname = DOCKER_CONTROL_HOST;
11876
+ }
11877
+ return trimTrailingSlashes(url.toString());
11878
+ } catch {
11879
+ return trimmed;
11880
+ }
11881
+ }
11858
11882
  function prefixAgentBranch(agent, branch) {
11859
11883
  return `${agent}-${branch}`;
11860
11884
  }
@@ -12137,7 +12161,7 @@ class LifecycleService {
12137
12161
  allocatedPorts: await this.allocatePorts(),
12138
12162
  runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: resolved.entry.path },
12139
12163
  dotenvValues,
12140
- controlUrl: this.controlUrl(),
12164
+ controlUrl: this.controlUrl(profile.runtime),
12141
12165
  controlToken: await this.deps.getControlToken()
12142
12166
  });
12143
12167
  }
@@ -12158,7 +12182,7 @@ class LifecycleService {
12158
12182
  }, dotenvValues);
12159
12183
  await writeRuntimeEnv(input.gitDir, runtimeEnv);
12160
12184
  const controlEnv = buildControlEnvMap({
12161
- controlUrl: this.controlUrl(),
12185
+ controlUrl: this.controlUrl(input.meta.runtime),
12162
12186
  controlToken: await this.deps.getControlToken(),
12163
12187
  worktreeId: input.meta.worktreeId,
12164
12188
  branch: input.meta.branch
@@ -12220,8 +12244,6 @@ class LifecycleService {
12220
12244
  paneCommands: containerName2 ? {
12221
12245
  agent: buildDockerAgentPaneCommand({
12222
12246
  agent: input.agent,
12223
- containerName: containerName2,
12224
- worktreePath: input.worktreePath,
12225
12247
  runtimeEnvPath: input.initialized.paths.runtimeEnvPath,
12226
12248
  yolo: input.profile.yolo === true,
12227
12249
  systemPrompt,
@@ -12282,8 +12304,8 @@ class LifecycleService {
12282
12304
  throw new LifecycleError(`Worktree has uncommitted changes: ${entry.branch ?? entry.path}`, 409);
12283
12305
  }
12284
12306
  }
12285
- controlUrl() {
12286
- return `${this.deps.controlBaseUrl.replace(/\/+$/, "")}/api/runtime/events`;
12307
+ controlUrl(runtime) {
12308
+ return `${buildRuntimeControlBaseUrl(this.deps.controlBaseUrl, runtime)}/api/runtime/events`;
12287
12309
  }
12288
12310
  async removeResolvedWorktree(resolved) {
12289
12311
  await this.runLifecycleHook({
@@ -12386,7 +12408,7 @@ class LifecycleService {
12386
12408
  startupEnvValues: await this.buildStartupEnvValues(input.envOverrides),
12387
12409
  allocatedPorts: await this.allocatePorts(),
12388
12410
  runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: worktreePath },
12389
- controlUrl: this.controlUrl(),
12411
+ controlUrl: this.controlUrl(profile.runtime),
12390
12412
  controlToken: await this.deps.getControlToken(),
12391
12413
  deleteBranchOnRollback
12392
12414
  }, {
@@ -12456,7 +12478,7 @@ class LifecycleService {
12456
12478
  return new LifecycleError(toErrorMessage2(error), 422);
12457
12479
  }
12458
12480
  }
12459
- var LifecycleError;
12481
+ var DOCKER_CONTROL_HOST = "host.docker.internal", LifecycleError;
12460
12482
  var init_lifecycle_service = __esm(() => {
12461
12483
  init_agent_runtime();
12462
12484
  init_fs();
@@ -13590,7 +13612,7 @@ import { fileURLToPath } from "url";
13590
13612
  // package.json
13591
13613
  var package_default = {
13592
13614
  name: "webmux",
13593
- version: "0.27.0",
13615
+ version: "0.27.1",
13594
13616
  description: "Web dashboard for workmux \u2014 browser UI with embedded terminals, PR monitoring, and CI integration",
13595
13617
  type: "module",
13596
13618
  repository: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webmux",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "Web dashboard for workmux — browser UI with embedded terminals, PR monitoring, and CI integration",
5
5
  "type": "module",
6
6
  "repository": {