webmux 0.9.0 → 0.10.0
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 +78 -25
- package/bin/webmux.js +82 -29
- 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
|
}
|
|
@@ -9765,36 +9801,53 @@ class BunLifecycleHookRunner {
|
|
|
9765
9801
|
// backend/src/adapters/port-probe.ts
|
|
9766
9802
|
class BunPortProbe {
|
|
9767
9803
|
timeoutMs;
|
|
9768
|
-
|
|
9769
|
-
constructor(timeoutMs = 300,
|
|
9804
|
+
hostnames;
|
|
9805
|
+
constructor(timeoutMs = 300, hostnames = ["127.0.0.1", "::1"]) {
|
|
9770
9806
|
this.timeoutMs = timeoutMs;
|
|
9771
|
-
this.
|
|
9807
|
+
this.hostnames = hostnames;
|
|
9772
9808
|
}
|
|
9773
9809
|
isListening(port) {
|
|
9774
9810
|
return new Promise((resolve4) => {
|
|
9775
9811
|
let settled = false;
|
|
9812
|
+
let pending = this.hostnames.length;
|
|
9776
9813
|
const settle = (result) => {
|
|
9777
9814
|
if (settled)
|
|
9778
9815
|
return;
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
|
|
9816
|
+
if (result) {
|
|
9817
|
+
settled = true;
|
|
9818
|
+
clearTimeout(timer);
|
|
9819
|
+
resolve4(true);
|
|
9820
|
+
return;
|
|
9821
|
+
}
|
|
9822
|
+
pending--;
|
|
9823
|
+
if (pending === 0) {
|
|
9824
|
+
settled = true;
|
|
9825
|
+
clearTimeout(timer);
|
|
9826
|
+
resolve4(false);
|
|
9827
|
+
}
|
|
9782
9828
|
};
|
|
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() {}
|
|
9829
|
+
const timer = setTimeout(() => {
|
|
9830
|
+
if (!settled) {
|
|
9831
|
+
settled = true;
|
|
9832
|
+
resolve4(false);
|
|
9796
9833
|
}
|
|
9797
|
-
}
|
|
9834
|
+
}, this.timeoutMs);
|
|
9835
|
+
for (const hostname of this.hostnames) {
|
|
9836
|
+
Bun.connect({
|
|
9837
|
+
hostname,
|
|
9838
|
+
port,
|
|
9839
|
+
socket: {
|
|
9840
|
+
open(socket) {
|
|
9841
|
+
socket.end();
|
|
9842
|
+
settle(true);
|
|
9843
|
+
},
|
|
9844
|
+
error() {
|
|
9845
|
+
settle(false);
|
|
9846
|
+
},
|
|
9847
|
+
data() {}
|
|
9848
|
+
}
|
|
9849
|
+
}).catch(() => settle(false));
|
|
9850
|
+
}
|
|
9798
9851
|
});
|
|
9799
9852
|
}
|
|
9800
9853
|
}
|
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: {
|
|
@@ -10060,36 +10090,53 @@ var init_hooks = () => {};
|
|
|
10060
10090
|
// backend/src/adapters/port-probe.ts
|
|
10061
10091
|
class BunPortProbe {
|
|
10062
10092
|
timeoutMs;
|
|
10063
|
-
|
|
10064
|
-
constructor(timeoutMs = 300,
|
|
10093
|
+
hostnames;
|
|
10094
|
+
constructor(timeoutMs = 300, hostnames = ["127.0.0.1", "::1"]) {
|
|
10065
10095
|
this.timeoutMs = timeoutMs;
|
|
10066
|
-
this.
|
|
10096
|
+
this.hostnames = hostnames;
|
|
10067
10097
|
}
|
|
10068
10098
|
isListening(port) {
|
|
10069
10099
|
return new Promise((resolve3) => {
|
|
10070
10100
|
let settled = false;
|
|
10101
|
+
let pending = this.hostnames.length;
|
|
10071
10102
|
const settle = (result) => {
|
|
10072
10103
|
if (settled)
|
|
10073
10104
|
return;
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10105
|
+
if (result) {
|
|
10106
|
+
settled = true;
|
|
10107
|
+
clearTimeout(timer);
|
|
10108
|
+
resolve3(true);
|
|
10109
|
+
return;
|
|
10110
|
+
}
|
|
10111
|
+
pending--;
|
|
10112
|
+
if (pending === 0) {
|
|
10113
|
+
settled = true;
|
|
10114
|
+
clearTimeout(timer);
|
|
10115
|
+
resolve3(false);
|
|
10116
|
+
}
|
|
10077
10117
|
};
|
|
10078
|
-
const timer = setTimeout(() =>
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10118
|
+
const timer = setTimeout(() => {
|
|
10119
|
+
if (!settled) {
|
|
10120
|
+
settled = true;
|
|
10121
|
+
resolve3(false);
|
|
10122
|
+
}
|
|
10123
|
+
}, this.timeoutMs);
|
|
10124
|
+
for (const hostname of this.hostnames) {
|
|
10125
|
+
Bun.connect({
|
|
10126
|
+
hostname,
|
|
10127
|
+
port,
|
|
10128
|
+
socket: {
|
|
10129
|
+
open(socket) {
|
|
10130
|
+
socket.end();
|
|
10131
|
+
settle(true);
|
|
10132
|
+
},
|
|
10133
|
+
error() {
|
|
10134
|
+
settle(false);
|
|
10135
|
+
},
|
|
10136
|
+
data() {}
|
|
10137
|
+
}
|
|
10138
|
+
}).catch(() => settle(false));
|
|
10139
|
+
}
|
|
10093
10140
|
});
|
|
10094
10141
|
}
|
|
10095
10142
|
}
|
|
@@ -10853,7 +10900,7 @@ async function initializeManagedWorktree(opts) {
|
|
|
10853
10900
|
};
|
|
10854
10901
|
const paths = await ensureWorktreeStorageDirs(opts.gitDir);
|
|
10855
10902
|
await writeWorktreeMeta(opts.gitDir, meta);
|
|
10856
|
-
const runtimeEnv = buildRuntimeEnvMap(meta, opts.runtimeEnvExtras);
|
|
10903
|
+
const runtimeEnv = buildRuntimeEnvMap(meta, opts.runtimeEnvExtras, opts.dotenvValues);
|
|
10857
10904
|
await writeRuntimeEnv(opts.gitDir, runtimeEnv);
|
|
10858
10905
|
let controlEnv = null;
|
|
10859
10906
|
if (opts.controlUrl && opts.controlToken) {
|
|
@@ -10885,6 +10932,7 @@ async function createManagedWorktree(opts, deps2 = {}) {
|
|
|
10885
10932
|
});
|
|
10886
10933
|
worktreeCreated = true;
|
|
10887
10934
|
const gitDir = git.resolveWorktreeGitDir(opts.worktreePath);
|
|
10935
|
+
const dotenvValues = await loadDotenvLocal(opts.worktreePath);
|
|
10888
10936
|
const initialized = await initializeManagedWorktree({
|
|
10889
10937
|
gitDir,
|
|
10890
10938
|
branch: opts.branch,
|
|
@@ -10894,6 +10942,7 @@ async function createManagedWorktree(opts, deps2 = {}) {
|
|
|
10894
10942
|
startupEnvValues: opts.startupEnvValues,
|
|
10895
10943
|
allocatedPorts: opts.allocatedPorts,
|
|
10896
10944
|
runtimeEnvExtras: opts.runtimeEnvExtras,
|
|
10945
|
+
dotenvValues,
|
|
10897
10946
|
controlUrl: opts.controlUrl,
|
|
10898
10947
|
controlToken: opts.controlToken,
|
|
10899
10948
|
now: opts.now,
|
|
@@ -11153,6 +11202,7 @@ class LifecycleService {
|
|
|
11153
11202
|
}
|
|
11154
11203
|
async initializeUnmanagedWorktree(resolved) {
|
|
11155
11204
|
const { profileName, profile } = this.resolveProfile(undefined);
|
|
11205
|
+
const dotenvValues = await loadDotenvLocal(resolved.entry.path);
|
|
11156
11206
|
return initializeManagedWorktree({
|
|
11157
11207
|
gitDir: resolved.gitDir,
|
|
11158
11208
|
branch: resolved.entry.branch ?? resolved.entry.path,
|
|
@@ -11162,6 +11212,7 @@ class LifecycleService {
|
|
|
11162
11212
|
startupEnvValues: await this.buildStartupEnvValues(undefined),
|
|
11163
11213
|
allocatedPorts: await this.allocatePorts(),
|
|
11164
11214
|
runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: resolved.entry.path },
|
|
11215
|
+
dotenvValues,
|
|
11165
11216
|
controlUrl: this.controlUrl(),
|
|
11166
11217
|
controlToken: await this.deps.getControlToken()
|
|
11167
11218
|
});
|
|
@@ -11170,9 +11221,10 @@ class LifecycleService {
|
|
|
11170
11221
|
if (!resolved.meta) {
|
|
11171
11222
|
throw new Error("Missing managed metadata");
|
|
11172
11223
|
}
|
|
11224
|
+
const dotenvValues = await loadDotenvLocal(resolved.entry.path);
|
|
11173
11225
|
const runtimeEnv = buildRuntimeEnvMap(resolved.meta, {
|
|
11174
11226
|
WEBMUX_WORKTREE_PATH: resolved.entry.path
|
|
11175
|
-
});
|
|
11227
|
+
}, dotenvValues);
|
|
11176
11228
|
await writeRuntimeEnv(resolved.gitDir, runtimeEnv);
|
|
11177
11229
|
const controlEnv = buildControlEnvMap({
|
|
11178
11230
|
controlUrl: this.controlUrl(),
|
|
@@ -11320,13 +11372,14 @@ class LifecycleService {
|
|
|
11320
11372
|
return;
|
|
11321
11373
|
}
|
|
11322
11374
|
console.debug(`[lifecycle-hook] RUNNING ${input.name}: ${input.command} in ${input.worktreePath}`);
|
|
11375
|
+
const dotenvValues = await loadDotenvLocal(input.worktreePath);
|
|
11323
11376
|
await this.deps.hooks.run({
|
|
11324
11377
|
name: input.name,
|
|
11325
11378
|
command: input.command,
|
|
11326
11379
|
cwd: input.worktreePath,
|
|
11327
11380
|
env: buildRuntimeEnvMap(input.meta, {
|
|
11328
11381
|
WEBMUX_WORKTREE_PATH: input.worktreePath
|
|
11329
|
-
})
|
|
11382
|
+
}, dotenvValues)
|
|
11330
11383
|
});
|
|
11331
11384
|
console.debug(`[lifecycle-hook] COMPLETED ${input.name}`);
|
|
11332
11385
|
}
|