webmux 0.9.0 → 0.10.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 +83 -26
- package/bin/webmux.js +87 -30
- package/package.json +1 -1
package/backend/dist/server.js
CHANGED
|
@@ -7253,7 +7253,7 @@ var DEFAULT_CONFIG = {
|
|
|
7253
7253
|
name: "Webmux",
|
|
7254
7254
|
workspace: {
|
|
7255
7255
|
mainBranch: "main",
|
|
7256
|
-
worktreeRoot: "
|
|
7256
|
+
worktreeRoot: "../worktrees",
|
|
7257
7257
|
defaultAgent: "claude"
|
|
7258
7258
|
},
|
|
7259
7259
|
profiles: {
|
|
@@ -7619,6 +7619,7 @@ import { dirname as dirname2, join as join3 } from "path";
|
|
|
7619
7619
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
7620
7620
|
import { join as join2 } from "path";
|
|
7621
7621
|
var SAFE_ENV_VALUE_RE = /^[A-Za-z0-9_./:@%+=,-]+$/;
|
|
7622
|
+
var DOTENV_LINE_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)/;
|
|
7622
7623
|
function stringifyAllocatedPorts(ports) {
|
|
7623
7624
|
const entries = Object.entries(ports).map(([key, value]) => [key, String(value)]);
|
|
7624
7625
|
return Object.fromEntries(entries);
|
|
@@ -7628,6 +7629,34 @@ function quoteEnvValue(value) {
|
|
|
7628
7629
|
return value;
|
|
7629
7630
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
7630
7631
|
}
|
|
7632
|
+
function parseDotenv(content) {
|
|
7633
|
+
const env = {};
|
|
7634
|
+
for (const line of content.split(`
|
|
7635
|
+
`)) {
|
|
7636
|
+
if (line.trimStart().startsWith("#"))
|
|
7637
|
+
continue;
|
|
7638
|
+
const match = DOTENV_LINE_RE.exec(line);
|
|
7639
|
+
if (!match)
|
|
7640
|
+
continue;
|
|
7641
|
+
const key = match[1];
|
|
7642
|
+
let value = match[2];
|
|
7643
|
+
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
7644
|
+
value = value.slice(1, -1);
|
|
7645
|
+
} else {
|
|
7646
|
+
value = value.trimEnd();
|
|
7647
|
+
}
|
|
7648
|
+
env[key] = value;
|
|
7649
|
+
}
|
|
7650
|
+
return env;
|
|
7651
|
+
}
|
|
7652
|
+
async function loadDotenvLocal(worktreePath) {
|
|
7653
|
+
try {
|
|
7654
|
+
const content = await Bun.file(join2(worktreePath, ".env.local")).text();
|
|
7655
|
+
return parseDotenv(content);
|
|
7656
|
+
} catch {
|
|
7657
|
+
return {};
|
|
7658
|
+
}
|
|
7659
|
+
}
|
|
7631
7660
|
function getWorktreeStoragePaths(gitDir) {
|
|
7632
7661
|
const webmuxDir = join2(gitDir, "webmux");
|
|
7633
7662
|
return {
|
|
@@ -7657,8 +7686,9 @@ async function writeWorktreeMeta(gitDir, meta) {
|
|
|
7657
7686
|
await Bun.write(metaPath, JSON.stringify(meta, null, 2) + `
|
|
7658
7687
|
`);
|
|
7659
7688
|
}
|
|
7660
|
-
function buildRuntimeEnvMap(meta, extraEnv = {}) {
|
|
7689
|
+
function buildRuntimeEnvMap(meta, extraEnv = {}, dotenvValues = {}) {
|
|
7661
7690
|
return {
|
|
7691
|
+
...dotenvValues,
|
|
7662
7692
|
...meta.startupEnvValues,
|
|
7663
7693
|
...stringifyAllocatedPorts(meta.allocatedPorts),
|
|
7664
7694
|
...extraEnv,
|
|
@@ -8538,7 +8568,7 @@ async function initializeManagedWorktree(opts) {
|
|
|
8538
8568
|
};
|
|
8539
8569
|
const paths = await ensureWorktreeStorageDirs(opts.gitDir);
|
|
8540
8570
|
await writeWorktreeMeta(opts.gitDir, meta);
|
|
8541
|
-
const runtimeEnv = buildRuntimeEnvMap(meta, opts.runtimeEnvExtras);
|
|
8571
|
+
const runtimeEnv = buildRuntimeEnvMap(meta, opts.runtimeEnvExtras, opts.dotenvValues);
|
|
8542
8572
|
await writeRuntimeEnv(opts.gitDir, runtimeEnv);
|
|
8543
8573
|
let controlEnv = null;
|
|
8544
8574
|
if (opts.controlUrl && opts.controlToken) {
|
|
@@ -8570,6 +8600,7 @@ async function createManagedWorktree(opts, deps = {}) {
|
|
|
8570
8600
|
});
|
|
8571
8601
|
worktreeCreated = true;
|
|
8572
8602
|
const gitDir = git.resolveWorktreeGitDir(opts.worktreePath);
|
|
8603
|
+
const dotenvValues = await loadDotenvLocal(opts.worktreePath);
|
|
8573
8604
|
const initialized = await initializeManagedWorktree({
|
|
8574
8605
|
gitDir,
|
|
8575
8606
|
branch: opts.branch,
|
|
@@ -8579,6 +8610,7 @@ async function createManagedWorktree(opts, deps = {}) {
|
|
|
8579
8610
|
startupEnvValues: opts.startupEnvValues,
|
|
8580
8611
|
allocatedPorts: opts.allocatedPorts,
|
|
8581
8612
|
runtimeEnvExtras: opts.runtimeEnvExtras,
|
|
8613
|
+
dotenvValues,
|
|
8582
8614
|
controlUrl: opts.controlUrl,
|
|
8583
8615
|
controlToken: opts.controlToken,
|
|
8584
8616
|
now: opts.now,
|
|
@@ -8838,6 +8870,7 @@ class LifecycleService {
|
|
|
8838
8870
|
}
|
|
8839
8871
|
async initializeUnmanagedWorktree(resolved) {
|
|
8840
8872
|
const { profileName, profile } = this.resolveProfile(undefined);
|
|
8873
|
+
const dotenvValues = await loadDotenvLocal(resolved.entry.path);
|
|
8841
8874
|
return initializeManagedWorktree({
|
|
8842
8875
|
gitDir: resolved.gitDir,
|
|
8843
8876
|
branch: resolved.entry.branch ?? resolved.entry.path,
|
|
@@ -8847,6 +8880,7 @@ class LifecycleService {
|
|
|
8847
8880
|
startupEnvValues: await this.buildStartupEnvValues(undefined),
|
|
8848
8881
|
allocatedPorts: await this.allocatePorts(),
|
|
8849
8882
|
runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: resolved.entry.path },
|
|
8883
|
+
dotenvValues,
|
|
8850
8884
|
controlUrl: this.controlUrl(),
|
|
8851
8885
|
controlToken: await this.deps.getControlToken()
|
|
8852
8886
|
});
|
|
@@ -8855,9 +8889,10 @@ class LifecycleService {
|
|
|
8855
8889
|
if (!resolved.meta) {
|
|
8856
8890
|
throw new Error("Missing managed metadata");
|
|
8857
8891
|
}
|
|
8892
|
+
const dotenvValues = await loadDotenvLocal(resolved.entry.path);
|
|
8858
8893
|
const runtimeEnv = buildRuntimeEnvMap(resolved.meta, {
|
|
8859
8894
|
WEBMUX_WORKTREE_PATH: resolved.entry.path
|
|
8860
|
-
});
|
|
8895
|
+
}, dotenvValues);
|
|
8861
8896
|
await writeRuntimeEnv(resolved.gitDir, runtimeEnv);
|
|
8862
8897
|
const controlEnv = buildControlEnvMap({
|
|
8863
8898
|
controlUrl: this.controlUrl(),
|
|
@@ -9005,13 +9040,14 @@ class LifecycleService {
|
|
|
9005
9040
|
return;
|
|
9006
9041
|
}
|
|
9007
9042
|
console.debug(`[lifecycle-hook] RUNNING ${input.name}: ${input.command} in ${input.worktreePath}`);
|
|
9043
|
+
const dotenvValues = await loadDotenvLocal(input.worktreePath);
|
|
9008
9044
|
await this.deps.hooks.run({
|
|
9009
9045
|
name: input.name,
|
|
9010
9046
|
command: input.command,
|
|
9011
9047
|
cwd: input.worktreePath,
|
|
9012
9048
|
env: buildRuntimeEnvMap(input.meta, {
|
|
9013
9049
|
WEBMUX_WORKTREE_PATH: input.worktreePath
|
|
9014
|
-
})
|
|
9050
|
+
}, dotenvValues)
|
|
9015
9051
|
});
|
|
9016
9052
|
console.debug(`[lifecycle-hook] COMPLETED ${input.name}`);
|
|
9017
9053
|
}
|
|
@@ -9715,7 +9751,11 @@ function buildErrorMessage(name, exitCode, stdout, stderr) {
|
|
|
9715
9751
|
return `${name} hook failed (exit ${exitCode})`;
|
|
9716
9752
|
}
|
|
9717
9753
|
function hasDirenv() {
|
|
9718
|
-
|
|
9754
|
+
try {
|
|
9755
|
+
return Bun.spawnSync(["direnv", "version"], { stdout: "pipe", stderr: "pipe" }).exitCode === 0;
|
|
9756
|
+
} catch {
|
|
9757
|
+
return false;
|
|
9758
|
+
}
|
|
9719
9759
|
}
|
|
9720
9760
|
|
|
9721
9761
|
class BunLifecycleHookRunner {
|
|
@@ -9765,36 +9805,53 @@ class BunLifecycleHookRunner {
|
|
|
9765
9805
|
// backend/src/adapters/port-probe.ts
|
|
9766
9806
|
class BunPortProbe {
|
|
9767
9807
|
timeoutMs;
|
|
9768
|
-
|
|
9769
|
-
constructor(timeoutMs = 300,
|
|
9808
|
+
hostnames;
|
|
9809
|
+
constructor(timeoutMs = 300, hostnames = ["127.0.0.1", "::1"]) {
|
|
9770
9810
|
this.timeoutMs = timeoutMs;
|
|
9771
|
-
this.
|
|
9811
|
+
this.hostnames = hostnames;
|
|
9772
9812
|
}
|
|
9773
9813
|
isListening(port) {
|
|
9774
9814
|
return new Promise((resolve4) => {
|
|
9775
9815
|
let settled = false;
|
|
9816
|
+
let pending = this.hostnames.length;
|
|
9776
9817
|
const settle = (result) => {
|
|
9777
9818
|
if (settled)
|
|
9778
9819
|
return;
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
|
|
9820
|
+
if (result) {
|
|
9821
|
+
settled = true;
|
|
9822
|
+
clearTimeout(timer);
|
|
9823
|
+
resolve4(true);
|
|
9824
|
+
return;
|
|
9825
|
+
}
|
|
9826
|
+
pending--;
|
|
9827
|
+
if (pending === 0) {
|
|
9828
|
+
settled = true;
|
|
9829
|
+
clearTimeout(timer);
|
|
9830
|
+
resolve4(false);
|
|
9831
|
+
}
|
|
9782
9832
|
};
|
|
9783
|
-
const timer = setTimeout(() =>
|
|
9784
|
-
|
|
9785
|
-
|
|
9786
|
-
|
|
9787
|
-
socket: {
|
|
9788
|
-
open(socket) {
|
|
9789
|
-
socket.end();
|
|
9790
|
-
settle(true);
|
|
9791
|
-
},
|
|
9792
|
-
error() {
|
|
9793
|
-
settle(false);
|
|
9794
|
-
},
|
|
9795
|
-
data() {}
|
|
9833
|
+
const timer = setTimeout(() => {
|
|
9834
|
+
if (!settled) {
|
|
9835
|
+
settled = true;
|
|
9836
|
+
resolve4(false);
|
|
9796
9837
|
}
|
|
9797
|
-
}
|
|
9838
|
+
}, this.timeoutMs);
|
|
9839
|
+
for (const hostname of this.hostnames) {
|
|
9840
|
+
Bun.connect({
|
|
9841
|
+
hostname,
|
|
9842
|
+
port,
|
|
9843
|
+
socket: {
|
|
9844
|
+
open(socket) {
|
|
9845
|
+
socket.end();
|
|
9846
|
+
settle(true);
|
|
9847
|
+
},
|
|
9848
|
+
error() {
|
|
9849
|
+
settle(false);
|
|
9850
|
+
},
|
|
9851
|
+
data() {}
|
|
9852
|
+
}
|
|
9853
|
+
}).catch(() => settle(false));
|
|
9854
|
+
}
|
|
9798
9855
|
});
|
|
9799
9856
|
}
|
|
9800
9857
|
}
|
package/bin/webmux.js
CHANGED
|
@@ -1095,7 +1095,7 @@ function buildInitPromptSpec(context) {
|
|
|
1095
1095
|
"Use this config shape:",
|
|
1096
1096
|
"name: infer from the repository",
|
|
1097
1097
|
"workspace.mainBranch: infer from git",
|
|
1098
|
-
"workspace.worktreeRoot: keep
|
|
1098
|
+
"workspace.worktreeRoot: keep ../worktrees unless there is clear evidence of an existing alternative",
|
|
1099
1099
|
"services: one entry per real dev service with name, portEnv, and portStart when a default port is clear",
|
|
1100
1100
|
"profiles.default.runtime: host",
|
|
1101
1101
|
"profiles.default.envPassthrough: []",
|
|
@@ -1441,7 +1441,7 @@ name: ${input.projectName}
|
|
|
1441
1441
|
|
|
1442
1442
|
workspace:
|
|
1443
1443
|
mainBranch: ${input.mainBranch}
|
|
1444
|
-
worktreeRoot:
|
|
1444
|
+
worktreeRoot: ../worktrees
|
|
1445
1445
|
defaultAgent: ${defaultAgent}
|
|
1446
1446
|
|
|
1447
1447
|
# Each service defines a port env var that webmux injects into pane and agent
|
|
@@ -2061,6 +2061,34 @@ function quoteEnvValue(value) {
|
|
|
2061
2061
|
return value;
|
|
2062
2062
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
2063
2063
|
}
|
|
2064
|
+
function parseDotenv(content) {
|
|
2065
|
+
const env = {};
|
|
2066
|
+
for (const line of content.split(`
|
|
2067
|
+
`)) {
|
|
2068
|
+
if (line.trimStart().startsWith("#"))
|
|
2069
|
+
continue;
|
|
2070
|
+
const match = DOTENV_LINE_RE.exec(line);
|
|
2071
|
+
if (!match)
|
|
2072
|
+
continue;
|
|
2073
|
+
const key = match[1];
|
|
2074
|
+
let value = match[2];
|
|
2075
|
+
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
2076
|
+
value = value.slice(1, -1);
|
|
2077
|
+
} else {
|
|
2078
|
+
value = value.trimEnd();
|
|
2079
|
+
}
|
|
2080
|
+
env[key] = value;
|
|
2081
|
+
}
|
|
2082
|
+
return env;
|
|
2083
|
+
}
|
|
2084
|
+
async function loadDotenvLocal(worktreePath) {
|
|
2085
|
+
try {
|
|
2086
|
+
const content = await Bun.file(join5(worktreePath, ".env.local")).text();
|
|
2087
|
+
return parseDotenv(content);
|
|
2088
|
+
} catch {
|
|
2089
|
+
return {};
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2064
2092
|
function getWorktreeStoragePaths(gitDir) {
|
|
2065
2093
|
const webmuxDir = join5(gitDir, "webmux");
|
|
2066
2094
|
return {
|
|
@@ -2090,8 +2118,9 @@ async function writeWorktreeMeta(gitDir, meta) {
|
|
|
2090
2118
|
await Bun.write(metaPath, JSON.stringify(meta, null, 2) + `
|
|
2091
2119
|
`);
|
|
2092
2120
|
}
|
|
2093
|
-
function buildRuntimeEnvMap(meta, extraEnv = {}) {
|
|
2121
|
+
function buildRuntimeEnvMap(meta, extraEnv = {}, dotenvValues = {}) {
|
|
2094
2122
|
return {
|
|
2123
|
+
...dotenvValues,
|
|
2095
2124
|
...meta.startupEnvValues,
|
|
2096
2125
|
...stringifyAllocatedPorts(meta.allocatedPorts),
|
|
2097
2126
|
...extraEnv,
|
|
@@ -2151,9 +2180,10 @@ async function readWorktreePrs(gitDir) {
|
|
|
2151
2180
|
return [];
|
|
2152
2181
|
}
|
|
2153
2182
|
}
|
|
2154
|
-
var SAFE_ENV_VALUE_RE;
|
|
2183
|
+
var SAFE_ENV_VALUE_RE, DOTENV_LINE_RE;
|
|
2155
2184
|
var init_fs = __esm(() => {
|
|
2156
2185
|
SAFE_ENV_VALUE_RE = /^[A-Za-z0-9_./:@%+=,-]+$/;
|
|
2186
|
+
DOTENV_LINE_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)/;
|
|
2157
2187
|
});
|
|
2158
2188
|
|
|
2159
2189
|
// backend/src/adapters/tmux.ts
|
|
@@ -9465,7 +9495,7 @@ var init_config = __esm(() => {
|
|
|
9465
9495
|
name: "Webmux",
|
|
9466
9496
|
workspace: {
|
|
9467
9497
|
mainBranch: "main",
|
|
9468
|
-
worktreeRoot: "
|
|
9498
|
+
worktreeRoot: "../worktrees",
|
|
9469
9499
|
defaultAgent: "claude"
|
|
9470
9500
|
},
|
|
9471
9501
|
profiles: {
|
|
@@ -10009,7 +10039,11 @@ function buildErrorMessage(name, exitCode, stdout, stderr) {
|
|
|
10009
10039
|
return `${name} hook failed (exit ${exitCode})`;
|
|
10010
10040
|
}
|
|
10011
10041
|
function hasDirenv() {
|
|
10012
|
-
|
|
10042
|
+
try {
|
|
10043
|
+
return Bun.spawnSync(["direnv", "version"], { stdout: "pipe", stderr: "pipe" }).exitCode === 0;
|
|
10044
|
+
} catch {
|
|
10045
|
+
return false;
|
|
10046
|
+
}
|
|
10013
10047
|
}
|
|
10014
10048
|
|
|
10015
10049
|
class BunLifecycleHookRunner {
|
|
@@ -10060,36 +10094,53 @@ var init_hooks = () => {};
|
|
|
10060
10094
|
// backend/src/adapters/port-probe.ts
|
|
10061
10095
|
class BunPortProbe {
|
|
10062
10096
|
timeoutMs;
|
|
10063
|
-
|
|
10064
|
-
constructor(timeoutMs = 300,
|
|
10097
|
+
hostnames;
|
|
10098
|
+
constructor(timeoutMs = 300, hostnames = ["127.0.0.1", "::1"]) {
|
|
10065
10099
|
this.timeoutMs = timeoutMs;
|
|
10066
|
-
this.
|
|
10100
|
+
this.hostnames = hostnames;
|
|
10067
10101
|
}
|
|
10068
10102
|
isListening(port) {
|
|
10069
10103
|
return new Promise((resolve3) => {
|
|
10070
10104
|
let settled = false;
|
|
10105
|
+
let pending = this.hostnames.length;
|
|
10071
10106
|
const settle = (result) => {
|
|
10072
10107
|
if (settled)
|
|
10073
10108
|
return;
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10109
|
+
if (result) {
|
|
10110
|
+
settled = true;
|
|
10111
|
+
clearTimeout(timer);
|
|
10112
|
+
resolve3(true);
|
|
10113
|
+
return;
|
|
10114
|
+
}
|
|
10115
|
+
pending--;
|
|
10116
|
+
if (pending === 0) {
|
|
10117
|
+
settled = true;
|
|
10118
|
+
clearTimeout(timer);
|
|
10119
|
+
resolve3(false);
|
|
10120
|
+
}
|
|
10077
10121
|
};
|
|
10078
|
-
const timer = setTimeout(() =>
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10122
|
+
const timer = setTimeout(() => {
|
|
10123
|
+
if (!settled) {
|
|
10124
|
+
settled = true;
|
|
10125
|
+
resolve3(false);
|
|
10126
|
+
}
|
|
10127
|
+
}, this.timeoutMs);
|
|
10128
|
+
for (const hostname of this.hostnames) {
|
|
10129
|
+
Bun.connect({
|
|
10130
|
+
hostname,
|
|
10131
|
+
port,
|
|
10132
|
+
socket: {
|
|
10133
|
+
open(socket) {
|
|
10134
|
+
socket.end();
|
|
10135
|
+
settle(true);
|
|
10136
|
+
},
|
|
10137
|
+
error() {
|
|
10138
|
+
settle(false);
|
|
10139
|
+
},
|
|
10140
|
+
data() {}
|
|
10141
|
+
}
|
|
10142
|
+
}).catch(() => settle(false));
|
|
10143
|
+
}
|
|
10093
10144
|
});
|
|
10094
10145
|
}
|
|
10095
10146
|
}
|
|
@@ -10853,7 +10904,7 @@ async function initializeManagedWorktree(opts) {
|
|
|
10853
10904
|
};
|
|
10854
10905
|
const paths = await ensureWorktreeStorageDirs(opts.gitDir);
|
|
10855
10906
|
await writeWorktreeMeta(opts.gitDir, meta);
|
|
10856
|
-
const runtimeEnv = buildRuntimeEnvMap(meta, opts.runtimeEnvExtras);
|
|
10907
|
+
const runtimeEnv = buildRuntimeEnvMap(meta, opts.runtimeEnvExtras, opts.dotenvValues);
|
|
10857
10908
|
await writeRuntimeEnv(opts.gitDir, runtimeEnv);
|
|
10858
10909
|
let controlEnv = null;
|
|
10859
10910
|
if (opts.controlUrl && opts.controlToken) {
|
|
@@ -10885,6 +10936,7 @@ async function createManagedWorktree(opts, deps2 = {}) {
|
|
|
10885
10936
|
});
|
|
10886
10937
|
worktreeCreated = true;
|
|
10887
10938
|
const gitDir = git.resolveWorktreeGitDir(opts.worktreePath);
|
|
10939
|
+
const dotenvValues = await loadDotenvLocal(opts.worktreePath);
|
|
10888
10940
|
const initialized = await initializeManagedWorktree({
|
|
10889
10941
|
gitDir,
|
|
10890
10942
|
branch: opts.branch,
|
|
@@ -10894,6 +10946,7 @@ async function createManagedWorktree(opts, deps2 = {}) {
|
|
|
10894
10946
|
startupEnvValues: opts.startupEnvValues,
|
|
10895
10947
|
allocatedPorts: opts.allocatedPorts,
|
|
10896
10948
|
runtimeEnvExtras: opts.runtimeEnvExtras,
|
|
10949
|
+
dotenvValues,
|
|
10897
10950
|
controlUrl: opts.controlUrl,
|
|
10898
10951
|
controlToken: opts.controlToken,
|
|
10899
10952
|
now: opts.now,
|
|
@@ -11153,6 +11206,7 @@ class LifecycleService {
|
|
|
11153
11206
|
}
|
|
11154
11207
|
async initializeUnmanagedWorktree(resolved) {
|
|
11155
11208
|
const { profileName, profile } = this.resolveProfile(undefined);
|
|
11209
|
+
const dotenvValues = await loadDotenvLocal(resolved.entry.path);
|
|
11156
11210
|
return initializeManagedWorktree({
|
|
11157
11211
|
gitDir: resolved.gitDir,
|
|
11158
11212
|
branch: resolved.entry.branch ?? resolved.entry.path,
|
|
@@ -11162,6 +11216,7 @@ class LifecycleService {
|
|
|
11162
11216
|
startupEnvValues: await this.buildStartupEnvValues(undefined),
|
|
11163
11217
|
allocatedPorts: await this.allocatePorts(),
|
|
11164
11218
|
runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: resolved.entry.path },
|
|
11219
|
+
dotenvValues,
|
|
11165
11220
|
controlUrl: this.controlUrl(),
|
|
11166
11221
|
controlToken: await this.deps.getControlToken()
|
|
11167
11222
|
});
|
|
@@ -11170,9 +11225,10 @@ class LifecycleService {
|
|
|
11170
11225
|
if (!resolved.meta) {
|
|
11171
11226
|
throw new Error("Missing managed metadata");
|
|
11172
11227
|
}
|
|
11228
|
+
const dotenvValues = await loadDotenvLocal(resolved.entry.path);
|
|
11173
11229
|
const runtimeEnv = buildRuntimeEnvMap(resolved.meta, {
|
|
11174
11230
|
WEBMUX_WORKTREE_PATH: resolved.entry.path
|
|
11175
|
-
});
|
|
11231
|
+
}, dotenvValues);
|
|
11176
11232
|
await writeRuntimeEnv(resolved.gitDir, runtimeEnv);
|
|
11177
11233
|
const controlEnv = buildControlEnvMap({
|
|
11178
11234
|
controlUrl: this.controlUrl(),
|
|
@@ -11320,13 +11376,14 @@ class LifecycleService {
|
|
|
11320
11376
|
return;
|
|
11321
11377
|
}
|
|
11322
11378
|
console.debug(`[lifecycle-hook] RUNNING ${input.name}: ${input.command} in ${input.worktreePath}`);
|
|
11379
|
+
const dotenvValues = await loadDotenvLocal(input.worktreePath);
|
|
11323
11380
|
await this.deps.hooks.run({
|
|
11324
11381
|
name: input.name,
|
|
11325
11382
|
command: input.command,
|
|
11326
11383
|
cwd: input.worktreePath,
|
|
11327
11384
|
env: buildRuntimeEnvMap(input.meta, {
|
|
11328
11385
|
WEBMUX_WORKTREE_PATH: input.worktreePath
|
|
11329
|
-
})
|
|
11386
|
+
}, dotenvValues)
|
|
11330
11387
|
});
|
|
11331
11388
|
console.debug(`[lifecycle-hook] COMPLETED ${input.name}`);
|
|
11332
11389
|
}
|