episoda 0.2.25 → 0.2.27
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/daemon/daemon-process.js +200 -69
- package/dist/daemon/daemon-process.js.map +1 -1
- package/dist/index.js +107 -43
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1556,15 +1556,15 @@ var require_git_executor = __commonJS({
|
|
|
1556
1556
|
try {
|
|
1557
1557
|
const { stdout: gitDir } = await execAsync2("git rev-parse --git-dir", { cwd, timeout: 5e3 });
|
|
1558
1558
|
const gitDirPath = gitDir.trim();
|
|
1559
|
-
const
|
|
1559
|
+
const fs16 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1560
1560
|
const rebaseMergePath = `${gitDirPath}/rebase-merge`;
|
|
1561
1561
|
const rebaseApplyPath = `${gitDirPath}/rebase-apply`;
|
|
1562
1562
|
try {
|
|
1563
|
-
await
|
|
1563
|
+
await fs16.access(rebaseMergePath);
|
|
1564
1564
|
inRebase = true;
|
|
1565
1565
|
} catch {
|
|
1566
1566
|
try {
|
|
1567
|
-
await
|
|
1567
|
+
await fs16.access(rebaseApplyPath);
|
|
1568
1568
|
inRebase = true;
|
|
1569
1569
|
} catch {
|
|
1570
1570
|
inRebase = false;
|
|
@@ -1618,9 +1618,9 @@ var require_git_executor = __commonJS({
|
|
|
1618
1618
|
error: validation.error || "UNKNOWN_ERROR"
|
|
1619
1619
|
};
|
|
1620
1620
|
}
|
|
1621
|
-
const
|
|
1621
|
+
const fs16 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1622
1622
|
try {
|
|
1623
|
-
await
|
|
1623
|
+
await fs16.access(command.path);
|
|
1624
1624
|
return {
|
|
1625
1625
|
success: false,
|
|
1626
1626
|
error: "WORKTREE_EXISTS",
|
|
@@ -1671,9 +1671,9 @@ var require_git_executor = __commonJS({
|
|
|
1671
1671
|
*/
|
|
1672
1672
|
async executeWorktreeRemove(command, cwd, options) {
|
|
1673
1673
|
try {
|
|
1674
|
-
const
|
|
1674
|
+
const fs16 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1675
1675
|
try {
|
|
1676
|
-
await
|
|
1676
|
+
await fs16.access(command.path);
|
|
1677
1677
|
} catch {
|
|
1678
1678
|
return {
|
|
1679
1679
|
success: false,
|
|
@@ -1826,10 +1826,10 @@ var require_git_executor = __commonJS({
|
|
|
1826
1826
|
*/
|
|
1827
1827
|
async executeCloneBare(command, options) {
|
|
1828
1828
|
try {
|
|
1829
|
-
const
|
|
1830
|
-
const
|
|
1829
|
+
const fs16 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1830
|
+
const path17 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
1831
1831
|
try {
|
|
1832
|
-
await
|
|
1832
|
+
await fs16.access(command.path);
|
|
1833
1833
|
return {
|
|
1834
1834
|
success: false,
|
|
1835
1835
|
error: "BRANCH_ALREADY_EXISTS",
|
|
@@ -1838,9 +1838,9 @@ var require_git_executor = __commonJS({
|
|
|
1838
1838
|
};
|
|
1839
1839
|
} catch {
|
|
1840
1840
|
}
|
|
1841
|
-
const parentDir =
|
|
1841
|
+
const parentDir = path17.dirname(command.path);
|
|
1842
1842
|
try {
|
|
1843
|
-
await
|
|
1843
|
+
await fs16.mkdir(parentDir, { recursive: true });
|
|
1844
1844
|
} catch {
|
|
1845
1845
|
}
|
|
1846
1846
|
const { stdout, stderr } = await execAsync2(
|
|
@@ -1883,22 +1883,22 @@ var require_git_executor = __commonJS({
|
|
|
1883
1883
|
*/
|
|
1884
1884
|
async executeProjectInfo(cwd, options) {
|
|
1885
1885
|
try {
|
|
1886
|
-
const
|
|
1887
|
-
const
|
|
1886
|
+
const fs16 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1887
|
+
const path17 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
1888
1888
|
let currentPath = cwd;
|
|
1889
1889
|
let projectPath = cwd;
|
|
1890
1890
|
let bareRepoPath;
|
|
1891
1891
|
for (let i = 0; i < 10; i++) {
|
|
1892
|
-
const bareDir =
|
|
1893
|
-
const episodaDir =
|
|
1892
|
+
const bareDir = path17.join(currentPath, ".bare");
|
|
1893
|
+
const episodaDir = path17.join(currentPath, ".episoda");
|
|
1894
1894
|
try {
|
|
1895
|
-
await
|
|
1896
|
-
await
|
|
1895
|
+
await fs16.access(bareDir);
|
|
1896
|
+
await fs16.access(episodaDir);
|
|
1897
1897
|
projectPath = currentPath;
|
|
1898
1898
|
bareRepoPath = bareDir;
|
|
1899
1899
|
break;
|
|
1900
1900
|
} catch {
|
|
1901
|
-
const parentPath =
|
|
1901
|
+
const parentPath = path17.dirname(currentPath);
|
|
1902
1902
|
if (parentPath === currentPath) {
|
|
1903
1903
|
break;
|
|
1904
1904
|
}
|
|
@@ -2492,31 +2492,31 @@ var require_auth = __commonJS({
|
|
|
2492
2492
|
exports2.loadConfig = loadConfig5;
|
|
2493
2493
|
exports2.saveConfig = saveConfig2;
|
|
2494
2494
|
exports2.validateToken = validateToken;
|
|
2495
|
-
var
|
|
2496
|
-
var
|
|
2495
|
+
var fs16 = __importStar(require("fs"));
|
|
2496
|
+
var path17 = __importStar(require("path"));
|
|
2497
2497
|
var os6 = __importStar(require("os"));
|
|
2498
2498
|
var child_process_1 = require("child_process");
|
|
2499
2499
|
var DEFAULT_CONFIG_FILE = "config.json";
|
|
2500
2500
|
function getConfigDir6() {
|
|
2501
|
-
return process.env.EPISODA_CONFIG_DIR ||
|
|
2501
|
+
return process.env.EPISODA_CONFIG_DIR || path17.join(os6.homedir(), ".episoda");
|
|
2502
2502
|
}
|
|
2503
2503
|
function getConfigPath(configPath) {
|
|
2504
2504
|
if (configPath) {
|
|
2505
2505
|
return configPath;
|
|
2506
2506
|
}
|
|
2507
|
-
return
|
|
2507
|
+
return path17.join(getConfigDir6(), DEFAULT_CONFIG_FILE);
|
|
2508
2508
|
}
|
|
2509
2509
|
function ensureConfigDir(configPath) {
|
|
2510
|
-
const dir =
|
|
2511
|
-
const isNew = !
|
|
2510
|
+
const dir = path17.dirname(configPath);
|
|
2511
|
+
const isNew = !fs16.existsSync(dir);
|
|
2512
2512
|
if (isNew) {
|
|
2513
|
-
|
|
2513
|
+
fs16.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2514
2514
|
}
|
|
2515
2515
|
if (process.platform === "darwin") {
|
|
2516
|
-
const nosyncPath =
|
|
2517
|
-
if (isNew || !
|
|
2516
|
+
const nosyncPath = path17.join(dir, ".nosync");
|
|
2517
|
+
if (isNew || !fs16.existsSync(nosyncPath)) {
|
|
2518
2518
|
try {
|
|
2519
|
-
|
|
2519
|
+
fs16.writeFileSync(nosyncPath, "", { mode: 384 });
|
|
2520
2520
|
(0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
|
|
2521
2521
|
stdio: "ignore",
|
|
2522
2522
|
timeout: 5e3
|
|
@@ -2528,11 +2528,11 @@ var require_auth = __commonJS({
|
|
|
2528
2528
|
}
|
|
2529
2529
|
async function loadConfig5(configPath) {
|
|
2530
2530
|
const fullPath = getConfigPath(configPath);
|
|
2531
|
-
if (!
|
|
2531
|
+
if (!fs16.existsSync(fullPath)) {
|
|
2532
2532
|
return null;
|
|
2533
2533
|
}
|
|
2534
2534
|
try {
|
|
2535
|
-
const content =
|
|
2535
|
+
const content = fs16.readFileSync(fullPath, "utf8");
|
|
2536
2536
|
const config = JSON.parse(content);
|
|
2537
2537
|
return config;
|
|
2538
2538
|
} catch (error) {
|
|
@@ -2545,7 +2545,7 @@ var require_auth = __commonJS({
|
|
|
2545
2545
|
ensureConfigDir(fullPath);
|
|
2546
2546
|
try {
|
|
2547
2547
|
const content = JSON.stringify(config, null, 2);
|
|
2548
|
-
|
|
2548
|
+
fs16.writeFileSync(fullPath, content, { mode: 384 });
|
|
2549
2549
|
} catch (error) {
|
|
2550
2550
|
throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
|
|
2551
2551
|
}
|
|
@@ -2696,7 +2696,7 @@ var require_package = __commonJS({
|
|
|
2696
2696
|
"package.json"(exports2, module2) {
|
|
2697
2697
|
module2.exports = {
|
|
2698
2698
|
name: "episoda",
|
|
2699
|
-
version: "0.2.
|
|
2699
|
+
version: "0.2.26",
|
|
2700
2700
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2701
2701
|
main: "dist/index.js",
|
|
2702
2702
|
types: "dist/index.d.ts",
|
|
@@ -6023,20 +6023,39 @@ async function findProjectRoot(startPath) {
|
|
|
6023
6023
|
return null;
|
|
6024
6024
|
}
|
|
6025
6025
|
|
|
6026
|
-
// src/utils/
|
|
6027
|
-
var path13 = __toESM(require("path"));
|
|
6026
|
+
// src/utils/env-setup.ts
|
|
6028
6027
|
var fs12 = __toESM(require("fs"));
|
|
6028
|
+
var path13 = __toESM(require("path"));
|
|
6029
|
+
function writeEnvFile(targetPath, envVars) {
|
|
6030
|
+
if (Object.keys(envVars).length === 0) {
|
|
6031
|
+
return;
|
|
6032
|
+
}
|
|
6033
|
+
const envContent = Object.entries(envVars).map(([key, value]) => {
|
|
6034
|
+
if (/[\s'"#$`\\]/.test(value) || value.includes("\n")) {
|
|
6035
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
|
|
6036
|
+
return `${key}="${escaped}"`;
|
|
6037
|
+
}
|
|
6038
|
+
return `${key}=${value}`;
|
|
6039
|
+
}).join("\n") + "\n";
|
|
6040
|
+
const envPath = path13.join(targetPath, ".env");
|
|
6041
|
+
fs12.writeFileSync(envPath, envContent, { mode: 384 });
|
|
6042
|
+
console.log(`[env-setup] Wrote ${Object.keys(envVars).length} env vars to ${envPath}`);
|
|
6043
|
+
}
|
|
6044
|
+
|
|
6045
|
+
// src/utils/worktree.ts
|
|
6046
|
+
var path14 = __toESM(require("path"));
|
|
6047
|
+
var fs13 = __toESM(require("fs"));
|
|
6029
6048
|
var os4 = __toESM(require("os"));
|
|
6030
6049
|
var import_core9 = __toESM(require_dist());
|
|
6031
6050
|
function getEpisodaRoot2() {
|
|
6032
|
-
return process.env.EPISODA_ROOT ||
|
|
6051
|
+
return process.env.EPISODA_ROOT || path14.join(os4.homedir(), "episoda");
|
|
6033
6052
|
}
|
|
6034
6053
|
function getWorktreeInfo(moduleUid, workspaceSlug, projectSlug) {
|
|
6035
6054
|
const root = getEpisodaRoot2();
|
|
6036
|
-
const worktreePath =
|
|
6055
|
+
const worktreePath = path14.join(root, workspaceSlug, projectSlug, moduleUid);
|
|
6037
6056
|
return {
|
|
6038
6057
|
path: worktreePath,
|
|
6039
|
-
exists:
|
|
6058
|
+
exists: fs13.existsSync(worktreePath),
|
|
6040
6059
|
moduleUid
|
|
6041
6060
|
};
|
|
6042
6061
|
}
|
|
@@ -6053,7 +6072,7 @@ async function getProjectRootPath() {
|
|
|
6053
6072
|
if (!config?.workspace_slug || !config?.project_slug) {
|
|
6054
6073
|
return null;
|
|
6055
6074
|
}
|
|
6056
|
-
return
|
|
6075
|
+
return path14.join(
|
|
6057
6076
|
getEpisodaRoot2(),
|
|
6058
6077
|
config.workspace_slug,
|
|
6059
6078
|
config.project_slug
|
|
@@ -6102,10 +6121,105 @@ function clearAllPorts() {
|
|
|
6102
6121
|
}
|
|
6103
6122
|
}
|
|
6104
6123
|
|
|
6124
|
+
// src/framework-detector.ts
|
|
6125
|
+
var fs14 = __toESM(require("fs"));
|
|
6126
|
+
var path15 = __toESM(require("path"));
|
|
6127
|
+
function getInstallCommand(cwd) {
|
|
6128
|
+
if (fs14.existsSync(path15.join(cwd, "bun.lockb"))) {
|
|
6129
|
+
return {
|
|
6130
|
+
command: ["bun", "install"],
|
|
6131
|
+
description: "Installing dependencies with bun",
|
|
6132
|
+
detectedFrom: "bun.lockb"
|
|
6133
|
+
};
|
|
6134
|
+
}
|
|
6135
|
+
if (fs14.existsSync(path15.join(cwd, "pnpm-lock.yaml"))) {
|
|
6136
|
+
return {
|
|
6137
|
+
command: ["pnpm", "install"],
|
|
6138
|
+
description: "Installing dependencies with pnpm",
|
|
6139
|
+
detectedFrom: "pnpm-lock.yaml"
|
|
6140
|
+
};
|
|
6141
|
+
}
|
|
6142
|
+
if (fs14.existsSync(path15.join(cwd, "yarn.lock"))) {
|
|
6143
|
+
return {
|
|
6144
|
+
command: ["yarn", "install"],
|
|
6145
|
+
description: "Installing dependencies with yarn",
|
|
6146
|
+
detectedFrom: "yarn.lock"
|
|
6147
|
+
};
|
|
6148
|
+
}
|
|
6149
|
+
if (fs14.existsSync(path15.join(cwd, "package-lock.json"))) {
|
|
6150
|
+
return {
|
|
6151
|
+
command: ["npm", "ci"],
|
|
6152
|
+
description: "Installing dependencies with npm ci",
|
|
6153
|
+
detectedFrom: "package-lock.json"
|
|
6154
|
+
};
|
|
6155
|
+
}
|
|
6156
|
+
if (fs14.existsSync(path15.join(cwd, "package.json"))) {
|
|
6157
|
+
return {
|
|
6158
|
+
command: ["npm", "install"],
|
|
6159
|
+
description: "Installing dependencies with npm",
|
|
6160
|
+
detectedFrom: "package.json"
|
|
6161
|
+
};
|
|
6162
|
+
}
|
|
6163
|
+
if (fs14.existsSync(path15.join(cwd, "Pipfile.lock")) || fs14.existsSync(path15.join(cwd, "Pipfile"))) {
|
|
6164
|
+
return {
|
|
6165
|
+
command: ["pipenv", "install"],
|
|
6166
|
+
description: "Installing dependencies with pipenv",
|
|
6167
|
+
detectedFrom: fs14.existsSync(path15.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
|
|
6168
|
+
};
|
|
6169
|
+
}
|
|
6170
|
+
if (fs14.existsSync(path15.join(cwd, "poetry.lock"))) {
|
|
6171
|
+
return {
|
|
6172
|
+
command: ["poetry", "install"],
|
|
6173
|
+
description: "Installing dependencies with poetry",
|
|
6174
|
+
detectedFrom: "poetry.lock"
|
|
6175
|
+
};
|
|
6176
|
+
}
|
|
6177
|
+
if (fs14.existsSync(path15.join(cwd, "pyproject.toml"))) {
|
|
6178
|
+
const pyprojectPath = path15.join(cwd, "pyproject.toml");
|
|
6179
|
+
const content = fs14.readFileSync(pyprojectPath, "utf-8");
|
|
6180
|
+
if (content.includes("[tool.poetry]")) {
|
|
6181
|
+
return {
|
|
6182
|
+
command: ["poetry", "install"],
|
|
6183
|
+
description: "Installing dependencies with poetry",
|
|
6184
|
+
detectedFrom: "pyproject.toml"
|
|
6185
|
+
};
|
|
6186
|
+
}
|
|
6187
|
+
}
|
|
6188
|
+
if (fs14.existsSync(path15.join(cwd, "requirements.txt"))) {
|
|
6189
|
+
return {
|
|
6190
|
+
command: ["pip", "install", "-r", "requirements.txt"],
|
|
6191
|
+
description: "Installing dependencies with pip",
|
|
6192
|
+
detectedFrom: "requirements.txt"
|
|
6193
|
+
};
|
|
6194
|
+
}
|
|
6195
|
+
if (fs14.existsSync(path15.join(cwd, "Gemfile.lock")) || fs14.existsSync(path15.join(cwd, "Gemfile"))) {
|
|
6196
|
+
return {
|
|
6197
|
+
command: ["bundle", "install"],
|
|
6198
|
+
description: "Installing dependencies with bundler",
|
|
6199
|
+
detectedFrom: fs14.existsSync(path15.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
|
|
6200
|
+
};
|
|
6201
|
+
}
|
|
6202
|
+
if (fs14.existsSync(path15.join(cwd, "go.sum")) || fs14.existsSync(path15.join(cwd, "go.mod"))) {
|
|
6203
|
+
return {
|
|
6204
|
+
command: ["go", "mod", "download"],
|
|
6205
|
+
description: "Downloading Go modules",
|
|
6206
|
+
detectedFrom: fs14.existsSync(path15.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
|
|
6207
|
+
};
|
|
6208
|
+
}
|
|
6209
|
+
if (fs14.existsSync(path15.join(cwd, "Cargo.lock")) || fs14.existsSync(path15.join(cwd, "Cargo.toml"))) {
|
|
6210
|
+
return {
|
|
6211
|
+
command: ["cargo", "build"],
|
|
6212
|
+
description: "Building Rust project (downloads dependencies)",
|
|
6213
|
+
detectedFrom: fs14.existsSync(path15.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
|
|
6214
|
+
};
|
|
6215
|
+
}
|
|
6216
|
+
return null;
|
|
6217
|
+
}
|
|
6218
|
+
|
|
6105
6219
|
// src/daemon/daemon-process.ts
|
|
6106
|
-
var
|
|
6220
|
+
var fs15 = __toESM(require("fs"));
|
|
6107
6221
|
var os5 = __toESM(require("os"));
|
|
6108
|
-
var
|
|
6222
|
+
var path16 = __toESM(require("path"));
|
|
6109
6223
|
var packageJson = require_package();
|
|
6110
6224
|
async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
|
|
6111
6225
|
const now = Date.now();
|
|
@@ -6602,7 +6716,7 @@ var Daemon = class _Daemon {
|
|
|
6602
6716
|
client.updateActivity();
|
|
6603
6717
|
try {
|
|
6604
6718
|
const gitCmd = message.command;
|
|
6605
|
-
const bareRepoPath =
|
|
6719
|
+
const bareRepoPath = path16.join(projectPath, ".bare");
|
|
6606
6720
|
const cwd = gitCmd.worktreePath || bareRepoPath;
|
|
6607
6721
|
if (gitCmd.worktreePath) {
|
|
6608
6722
|
console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
|
|
@@ -7101,8 +7215,9 @@ var Daemon = class _Daemon {
|
|
|
7101
7215
|
const setupConfig = worktreeConfig?.project_settings;
|
|
7102
7216
|
const envVars = await fetchEnvVars();
|
|
7103
7217
|
const hasEnvVars = Object.keys(envVars).length > 0;
|
|
7104
|
-
|
|
7105
|
-
|
|
7218
|
+
const hasSetupConfig = setupConfig?.worktree_copy_files?.length || setupConfig?.worktree_setup_script || hasEnvVars;
|
|
7219
|
+
{
|
|
7220
|
+
console.log(`[Daemon] EP986: Starting async worktree setup for ${moduleUid}${hasSetupConfig ? " (with config)" : " (for dependency installation)"}`);
|
|
7106
7221
|
await worktreeManager.updateWorktreeStatus(moduleUid, "pending");
|
|
7107
7222
|
this.runWorktreeSetupAsync(
|
|
7108
7223
|
moduleUid,
|
|
@@ -7111,6 +7226,7 @@ var Daemon = class _Daemon {
|
|
|
7111
7226
|
setupConfig?.worktree_setup_script,
|
|
7112
7227
|
worktree.path,
|
|
7113
7228
|
envVars
|
|
7229
|
+
// EP973: Use server-fetched env vars
|
|
7114
7230
|
).then(() => {
|
|
7115
7231
|
console.log(`[Daemon] EP959: Setup complete for ${moduleUid}, starting tunnel`);
|
|
7116
7232
|
this.startTunnelForModule(moduleUid, worktree.path);
|
|
@@ -7119,7 +7235,8 @@ var Daemon = class _Daemon {
|
|
|
7119
7235
|
});
|
|
7120
7236
|
return;
|
|
7121
7237
|
}
|
|
7122
|
-
}
|
|
7238
|
+
}
|
|
7239
|
+
if (!worktree.exists) {
|
|
7123
7240
|
console.log(`[Daemon] EP956: No worktree for ${moduleUid} at ${worktree.path}, skipping tunnel`);
|
|
7124
7241
|
return;
|
|
7125
7242
|
}
|
|
@@ -7209,8 +7326,8 @@ var Daemon = class _Daemon {
|
|
|
7209
7326
|
let daemonPid;
|
|
7210
7327
|
try {
|
|
7211
7328
|
const pidPath = getPidFilePath();
|
|
7212
|
-
if (
|
|
7213
|
-
const pidStr =
|
|
7329
|
+
if (fs15.existsSync(pidPath)) {
|
|
7330
|
+
const pidStr = fs15.readFileSync(pidPath, "utf-8").trim();
|
|
7214
7331
|
daemonPid = parseInt(pidStr, 10);
|
|
7215
7332
|
}
|
|
7216
7333
|
} catch (pidError) {
|
|
@@ -7331,27 +7448,27 @@ var Daemon = class _Daemon {
|
|
|
7331
7448
|
*/
|
|
7332
7449
|
async installGitHooks(projectPath) {
|
|
7333
7450
|
const hooks = ["post-checkout", "pre-commit", "post-commit"];
|
|
7334
|
-
const hooksDir =
|
|
7335
|
-
if (!
|
|
7451
|
+
const hooksDir = path16.join(projectPath, ".git", "hooks");
|
|
7452
|
+
if (!fs15.existsSync(hooksDir)) {
|
|
7336
7453
|
console.warn(`[Daemon] Hooks directory not found: ${hooksDir}`);
|
|
7337
7454
|
return;
|
|
7338
7455
|
}
|
|
7339
7456
|
for (const hookName of hooks) {
|
|
7340
7457
|
try {
|
|
7341
|
-
const hookPath =
|
|
7342
|
-
const bundledHookPath =
|
|
7343
|
-
if (!
|
|
7458
|
+
const hookPath = path16.join(hooksDir, hookName);
|
|
7459
|
+
const bundledHookPath = path16.join(__dirname, "..", "hooks", hookName);
|
|
7460
|
+
if (!fs15.existsSync(bundledHookPath)) {
|
|
7344
7461
|
console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
|
|
7345
7462
|
continue;
|
|
7346
7463
|
}
|
|
7347
|
-
const hookContent =
|
|
7348
|
-
if (
|
|
7349
|
-
const existingContent =
|
|
7464
|
+
const hookContent = fs15.readFileSync(bundledHookPath, "utf-8");
|
|
7465
|
+
if (fs15.existsSync(hookPath)) {
|
|
7466
|
+
const existingContent = fs15.readFileSync(hookPath, "utf-8");
|
|
7350
7467
|
if (existingContent === hookContent) {
|
|
7351
7468
|
continue;
|
|
7352
7469
|
}
|
|
7353
7470
|
}
|
|
7354
|
-
|
|
7471
|
+
fs15.writeFileSync(hookPath, hookContent, { mode: 493 });
|
|
7355
7472
|
console.log(`[Daemon] Installed git hook: ${hookName}`);
|
|
7356
7473
|
} catch (error) {
|
|
7357
7474
|
console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
|
|
@@ -7471,17 +7588,8 @@ var Daemon = class _Daemon {
|
|
|
7471
7588
|
try {
|
|
7472
7589
|
await worktreeManager.updateWorktreeStatus(moduleUid, "running");
|
|
7473
7590
|
if (Object.keys(envVars).length > 0) {
|
|
7474
|
-
console.log(`[Daemon]
|
|
7475
|
-
|
|
7476
|
-
if (/[\s'"#$`\\]/.test(value) || value.includes("\n")) {
|
|
7477
|
-
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
|
|
7478
|
-
return `${key}="${escaped}"`;
|
|
7479
|
-
}
|
|
7480
|
-
return `${key}=${value}`;
|
|
7481
|
-
}).join("\n") + "\n";
|
|
7482
|
-
const envPath = path14.join(worktreePath, ".env");
|
|
7483
|
-
fs13.writeFileSync(envPath, envContent, { mode: 384 });
|
|
7484
|
-
console.log(`[Daemon] EP964: .env written to ${envPath}`);
|
|
7591
|
+
console.log(`[Daemon] EP988: Writing .env with ${Object.keys(envVars).length} variables to ${moduleUid}`);
|
|
7592
|
+
writeEnvFile(worktreePath, envVars);
|
|
7485
7593
|
}
|
|
7486
7594
|
if (copyFiles.length > 0) {
|
|
7487
7595
|
console.log(`[Daemon] EP964: DEPRECATED - Copying ${copyFiles.length} files to ${moduleUid}`);
|
|
@@ -7491,6 +7599,29 @@ var Daemon = class _Daemon {
|
|
|
7491
7599
|
console.warn(`[Daemon] EP964: File copy failed (non-fatal): ${copyResult.error}`);
|
|
7492
7600
|
}
|
|
7493
7601
|
}
|
|
7602
|
+
const installCmd = getInstallCommand(worktreePath);
|
|
7603
|
+
if (installCmd) {
|
|
7604
|
+
console.log(`[Daemon] EP986: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
|
|
7605
|
+
console.log(`[Daemon] EP986: Running: ${installCmd.command.join(" ")}`);
|
|
7606
|
+
try {
|
|
7607
|
+
const { execSync: execSync6 } = await import("child_process");
|
|
7608
|
+
execSync6(installCmd.command.join(" "), {
|
|
7609
|
+
cwd: worktreePath,
|
|
7610
|
+
stdio: "inherit",
|
|
7611
|
+
timeout: 10 * 60 * 1e3,
|
|
7612
|
+
// 10 minute timeout
|
|
7613
|
+
env: { ...process.env, CI: "true" }
|
|
7614
|
+
// CI=true for cleaner output
|
|
7615
|
+
});
|
|
7616
|
+
console.log(`[Daemon] EP986: Dependencies installed successfully for ${moduleUid}`);
|
|
7617
|
+
} catch (installError) {
|
|
7618
|
+
const errorMsg = installError instanceof Error ? installError.message : String(installError);
|
|
7619
|
+
console.warn(`[Daemon] EP986: Dependency installation failed (non-fatal): ${errorMsg}`);
|
|
7620
|
+
console.warn(`[Daemon] EP986: You may need to run '${installCmd.command.join(" ")}' manually`);
|
|
7621
|
+
}
|
|
7622
|
+
} else {
|
|
7623
|
+
console.log(`[Daemon] EP986: No package manager detected for ${moduleUid}, skipping dependency installation`);
|
|
7624
|
+
}
|
|
7494
7625
|
if (setupScript) {
|
|
7495
7626
|
console.log(`[Daemon] EP959: Running setup script for ${moduleUid}`);
|
|
7496
7627
|
const scriptResult = await worktreeManager.runSetupScript(moduleUid, setupScript);
|
|
@@ -8233,8 +8364,8 @@ var Daemon = class _Daemon {
|
|
|
8233
8364
|
await this.shutdown();
|
|
8234
8365
|
try {
|
|
8235
8366
|
const pidPath = getPidFilePath();
|
|
8236
|
-
if (
|
|
8237
|
-
|
|
8367
|
+
if (fs15.existsSync(pidPath)) {
|
|
8368
|
+
fs15.unlinkSync(pidPath);
|
|
8238
8369
|
console.log("[Daemon] PID file cleaned up");
|
|
8239
8370
|
}
|
|
8240
8371
|
} catch (error) {
|