@episoda/cli 0.2.146 → 0.2.148
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.
|
@@ -1880,7 +1880,7 @@ var require_git_executor = __commonJS({
|
|
|
1880
1880
|
async executeCloneBare(command, options) {
|
|
1881
1881
|
try {
|
|
1882
1882
|
const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1883
|
-
const
|
|
1883
|
+
const path25 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
1884
1884
|
try {
|
|
1885
1885
|
await fs24.access(command.path);
|
|
1886
1886
|
return {
|
|
@@ -1891,7 +1891,7 @@ var require_git_executor = __commonJS({
|
|
|
1891
1891
|
};
|
|
1892
1892
|
} catch {
|
|
1893
1893
|
}
|
|
1894
|
-
const parentDir =
|
|
1894
|
+
const parentDir = path25.dirname(command.path);
|
|
1895
1895
|
try {
|
|
1896
1896
|
await fs24.mkdir(parentDir, { recursive: true });
|
|
1897
1897
|
} catch {
|
|
@@ -1942,13 +1942,13 @@ var require_git_executor = __commonJS({
|
|
|
1942
1942
|
async executeProjectInfo(cwd, options) {
|
|
1943
1943
|
try {
|
|
1944
1944
|
const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1945
|
-
const
|
|
1945
|
+
const path25 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
1946
1946
|
let currentPath = cwd;
|
|
1947
1947
|
let projectPath = cwd;
|
|
1948
1948
|
let bareRepoPath;
|
|
1949
1949
|
for (let i = 0; i < 10; i++) {
|
|
1950
|
-
const bareDir =
|
|
1951
|
-
const episodaDir =
|
|
1950
|
+
const bareDir = path25.join(currentPath, ".bare");
|
|
1951
|
+
const episodaDir = path25.join(currentPath, ".episoda");
|
|
1952
1952
|
try {
|
|
1953
1953
|
await fs24.access(bareDir);
|
|
1954
1954
|
await fs24.access(episodaDir);
|
|
@@ -1956,7 +1956,7 @@ var require_git_executor = __commonJS({
|
|
|
1956
1956
|
bareRepoPath = bareDir;
|
|
1957
1957
|
break;
|
|
1958
1958
|
} catch {
|
|
1959
|
-
const parentPath =
|
|
1959
|
+
const parentPath = path25.dirname(currentPath);
|
|
1960
1960
|
if (parentPath === currentPath) {
|
|
1961
1961
|
break;
|
|
1962
1962
|
}
|
|
@@ -2610,29 +2610,29 @@ var require_auth = __commonJS({
|
|
|
2610
2610
|
exports2.saveConfig = saveConfig2;
|
|
2611
2611
|
exports2.validateToken = validateToken;
|
|
2612
2612
|
var fs24 = __importStar(require("fs"));
|
|
2613
|
-
var
|
|
2613
|
+
var path25 = __importStar(require("path"));
|
|
2614
2614
|
var os10 = __importStar(require("os"));
|
|
2615
2615
|
var child_process_1 = require("child_process");
|
|
2616
2616
|
var DEFAULT_CONFIG_FILE = "config.json";
|
|
2617
2617
|
var hasWarnedMissingProjectId = false;
|
|
2618
2618
|
var hasWarnedMissingRequiredFields = false;
|
|
2619
2619
|
function getConfigDir8() {
|
|
2620
|
-
return process.env.EPISODA_CONFIG_DIR ||
|
|
2620
|
+
return process.env.EPISODA_CONFIG_DIR || path25.join(os10.homedir(), ".episoda");
|
|
2621
2621
|
}
|
|
2622
2622
|
function getConfigPath(configPath) {
|
|
2623
2623
|
if (configPath) {
|
|
2624
2624
|
return configPath;
|
|
2625
2625
|
}
|
|
2626
|
-
return
|
|
2626
|
+
return path25.join(getConfigDir8(), DEFAULT_CONFIG_FILE);
|
|
2627
2627
|
}
|
|
2628
2628
|
function ensureConfigDir(configPath) {
|
|
2629
|
-
const dir =
|
|
2629
|
+
const dir = path25.dirname(configPath);
|
|
2630
2630
|
const isNew = !fs24.existsSync(dir);
|
|
2631
2631
|
if (isNew) {
|
|
2632
2632
|
fs24.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2633
2633
|
}
|
|
2634
2634
|
if (process.platform === "darwin") {
|
|
2635
|
-
const nosyncPath =
|
|
2635
|
+
const nosyncPath = path25.join(dir, ".nosync");
|
|
2636
2636
|
if (isNew || !fs24.existsSync(nosyncPath)) {
|
|
2637
2637
|
try {
|
|
2638
2638
|
fs24.writeFileSync(nosyncPath, "", { mode: 384 });
|
|
@@ -2913,7 +2913,7 @@ var require_package = __commonJS({
|
|
|
2913
2913
|
"package.json"(exports2, module2) {
|
|
2914
2914
|
module2.exports = {
|
|
2915
2915
|
name: "@episoda/cli",
|
|
2916
|
-
version: "0.2.
|
|
2916
|
+
version: "0.2.148",
|
|
2917
2917
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2918
2918
|
main: "dist/index.js",
|
|
2919
2919
|
types: "dist/index.d.ts",
|
|
@@ -3304,77 +3304,7 @@ var import_child_process2 = require("child_process");
|
|
|
3304
3304
|
var semver = __toESM(require("semver"));
|
|
3305
3305
|
|
|
3306
3306
|
// src/ipc/ipc-client.ts
|
|
3307
|
-
var net2 = __toESM(require("net"));
|
|
3308
|
-
var path5 = __toESM(require("path"));
|
|
3309
|
-
var crypto2 = __toESM(require("crypto"));
|
|
3310
3307
|
var import_core5 = __toESM(require_dist());
|
|
3311
|
-
var getSocketPath2 = () => path5.join((0, import_core5.getConfigDir)(), "daemon.sock");
|
|
3312
|
-
var DEFAULT_TIMEOUT = 15e3;
|
|
3313
|
-
async function sendCommand(command, params, timeout = DEFAULT_TIMEOUT) {
|
|
3314
|
-
return new Promise((resolve4, reject) => {
|
|
3315
|
-
const socket = net2.createConnection(getSocketPath2());
|
|
3316
|
-
const requestId = crypto2.randomUUID();
|
|
3317
|
-
let buffer = "";
|
|
3318
|
-
let timeoutHandle;
|
|
3319
|
-
timeoutHandle = setTimeout(() => {
|
|
3320
|
-
socket.destroy();
|
|
3321
|
-
reject(new Error(`Command timed out after ${timeout}ms`));
|
|
3322
|
-
}, timeout);
|
|
3323
|
-
socket.on("connect", () => {
|
|
3324
|
-
const request2 = {
|
|
3325
|
-
id: requestId,
|
|
3326
|
-
command,
|
|
3327
|
-
params
|
|
3328
|
-
};
|
|
3329
|
-
socket.write(JSON.stringify(request2) + "\n");
|
|
3330
|
-
});
|
|
3331
|
-
socket.on("data", (chunk) => {
|
|
3332
|
-
buffer += chunk.toString();
|
|
3333
|
-
const newlineIndex = buffer.indexOf("\n");
|
|
3334
|
-
if (newlineIndex === -1) return;
|
|
3335
|
-
const message = buffer.slice(0, newlineIndex);
|
|
3336
|
-
try {
|
|
3337
|
-
const response = JSON.parse(message);
|
|
3338
|
-
if (response.id !== requestId) {
|
|
3339
|
-
reject(new Error("Response ID mismatch"));
|
|
3340
|
-
return;
|
|
3341
|
-
}
|
|
3342
|
-
clearTimeout(timeoutHandle);
|
|
3343
|
-
socket.end();
|
|
3344
|
-
if (response.success) {
|
|
3345
|
-
resolve4(response.data);
|
|
3346
|
-
} else {
|
|
3347
|
-
reject(new Error(response.error || "Command failed"));
|
|
3348
|
-
}
|
|
3349
|
-
} catch (error) {
|
|
3350
|
-
clearTimeout(timeoutHandle);
|
|
3351
|
-
socket.end();
|
|
3352
|
-
reject(new Error("Invalid response from daemon"));
|
|
3353
|
-
}
|
|
3354
|
-
});
|
|
3355
|
-
socket.on("error", (error) => {
|
|
3356
|
-
clearTimeout(timeoutHandle);
|
|
3357
|
-
if (error.code === "ENOENT" || error.code === "ECONNREFUSED") {
|
|
3358
|
-
reject(new Error("Daemon is not running. Start it with: episoda dev"));
|
|
3359
|
-
} else {
|
|
3360
|
-
reject(error);
|
|
3361
|
-
}
|
|
3362
|
-
});
|
|
3363
|
-
socket.on("timeout", () => {
|
|
3364
|
-
clearTimeout(timeoutHandle);
|
|
3365
|
-
socket.destroy();
|
|
3366
|
-
reject(new Error("Connection timeout"));
|
|
3367
|
-
});
|
|
3368
|
-
});
|
|
3369
|
-
}
|
|
3370
|
-
async function isDaemonReachable() {
|
|
3371
|
-
try {
|
|
3372
|
-
await sendCommand("ping", {}, 1e3);
|
|
3373
|
-
return true;
|
|
3374
|
-
} catch (error) {
|
|
3375
|
-
return false;
|
|
3376
|
-
}
|
|
3377
|
-
}
|
|
3378
3308
|
|
|
3379
3309
|
// src/utils/update-checker.ts
|
|
3380
3310
|
var PACKAGE_NAME = "@episoda/cli";
|
|
@@ -3438,67 +3368,6 @@ function performSyncUpdate(targetVersion) {
|
|
|
3438
3368
|
};
|
|
3439
3369
|
}
|
|
3440
3370
|
}
|
|
3441
|
-
async function restartDaemon() {
|
|
3442
|
-
try {
|
|
3443
|
-
(0, import_child_process2.execSync)("episoda stop", {
|
|
3444
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
3445
|
-
timeout: 1e4
|
|
3446
|
-
});
|
|
3447
|
-
await new Promise((resolve4) => setTimeout(resolve4, 1e3));
|
|
3448
|
-
const child = (0, import_child_process2.spawn)("episoda", ["dev"], {
|
|
3449
|
-
detached: true,
|
|
3450
|
-
stdio: "ignore",
|
|
3451
|
-
shell: true
|
|
3452
|
-
});
|
|
3453
|
-
child.unref();
|
|
3454
|
-
const maxWaitMs = 1e4;
|
|
3455
|
-
const pollIntervalMs = 500;
|
|
3456
|
-
const startTime = Date.now();
|
|
3457
|
-
while (Date.now() - startTime < maxWaitMs) {
|
|
3458
|
-
await new Promise((resolve4) => setTimeout(resolve4, pollIntervalMs));
|
|
3459
|
-
try {
|
|
3460
|
-
const reachable = await isDaemonReachable();
|
|
3461
|
-
if (reachable) {
|
|
3462
|
-
return { success: true };
|
|
3463
|
-
}
|
|
3464
|
-
} catch {
|
|
3465
|
-
}
|
|
3466
|
-
}
|
|
3467
|
-
return {
|
|
3468
|
-
success: false,
|
|
3469
|
-
error: "Daemon did not respond within 10 seconds"
|
|
3470
|
-
};
|
|
3471
|
-
} catch (error) {
|
|
3472
|
-
return {
|
|
3473
|
-
success: false,
|
|
3474
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3475
|
-
};
|
|
3476
|
-
}
|
|
3477
|
-
}
|
|
3478
|
-
async function updateAndRestartDaemon(targetVersion) {
|
|
3479
|
-
const updateResult = performSyncUpdate(targetVersion);
|
|
3480
|
-
if (!updateResult.success) {
|
|
3481
|
-
return {
|
|
3482
|
-
updateSuccess: false,
|
|
3483
|
-
restartSuccess: false,
|
|
3484
|
-
error: `Update failed: ${updateResult.error}`
|
|
3485
|
-
};
|
|
3486
|
-
}
|
|
3487
|
-
const installedVersion = getInstalledVersion();
|
|
3488
|
-
if (installedVersion !== targetVersion) {
|
|
3489
|
-
return {
|
|
3490
|
-
updateSuccess: false,
|
|
3491
|
-
restartSuccess: false,
|
|
3492
|
-
error: `Version mismatch: expected ${targetVersion}, got ${installedVersion || "unknown"}`
|
|
3493
|
-
};
|
|
3494
|
-
}
|
|
3495
|
-
const restartResult = await restartDaemon();
|
|
3496
|
-
return {
|
|
3497
|
-
updateSuccess: true,
|
|
3498
|
-
restartSuccess: restartResult.success,
|
|
3499
|
-
error: restartResult.success ? void 0 : `Restart failed: ${restartResult.error}`
|
|
3500
|
-
};
|
|
3501
|
-
}
|
|
3502
3371
|
function getInstalledVersion() {
|
|
3503
3372
|
try {
|
|
3504
3373
|
const output = (0, import_child_process2.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
|
|
@@ -3514,26 +3383,26 @@ function getInstalledVersion() {
|
|
|
3514
3383
|
|
|
3515
3384
|
// src/daemon/handlers/file-handlers.ts
|
|
3516
3385
|
var fs5 = __toESM(require("fs"));
|
|
3517
|
-
var
|
|
3386
|
+
var path6 = __toESM(require("path"));
|
|
3518
3387
|
var readline = __toESM(require("readline"));
|
|
3519
3388
|
|
|
3520
3389
|
// src/daemon/permissions/path-classifier.ts
|
|
3521
|
-
var
|
|
3390
|
+
var path5 = __toESM(require("path"));
|
|
3522
3391
|
var fs4 = __toESM(require("fs"));
|
|
3523
3392
|
function classifyPath(targetPath, options) {
|
|
3524
3393
|
const { workspaceRoot, projectRoot } = options;
|
|
3525
|
-
const normalizedWorkspace =
|
|
3526
|
-
const normalizedProject =
|
|
3527
|
-
const resolvedPath =
|
|
3528
|
-
const artifactsDir =
|
|
3529
|
-
if (resolvedPath.startsWith(artifactsDir +
|
|
3394
|
+
const normalizedWorkspace = path5.resolve(workspaceRoot);
|
|
3395
|
+
const normalizedProject = path5.resolve(projectRoot);
|
|
3396
|
+
const resolvedPath = path5.isAbsolute(targetPath) ? path5.resolve(targetPath) : path5.resolve(projectRoot, targetPath);
|
|
3397
|
+
const artifactsDir = path5.join(normalizedWorkspace, "artifacts");
|
|
3398
|
+
if (resolvedPath.startsWith(artifactsDir + path5.sep) || resolvedPath === artifactsDir) {
|
|
3530
3399
|
return {
|
|
3531
3400
|
classification: "artifacts",
|
|
3532
3401
|
resolvedPath
|
|
3533
3402
|
};
|
|
3534
3403
|
}
|
|
3535
|
-
if (!resolvedPath.startsWith(normalizedProject +
|
|
3536
|
-
if (resolvedPath.startsWith(normalizedWorkspace +
|
|
3404
|
+
if (!resolvedPath.startsWith(normalizedProject + path5.sep) && resolvedPath !== normalizedProject) {
|
|
3405
|
+
if (resolvedPath.startsWith(normalizedWorkspace + path5.sep)) {
|
|
3537
3406
|
return {
|
|
3538
3407
|
classification: "unknown",
|
|
3539
3408
|
resolvedPath
|
|
@@ -3544,8 +3413,8 @@ function classifyPath(targetPath, options) {
|
|
|
3544
3413
|
resolvedPath
|
|
3545
3414
|
};
|
|
3546
3415
|
}
|
|
3547
|
-
const relativePath =
|
|
3548
|
-
const pathParts = relativePath.split(
|
|
3416
|
+
const relativePath = path5.relative(normalizedProject, resolvedPath);
|
|
3417
|
+
const pathParts = relativePath.split(path5.sep);
|
|
3549
3418
|
if (pathParts[0] === ".bare") {
|
|
3550
3419
|
return {
|
|
3551
3420
|
classification: "bare_repo",
|
|
@@ -3560,8 +3429,8 @@ function classifyPath(targetPath, options) {
|
|
|
3560
3429
|
}
|
|
3561
3430
|
const firstPart = pathParts[0];
|
|
3562
3431
|
if (firstPart && isModuleUidPattern(firstPart)) {
|
|
3563
|
-
const worktreeDir =
|
|
3564
|
-
const gitFile =
|
|
3432
|
+
const worktreeDir = path5.join(normalizedProject, firstPart);
|
|
3433
|
+
const gitFile = path5.join(worktreeDir, ".git");
|
|
3565
3434
|
const worktreeExists = fs4.existsSync(gitFile) && fs4.statSync(gitFile).isFile();
|
|
3566
3435
|
return {
|
|
3567
3436
|
classification: "worktree",
|
|
@@ -3579,19 +3448,19 @@ function isModuleUidPattern(str) {
|
|
|
3579
3448
|
return /^EP\d+$/.test(str);
|
|
3580
3449
|
}
|
|
3581
3450
|
function deriveWorkspaceRoot(projectPath) {
|
|
3582
|
-
return
|
|
3451
|
+
return path5.dirname(path5.resolve(projectPath));
|
|
3583
3452
|
}
|
|
3584
3453
|
function validateWorkspacePath(filePath, projectPath) {
|
|
3585
|
-
const normalizedProjectPath =
|
|
3454
|
+
const normalizedProjectPath = path5.resolve(projectPath);
|
|
3586
3455
|
const workspaceRoot = deriveWorkspaceRoot(projectPath);
|
|
3587
|
-
const normalizedWorkspace =
|
|
3588
|
-
const artifactsDir =
|
|
3589
|
-
const absolutePath =
|
|
3590
|
-
const normalizedPath =
|
|
3591
|
-
if (normalizedPath.startsWith(normalizedProjectPath +
|
|
3456
|
+
const normalizedWorkspace = path5.resolve(workspaceRoot);
|
|
3457
|
+
const artifactsDir = path5.join(normalizedWorkspace, "artifacts");
|
|
3458
|
+
const absolutePath = path5.isAbsolute(filePath) ? path5.resolve(filePath) : path5.resolve(projectPath, filePath);
|
|
3459
|
+
const normalizedPath = path5.normalize(absolutePath);
|
|
3460
|
+
if (normalizedPath.startsWith(normalizedProjectPath + path5.sep) || normalizedPath === normalizedProjectPath) {
|
|
3592
3461
|
return normalizedPath;
|
|
3593
3462
|
}
|
|
3594
|
-
if (normalizedPath.startsWith(artifactsDir +
|
|
3463
|
+
if (normalizedPath.startsWith(artifactsDir + path5.sep) || normalizedPath === artifactsDir) {
|
|
3595
3464
|
return normalizedPath;
|
|
3596
3465
|
}
|
|
3597
3466
|
return null;
|
|
@@ -3748,7 +3617,7 @@ async function handleFileWrite(command, projectPath) {
|
|
|
3748
3617
|
}
|
|
3749
3618
|
try {
|
|
3750
3619
|
if (createDirs) {
|
|
3751
|
-
const dirPath =
|
|
3620
|
+
const dirPath = path6.dirname(validPath);
|
|
3752
3621
|
if (!fs5.existsSync(dirPath)) {
|
|
3753
3622
|
fs5.mkdirSync(dirPath, { recursive: true });
|
|
3754
3623
|
}
|
|
@@ -3806,7 +3675,7 @@ async function handleFileList(command, projectPath) {
|
|
|
3806
3675
|
const dirEntries = await fs5.promises.readdir(validPath, { withFileTypes: true });
|
|
3807
3676
|
for (const entry of dirEntries) {
|
|
3808
3677
|
if (!includeHidden && entry.name.startsWith(".")) continue;
|
|
3809
|
-
const entryPath =
|
|
3678
|
+
const entryPath = path6.join(validPath, entry.name);
|
|
3810
3679
|
const entryStats = await fs5.promises.stat(entryPath);
|
|
3811
3680
|
entries.push({
|
|
3812
3681
|
name: entry.name,
|
|
@@ -3832,8 +3701,8 @@ async function listDirectoryRecursive(basePath, currentPath, entries, includeHid
|
|
|
3832
3701
|
const dirEntries = await fs5.promises.readdir(currentPath, { withFileTypes: true });
|
|
3833
3702
|
for (const entry of dirEntries) {
|
|
3834
3703
|
if (!includeHidden && entry.name.startsWith(".")) continue;
|
|
3835
|
-
const entryPath =
|
|
3836
|
-
const relativePath =
|
|
3704
|
+
const entryPath = path6.join(currentPath, entry.name);
|
|
3705
|
+
const relativePath = path6.relative(basePath, entryPath);
|
|
3837
3706
|
try {
|
|
3838
3707
|
const entryStats = await fs5.promises.stat(entryPath);
|
|
3839
3708
|
entries.push({
|
|
@@ -3953,8 +3822,8 @@ async function searchFilesRecursive(basePath, currentPath, pattern, files, maxRe
|
|
|
3953
3822
|
for (const entry of entries) {
|
|
3954
3823
|
if (files.length >= maxResults) return;
|
|
3955
3824
|
if (entry.name.startsWith(".")) continue;
|
|
3956
|
-
const entryPath =
|
|
3957
|
-
const relativePath =
|
|
3825
|
+
const entryPath = path6.join(currentPath, entry.name);
|
|
3826
|
+
const relativePath = path6.relative(basePath, entryPath);
|
|
3958
3827
|
try {
|
|
3959
3828
|
if (entry.isDirectory()) {
|
|
3960
3829
|
await searchFilesRecursive(basePath, entryPath, pattern, files, maxResults);
|
|
@@ -4012,7 +3881,7 @@ async function handleFileGrep(command, projectPath) {
|
|
|
4012
3881
|
}
|
|
4013
3882
|
async function grepFile(basePath, filePath, pattern, matches, maxResults) {
|
|
4014
3883
|
if (matches.length >= maxResults) return;
|
|
4015
|
-
const relativePath =
|
|
3884
|
+
const relativePath = path6.relative(basePath, filePath);
|
|
4016
3885
|
const fileStream = fs5.createReadStream(filePath, { encoding: "utf8" });
|
|
4017
3886
|
const rl = readline.createInterface({
|
|
4018
3887
|
input: fileStream,
|
|
@@ -4027,7 +3896,7 @@ async function grepFile(basePath, filePath, pattern, matches, maxResults) {
|
|
|
4027
3896
|
}
|
|
4028
3897
|
if (pattern.test(line)) {
|
|
4029
3898
|
matches.push({
|
|
4030
|
-
file: relativePath ||
|
|
3899
|
+
file: relativePath || path6.basename(filePath),
|
|
4031
3900
|
line: lineNumber,
|
|
4032
3901
|
content: line.slice(0, 500)
|
|
4033
3902
|
// Truncate long lines
|
|
@@ -4041,7 +3910,7 @@ async function grepDirectoryRecursive(basePath, currentPath, searchPattern, file
|
|
|
4041
3910
|
for (const entry of entries) {
|
|
4042
3911
|
if (matches.length >= maxResults) return;
|
|
4043
3912
|
if (entry.name.startsWith(".")) continue;
|
|
4044
|
-
const entryPath =
|
|
3913
|
+
const entryPath = path6.join(currentPath, entry.name);
|
|
4045
3914
|
try {
|
|
4046
3915
|
if (entry.isDirectory()) {
|
|
4047
3916
|
await grepDirectoryRecursive(basePath, entryPath, searchPattern, filePattern, matches, maxResults);
|
|
@@ -4132,7 +4001,7 @@ async function handleFileDelete(command, projectPath) {
|
|
|
4132
4001
|
error: "Invalid path: directory traversal not allowed"
|
|
4133
4002
|
};
|
|
4134
4003
|
}
|
|
4135
|
-
const normalizedProjectPath =
|
|
4004
|
+
const normalizedProjectPath = path6.resolve(projectPath);
|
|
4136
4005
|
if (validPath === normalizedProjectPath) {
|
|
4137
4006
|
return {
|
|
4138
4007
|
success: false,
|
|
@@ -4230,13 +4099,13 @@ async function handleFileMkdir(command, projectPath) {
|
|
|
4230
4099
|
|
|
4231
4100
|
// src/daemon/handlers/exec-handler.ts
|
|
4232
4101
|
var import_child_process3 = require("child_process");
|
|
4233
|
-
var
|
|
4102
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
4234
4103
|
var MAX_TIMEOUT = 3e5;
|
|
4235
4104
|
async function handleExec(command, projectPath) {
|
|
4236
4105
|
const {
|
|
4237
4106
|
command: cmd,
|
|
4238
4107
|
cwd = projectPath,
|
|
4239
|
-
timeout =
|
|
4108
|
+
timeout = DEFAULT_TIMEOUT,
|
|
4240
4109
|
env = {}
|
|
4241
4110
|
} = command;
|
|
4242
4111
|
const effectiveTimeout = Math.min(Math.max(timeout, 1e3), MAX_TIMEOUT);
|
|
@@ -4312,7 +4181,7 @@ async function handleExec(command, projectPath) {
|
|
|
4312
4181
|
}
|
|
4313
4182
|
|
|
4314
4183
|
// src/daemon/handlers/worktree-handlers.ts
|
|
4315
|
-
var
|
|
4184
|
+
var path16 = __toESM(require("path"));
|
|
4316
4185
|
var fs15 = __toESM(require("fs"));
|
|
4317
4186
|
var os6 = __toESM(require("os"));
|
|
4318
4187
|
var import_child_process8 = require("child_process");
|
|
@@ -4320,7 +4189,7 @@ var import_util = require("util");
|
|
|
4320
4189
|
|
|
4321
4190
|
// src/daemon/worktree-manager.ts
|
|
4322
4191
|
var fs6 = __toESM(require("fs"));
|
|
4323
|
-
var
|
|
4192
|
+
var path7 = __toESM(require("path"));
|
|
4324
4193
|
var import_core6 = __toESM(require_dist());
|
|
4325
4194
|
function validateModuleUid(moduleUid) {
|
|
4326
4195
|
if (!moduleUid || typeof moduleUid !== "string" || !moduleUid.trim()) {
|
|
@@ -4344,8 +4213,8 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4344
4213
|
// ============================================================
|
|
4345
4214
|
this.lockPath = "";
|
|
4346
4215
|
this.projectRoot = projectRoot;
|
|
4347
|
-
this.bareRepoPath =
|
|
4348
|
-
this.configPath =
|
|
4216
|
+
this.bareRepoPath = path7.join(projectRoot, ".bare");
|
|
4217
|
+
this.configPath = path7.join(projectRoot, ".episoda", "config.json");
|
|
4349
4218
|
this.gitExecutor = new import_core6.GitExecutor();
|
|
4350
4219
|
}
|
|
4351
4220
|
/**
|
|
@@ -4421,7 +4290,7 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4421
4290
|
*/
|
|
4422
4291
|
static async createProject(projectRoot, repoUrl, projectId, workspaceSlug, projectSlug) {
|
|
4423
4292
|
const manager = new _WorktreeManager(projectRoot);
|
|
4424
|
-
const episodaDir =
|
|
4293
|
+
const episodaDir = path7.join(projectRoot, ".episoda");
|
|
4425
4294
|
fs6.mkdirSync(episodaDir, { recursive: true });
|
|
4426
4295
|
const cloneResult = await manager.gitExecutor.execute({
|
|
4427
4296
|
action: "clone_bare",
|
|
@@ -4453,8 +4322,8 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4453
4322
|
error: `Invalid module UID: "${moduleUid}" - contains disallowed characters`
|
|
4454
4323
|
};
|
|
4455
4324
|
}
|
|
4456
|
-
const worktreePath =
|
|
4457
|
-
const normalizedWorktreePath =
|
|
4325
|
+
const worktreePath = path7.join(this.projectRoot, moduleUid);
|
|
4326
|
+
const normalizedWorktreePath = path7.resolve(worktreePath);
|
|
4458
4327
|
const lockAcquired = await this.acquireLock();
|
|
4459
4328
|
if (!lockAcquired) {
|
|
4460
4329
|
return {
|
|
@@ -4476,7 +4345,7 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4476
4345
|
action: "worktree_list"
|
|
4477
4346
|
}, { cwd: this.bareRepoPath });
|
|
4478
4347
|
const worktrees = listResult.details?.worktrees || [];
|
|
4479
|
-
const matching = worktrees.find((w) =>
|
|
4348
|
+
const matching = worktrees.find((w) => path7.resolve(w.path) === normalizedWorktreePath);
|
|
4480
4349
|
if (matching) {
|
|
4481
4350
|
const adoptedWorktree = {
|
|
4482
4351
|
moduleUid,
|
|
@@ -4736,7 +4605,7 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4736
4605
|
try {
|
|
4737
4606
|
const validation = await this.validateWorktrees();
|
|
4738
4607
|
for (const orphanPath of validation.orphaned) {
|
|
4739
|
-
const dirName =
|
|
4608
|
+
const dirName = path7.basename(orphanPath);
|
|
4740
4609
|
const isModuleWorktree = /^EP\d+$/.test(dirName);
|
|
4741
4610
|
if (!isModuleWorktree) {
|
|
4742
4611
|
console.log(`[WorktreeManager] EP1190: Found non-module worktree: ${dirName}`);
|
|
@@ -4872,7 +4741,7 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4872
4741
|
// Turborepo cache
|
|
4873
4742
|
];
|
|
4874
4743
|
for (const cacheDir of cacheDirs) {
|
|
4875
|
-
const cachePath =
|
|
4744
|
+
const cachePath = path7.join(worktreePath, cacheDir);
|
|
4876
4745
|
try {
|
|
4877
4746
|
if (fs6.existsSync(cachePath)) {
|
|
4878
4747
|
console.log(`[WorktreeManager] EP1070: Cleaning build cache: ${cacheDir}`);
|
|
@@ -4902,7 +4771,7 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4902
4771
|
}
|
|
4903
4772
|
writeConfig(config) {
|
|
4904
4773
|
try {
|
|
4905
|
-
const dir =
|
|
4774
|
+
const dir = path7.dirname(this.configPath);
|
|
4906
4775
|
if (!fs6.existsSync(dir)) {
|
|
4907
4776
|
fs6.mkdirSync(dir, { recursive: true });
|
|
4908
4777
|
}
|
|
@@ -4988,10 +4857,10 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4988
4857
|
}
|
|
4989
4858
|
try {
|
|
4990
4859
|
for (const file of files) {
|
|
4991
|
-
const srcPath =
|
|
4992
|
-
const destPath =
|
|
4860
|
+
const srcPath = path7.join(mainWorktree.worktreePath, file);
|
|
4861
|
+
const destPath = path7.join(worktree.worktreePath, file);
|
|
4993
4862
|
if (fs6.existsSync(srcPath)) {
|
|
4994
|
-
const destDir =
|
|
4863
|
+
const destDir = path7.dirname(destPath);
|
|
4995
4864
|
if (!fs6.existsSync(destDir)) {
|
|
4996
4865
|
fs6.mkdirSync(destDir, { recursive: true });
|
|
4997
4866
|
}
|
|
@@ -5084,10 +4953,10 @@ function getEpisodaRoot() {
|
|
|
5084
4953
|
if (process.env.EPISODA_MODE === "cloud") {
|
|
5085
4954
|
return process.env.HOME || "/home/episoda";
|
|
5086
4955
|
}
|
|
5087
|
-
return
|
|
4956
|
+
return path7.join(require("os").homedir(), "episoda");
|
|
5088
4957
|
}
|
|
5089
4958
|
function getProjectPath(workspaceSlug, projectSlug) {
|
|
5090
|
-
return
|
|
4959
|
+
return path7.join(getEpisodaRoot(), workspaceSlug, projectSlug);
|
|
5091
4960
|
}
|
|
5092
4961
|
async function isWorktreeProject(projectRoot) {
|
|
5093
4962
|
const debug = process.env.EPISODA_DEBUG === "1" || process.env.GIT_CREDENTIAL_EPISODA_DEBUG === "1";
|
|
@@ -5102,7 +4971,7 @@ async function isWorktreeProject(projectRoot) {
|
|
|
5102
4971
|
return result;
|
|
5103
4972
|
}
|
|
5104
4973
|
async function findProjectRoot(startPath) {
|
|
5105
|
-
let current =
|
|
4974
|
+
let current = path7.resolve(startPath);
|
|
5106
4975
|
const episodaRoot = getEpisodaRoot();
|
|
5107
4976
|
const debug = process.env.EPISODA_DEBUG === "1" || process.env.GIT_CREDENTIAL_EPISODA_DEBUG === "1";
|
|
5108
4977
|
if (debug) {
|
|
@@ -5115,8 +4984,8 @@ async function findProjectRoot(startPath) {
|
|
|
5115
4984
|
return null;
|
|
5116
4985
|
}
|
|
5117
4986
|
for (let i = 0; i < 10; i++) {
|
|
5118
|
-
const bareDir =
|
|
5119
|
-
const episodaDir =
|
|
4987
|
+
const bareDir = path7.join(current, ".bare");
|
|
4988
|
+
const episodaDir = path7.join(current, ".episoda");
|
|
5120
4989
|
if (debug) {
|
|
5121
4990
|
const bareExists = fs6.existsSync(bareDir);
|
|
5122
4991
|
const episodaExists = fs6.existsSync(episodaDir);
|
|
@@ -5130,7 +4999,7 @@ async function findProjectRoot(startPath) {
|
|
|
5130
4999
|
return current;
|
|
5131
5000
|
}
|
|
5132
5001
|
}
|
|
5133
|
-
const parent =
|
|
5002
|
+
const parent = path7.dirname(current);
|
|
5134
5003
|
if (parent === current) {
|
|
5135
5004
|
break;
|
|
5136
5005
|
}
|
|
@@ -5169,15 +5038,15 @@ var import_fs = require("fs");
|
|
|
5169
5038
|
var import_child_process5 = require("child_process");
|
|
5170
5039
|
var http = __toESM(require("http"));
|
|
5171
5040
|
var fs10 = __toESM(require("fs"));
|
|
5172
|
-
var
|
|
5041
|
+
var path11 = __toESM(require("path"));
|
|
5173
5042
|
var import_events = require("events");
|
|
5174
5043
|
var import_core7 = __toESM(require_dist());
|
|
5175
5044
|
|
|
5176
5045
|
// src/utils/port-check.ts
|
|
5177
|
-
var
|
|
5046
|
+
var net2 = __toESM(require("net"));
|
|
5178
5047
|
async function isPortInUse(port) {
|
|
5179
5048
|
return new Promise((resolve4) => {
|
|
5180
|
-
const server =
|
|
5049
|
+
const server = net2.createServer();
|
|
5181
5050
|
server.once("error", (err) => {
|
|
5182
5051
|
if (err.code === "EADDRINUSE") {
|
|
5183
5052
|
resolve4(true);
|
|
@@ -5195,12 +5064,12 @@ async function isPortInUse(port) {
|
|
|
5195
5064
|
|
|
5196
5065
|
// src/utils/env-cache.ts
|
|
5197
5066
|
var fs8 = __toESM(require("fs"));
|
|
5198
|
-
var
|
|
5067
|
+
var path9 = __toESM(require("path"));
|
|
5199
5068
|
var os = __toESM(require("os"));
|
|
5200
5069
|
|
|
5201
5070
|
// src/utils/env-setup.ts
|
|
5202
5071
|
var fs7 = __toESM(require("fs"));
|
|
5203
|
-
var
|
|
5072
|
+
var path8 = __toESM(require("path"));
|
|
5204
5073
|
async function fetchEnvVars(apiUrl, accessToken) {
|
|
5205
5074
|
try {
|
|
5206
5075
|
const url = `${apiUrl}/api/cli/env-vars`;
|
|
@@ -5235,16 +5104,16 @@ function writeEnvFile(targetPath, envVars) {
|
|
|
5235
5104
|
}
|
|
5236
5105
|
return `${key}=${value}`;
|
|
5237
5106
|
}).join("\n") + "\n";
|
|
5238
|
-
const envPath =
|
|
5107
|
+
const envPath = path8.join(targetPath, ".env");
|
|
5239
5108
|
fs7.writeFileSync(envPath, envContent, { mode: 384 });
|
|
5240
5109
|
console.log(`[env-setup] Wrote ${Object.keys(envVars).length} env vars to ${envPath}`);
|
|
5241
5110
|
}
|
|
5242
5111
|
|
|
5243
5112
|
// src/utils/env-cache.ts
|
|
5244
5113
|
var DEFAULT_CACHE_TTL = 60;
|
|
5245
|
-
var CACHE_DIR =
|
|
5114
|
+
var CACHE_DIR = path9.join(os.homedir(), ".episoda", "cache");
|
|
5246
5115
|
function getCacheFilePath(projectId) {
|
|
5247
|
-
return
|
|
5116
|
+
return path9.join(CACHE_DIR, `env-vars-${projectId}.json`);
|
|
5248
5117
|
}
|
|
5249
5118
|
function ensureCacheDir() {
|
|
5250
5119
|
if (!fs8.existsSync(CACHE_DIR)) {
|
|
@@ -5346,10 +5215,10 @@ No cached values available as fallback.`
|
|
|
5346
5215
|
|
|
5347
5216
|
// src/preview/dev-server-registry.ts
|
|
5348
5217
|
var fs9 = __toESM(require("fs"));
|
|
5349
|
-
var
|
|
5218
|
+
var path10 = __toESM(require("path"));
|
|
5350
5219
|
var os2 = __toESM(require("os"));
|
|
5351
5220
|
var import_child_process4 = require("child_process");
|
|
5352
|
-
var DEV_SERVER_REGISTRY_DIR =
|
|
5221
|
+
var DEV_SERVER_REGISTRY_DIR = path10.join(os2.homedir(), ".episoda", "dev-servers");
|
|
5353
5222
|
var DevServerRegistry = class {
|
|
5354
5223
|
constructor() {
|
|
5355
5224
|
this.ensureRegistryDir();
|
|
@@ -5372,7 +5241,7 @@ var DevServerRegistry = class {
|
|
|
5372
5241
|
* Get the registry file path for a module
|
|
5373
5242
|
*/
|
|
5374
5243
|
getEntryPath(moduleUid) {
|
|
5375
|
-
return
|
|
5244
|
+
return path10.join(DEV_SERVER_REGISTRY_DIR, `${moduleUid}.json`);
|
|
5376
5245
|
}
|
|
5377
5246
|
/**
|
|
5378
5247
|
* Register a dev server
|
|
@@ -5883,7 +5752,7 @@ var DevServerRunner = class extends import_events.EventEmitter {
|
|
|
5883
5752
|
cacheTtl: 300
|
|
5884
5753
|
});
|
|
5885
5754
|
console.log(`[DevServerRunner] Loaded ${Object.keys(result.envVars).length} env vars`);
|
|
5886
|
-
const envFilePath =
|
|
5755
|
+
const envFilePath = path11.join(projectPath, ".env");
|
|
5887
5756
|
if (!fs10.existsSync(envFilePath) && Object.keys(result.envVars).length > 0) {
|
|
5888
5757
|
console.log(`[DevServerRunner] Writing .env file`);
|
|
5889
5758
|
writeEnvFile(projectPath, result.envVars);
|
|
@@ -6033,14 +5902,14 @@ var DevServerRunner = class extends import_events.EventEmitter {
|
|
|
6033
5902
|
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
6034
5903
|
}
|
|
6035
5904
|
getLogsDir() {
|
|
6036
|
-
const logsDir =
|
|
5905
|
+
const logsDir = path11.join((0, import_core7.getConfigDir)(), "logs");
|
|
6037
5906
|
if (!fs10.existsSync(logsDir)) {
|
|
6038
5907
|
fs10.mkdirSync(logsDir, { recursive: true });
|
|
6039
5908
|
}
|
|
6040
5909
|
return logsDir;
|
|
6041
5910
|
}
|
|
6042
5911
|
getLogFilePath(moduleUid) {
|
|
6043
|
-
return
|
|
5912
|
+
return path11.join(this.getLogsDir(), `dev-${moduleUid}.log`);
|
|
6044
5913
|
}
|
|
6045
5914
|
rotateLogIfNeeded(logPath) {
|
|
6046
5915
|
try {
|
|
@@ -6093,13 +5962,13 @@ function getDevServerRunner() {
|
|
|
6093
5962
|
var import_child_process7 = require("child_process");
|
|
6094
5963
|
var import_events2 = require("events");
|
|
6095
5964
|
var fs12 = __toESM(require("fs"));
|
|
6096
|
-
var
|
|
5965
|
+
var path13 = __toESM(require("path"));
|
|
6097
5966
|
var os4 = __toESM(require("os"));
|
|
6098
5967
|
|
|
6099
5968
|
// src/tunnel/cloudflared-manager.ts
|
|
6100
5969
|
var import_child_process6 = require("child_process");
|
|
6101
5970
|
var fs11 = __toESM(require("fs"));
|
|
6102
|
-
var
|
|
5971
|
+
var path12 = __toESM(require("path"));
|
|
6103
5972
|
var os3 = __toESM(require("os"));
|
|
6104
5973
|
var https = __toESM(require("https"));
|
|
6105
5974
|
var tar = __toESM(require("tar"));
|
|
@@ -6118,11 +5987,11 @@ var DOWNLOAD_URLS = {
|
|
|
6118
5987
|
}
|
|
6119
5988
|
};
|
|
6120
5989
|
function getEpisodaBinDir() {
|
|
6121
|
-
return
|
|
5990
|
+
return path12.join(os3.homedir(), ".episoda", "bin");
|
|
6122
5991
|
}
|
|
6123
5992
|
function getCloudflaredPath() {
|
|
6124
5993
|
const binaryName = os3.platform() === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
6125
|
-
return
|
|
5994
|
+
return path12.join(getEpisodaBinDir(), binaryName);
|
|
6126
5995
|
}
|
|
6127
5996
|
function isCloudflaredInPath() {
|
|
6128
5997
|
try {
|
|
@@ -6220,7 +6089,7 @@ async function downloadCloudflared() {
|
|
|
6220
6089
|
fs11.mkdirSync(binDir, { recursive: true });
|
|
6221
6090
|
const isTgz = url.endsWith(".tgz");
|
|
6222
6091
|
if (isTgz) {
|
|
6223
|
-
const tempFile =
|
|
6092
|
+
const tempFile = path12.join(binDir, "cloudflared.tgz");
|
|
6224
6093
|
console.log(`[Tunnel] Downloading cloudflared from ${url}...`);
|
|
6225
6094
|
await downloadFile(url, tempFile);
|
|
6226
6095
|
console.log("[Tunnel] Extracting cloudflared...");
|
|
@@ -6424,7 +6293,7 @@ function getDaemonModeConfig() {
|
|
|
6424
6293
|
}
|
|
6425
6294
|
|
|
6426
6295
|
// src/tunnel/tunnel-manager.ts
|
|
6427
|
-
var TUNNEL_PID_DIR =
|
|
6296
|
+
var TUNNEL_PID_DIR = path13.join(os4.homedir(), ".episoda", "tunnels");
|
|
6428
6297
|
var TUNNEL_TIMEOUTS = {
|
|
6429
6298
|
/** Time to wait for Named Tunnel connection (includes API token fetch + connect) */
|
|
6430
6299
|
NAMED_TUNNEL_CONNECT: 6e4,
|
|
@@ -6470,7 +6339,7 @@ var TunnelManager = class extends import_events2.EventEmitter {
|
|
|
6470
6339
|
* EP877: Get PID file path for a module
|
|
6471
6340
|
*/
|
|
6472
6341
|
getPidFilePath(moduleUid) {
|
|
6473
|
-
return
|
|
6342
|
+
return path13.join(TUNNEL_PID_DIR, `${moduleUid}.pid`);
|
|
6474
6343
|
}
|
|
6475
6344
|
/**
|
|
6476
6345
|
* EP877: Write PID to file for tracking across restarts
|
|
@@ -7086,12 +6955,12 @@ function getTunnelManager() {
|
|
|
7086
6955
|
|
|
7087
6956
|
// src/utils/port-allocator.ts
|
|
7088
6957
|
var fs13 = __toESM(require("fs"));
|
|
7089
|
-
var
|
|
6958
|
+
var path14 = __toESM(require("path"));
|
|
7090
6959
|
var os5 = __toESM(require("os"));
|
|
7091
6960
|
var PORT_RANGE_START = 3100;
|
|
7092
6961
|
var PORT_RANGE_END = 3199;
|
|
7093
6962
|
var PORT_WARNING_THRESHOLD = 80;
|
|
7094
|
-
var PORTS_FILE =
|
|
6963
|
+
var PORTS_FILE = path14.join(os5.homedir(), ".episoda", "ports.json");
|
|
7095
6964
|
var portAssignments = /* @__PURE__ */ new Map();
|
|
7096
6965
|
var initialized = false;
|
|
7097
6966
|
function loadFromDisk() {
|
|
@@ -7116,7 +6985,7 @@ function loadFromDisk() {
|
|
|
7116
6985
|
}
|
|
7117
6986
|
function saveToDisk() {
|
|
7118
6987
|
try {
|
|
7119
|
-
const dir =
|
|
6988
|
+
const dir = path14.dirname(PORTS_FILE);
|
|
7120
6989
|
if (!fs13.existsSync(dir)) {
|
|
7121
6990
|
fs13.mkdirSync(dir, { recursive: true });
|
|
7122
6991
|
}
|
|
@@ -7660,16 +7529,16 @@ async function deleteWorktree(config, moduleUid) {
|
|
|
7660
7529
|
|
|
7661
7530
|
// src/daemon/package-manager.ts
|
|
7662
7531
|
var fs14 = __toESM(require("fs"));
|
|
7663
|
-
var
|
|
7532
|
+
var path15 = __toESM(require("path"));
|
|
7664
7533
|
var PACKAGE_MANAGERS = {
|
|
7665
7534
|
javascript: [
|
|
7666
7535
|
{
|
|
7667
7536
|
name: "pnpm",
|
|
7668
7537
|
detector: (p) => {
|
|
7669
|
-
if (fs14.existsSync(
|
|
7538
|
+
if (fs14.existsSync(path15.join(p, "pnpm-lock.yaml"))) {
|
|
7670
7539
|
return "pnpm-lock.yaml";
|
|
7671
7540
|
}
|
|
7672
|
-
const pkgJsonPath =
|
|
7541
|
+
const pkgJsonPath = path15.join(p, "package.json");
|
|
7673
7542
|
if (fs14.existsSync(pkgJsonPath)) {
|
|
7674
7543
|
try {
|
|
7675
7544
|
const pkg = JSON.parse(fs14.readFileSync(pkgJsonPath, "utf-8"));
|
|
@@ -7688,7 +7557,7 @@ var PACKAGE_MANAGERS = {
|
|
|
7688
7557
|
},
|
|
7689
7558
|
{
|
|
7690
7559
|
name: "yarn",
|
|
7691
|
-
detector: (p) => fs14.existsSync(
|
|
7560
|
+
detector: (p) => fs14.existsSync(path15.join(p, "yarn.lock")) ? "yarn.lock" : null,
|
|
7692
7561
|
config: {
|
|
7693
7562
|
installCmd: "yarn install --frozen-lockfile",
|
|
7694
7563
|
cacheEnvVar: "YARN_CACHE_FOLDER"
|
|
@@ -7696,14 +7565,14 @@ var PACKAGE_MANAGERS = {
|
|
|
7696
7565
|
},
|
|
7697
7566
|
{
|
|
7698
7567
|
name: "bun",
|
|
7699
|
-
detector: (p) => fs14.existsSync(
|
|
7568
|
+
detector: (p) => fs14.existsSync(path15.join(p, "bun.lockb")) ? "bun.lockb" : null,
|
|
7700
7569
|
config: {
|
|
7701
7570
|
installCmd: "bun install --frozen-lockfile"
|
|
7702
7571
|
}
|
|
7703
7572
|
},
|
|
7704
7573
|
{
|
|
7705
7574
|
name: "npm",
|
|
7706
|
-
detector: (p) => fs14.existsSync(
|
|
7575
|
+
detector: (p) => fs14.existsSync(path15.join(p, "package-lock.json")) ? "package-lock.json" : null,
|
|
7707
7576
|
config: {
|
|
7708
7577
|
installCmd: "npm ci"
|
|
7709
7578
|
}
|
|
@@ -7712,7 +7581,7 @@ var PACKAGE_MANAGERS = {
|
|
|
7712
7581
|
// EP1222: Default to pnpm for new projects without lockfile
|
|
7713
7582
|
// This encourages standardization on pnpm across Episoda projects
|
|
7714
7583
|
name: "pnpm",
|
|
7715
|
-
detector: (p) => fs14.existsSync(
|
|
7584
|
+
detector: (p) => fs14.existsSync(path15.join(p, "package.json")) ? "package.json (no lockfile - defaulting to pnpm)" : null,
|
|
7716
7585
|
config: {
|
|
7717
7586
|
installCmd: "pnpm install",
|
|
7718
7587
|
cacheEnvVar: "PNPM_HOME"
|
|
@@ -7723,8 +7592,8 @@ var PACKAGE_MANAGERS = {
|
|
|
7723
7592
|
{
|
|
7724
7593
|
name: "uv",
|
|
7725
7594
|
detector: (p) => {
|
|
7726
|
-
const pyprojectPath =
|
|
7727
|
-
if (fs14.existsSync(
|
|
7595
|
+
const pyprojectPath = path15.join(p, "pyproject.toml");
|
|
7596
|
+
if (fs14.existsSync(path15.join(p, "uv.lock"))) {
|
|
7728
7597
|
return "uv.lock";
|
|
7729
7598
|
}
|
|
7730
7599
|
if (fs14.existsSync(pyprojectPath)) {
|
|
@@ -7745,7 +7614,7 @@ var PACKAGE_MANAGERS = {
|
|
|
7745
7614
|
},
|
|
7746
7615
|
{
|
|
7747
7616
|
name: "pip",
|
|
7748
|
-
detector: (p) => fs14.existsSync(
|
|
7617
|
+
detector: (p) => fs14.existsSync(path15.join(p, "requirements.txt")) ? "requirements.txt" : null,
|
|
7749
7618
|
config: {
|
|
7750
7619
|
installCmd: "pip install -r requirements.txt"
|
|
7751
7620
|
}
|
|
@@ -7819,7 +7688,7 @@ function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
|
|
|
7819
7688
|
return;
|
|
7820
7689
|
}
|
|
7821
7690
|
const homeDir = process.env.HOME || os6.homedir();
|
|
7822
|
-
const workspaceConfigPath =
|
|
7691
|
+
const workspaceConfigPath = path16.join(
|
|
7823
7692
|
homeDir,
|
|
7824
7693
|
"episoda",
|
|
7825
7694
|
workspaceSlug,
|
|
@@ -7899,19 +7768,19 @@ async function handleWorktreeCreate(request2) {
|
|
|
7899
7768
|
}
|
|
7900
7769
|
try {
|
|
7901
7770
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
7902
|
-
const bareRepoPath =
|
|
7771
|
+
const bareRepoPath = path16.join(projectPath, ".bare");
|
|
7903
7772
|
const gitEnv = projectId ? { ...process.env, EPISODA_PROJECT_ID: projectId } : process.env;
|
|
7904
7773
|
if (!fs15.existsSync(bareRepoPath)) {
|
|
7905
7774
|
console.log(`[Worktree] K1273: Project not found, cloning lazily...`);
|
|
7906
7775
|
console.log(`[Worktree] Repo URL: ${repoUrl.replace(/\/\/[^@]*@/, "//***@")}`);
|
|
7907
|
-
const episodaDir =
|
|
7776
|
+
const episodaDir = path16.join(projectPath, ".episoda");
|
|
7908
7777
|
fs15.mkdirSync(episodaDir, { recursive: true });
|
|
7909
7778
|
try {
|
|
7910
7779
|
console.log(`[Worktree] K1273: Starting git clone...`);
|
|
7911
7780
|
await execAsync(`git clone --bare "${repoUrl}" "${bareRepoPath}"`, { env: gitEnv });
|
|
7912
7781
|
console.log(`[Worktree] K1273: Clone successful`);
|
|
7913
7782
|
await execAsync(`git -C "${bareRepoPath}" config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"`, { env: gitEnv });
|
|
7914
|
-
const configPath =
|
|
7783
|
+
const configPath = path16.join(episodaDir, "config.json");
|
|
7915
7784
|
const config2 = {
|
|
7916
7785
|
projectId,
|
|
7917
7786
|
workspaceSlug,
|
|
@@ -7968,7 +7837,7 @@ async function handleWorktreeCreate(request2) {
|
|
|
7968
7837
|
}
|
|
7969
7838
|
if (envVars && Object.keys(envVars).length > 0) {
|
|
7970
7839
|
const envContent = Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n");
|
|
7971
|
-
const envPath =
|
|
7840
|
+
const envPath = path16.join(worktreePath, ".env");
|
|
7972
7841
|
fs15.writeFileSync(envPath, envContent + "\n", "utf-8");
|
|
7973
7842
|
console.log(`[Worktree] EP1143: Wrote ${Object.keys(envVars).length} env vars to .env`);
|
|
7974
7843
|
}
|
|
@@ -8155,7 +8024,7 @@ async function handleProjectEject(request2) {
|
|
|
8155
8024
|
console.log(`[Worktree] EP1144: Ejecting project ${projectSlug} from workspace ${workspaceSlug}`);
|
|
8156
8025
|
try {
|
|
8157
8026
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
8158
|
-
const bareRepoPath =
|
|
8027
|
+
const bareRepoPath = path16.join(projectPath, ".bare");
|
|
8159
8028
|
if (!fs15.existsSync(projectPath)) {
|
|
8160
8029
|
console.log(`[Worktree] EP1144: Project path not found, nothing to eject: ${projectPath}`);
|
|
8161
8030
|
return { success: true };
|
|
@@ -8175,7 +8044,7 @@ async function handleProjectEject(request2) {
|
|
|
8175
8044
|
};
|
|
8176
8045
|
}
|
|
8177
8046
|
}
|
|
8178
|
-
const artifactsPath =
|
|
8047
|
+
const artifactsPath = path16.join(projectPath, "artifacts");
|
|
8179
8048
|
if (fs15.existsSync(artifactsPath)) {
|
|
8180
8049
|
await persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug);
|
|
8181
8050
|
}
|
|
@@ -8208,7 +8077,7 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
8208
8077
|
}
|
|
8209
8078
|
const artifacts = [];
|
|
8210
8079
|
for (const fileName of files) {
|
|
8211
|
-
const filePath =
|
|
8080
|
+
const filePath = path16.join(artifactsPath, fileName);
|
|
8212
8081
|
const stat = await fs15.promises.stat(filePath);
|
|
8213
8082
|
if (stat.isDirectory()) {
|
|
8214
8083
|
continue;
|
|
@@ -8220,7 +8089,7 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
8220
8089
|
try {
|
|
8221
8090
|
const content = await fs15.promises.readFile(filePath);
|
|
8222
8091
|
const base64Content = content.toString("base64");
|
|
8223
|
-
const ext =
|
|
8092
|
+
const ext = path16.extname(fileName).toLowerCase();
|
|
8224
8093
|
const mimeTypes = {
|
|
8225
8094
|
".json": "application/json",
|
|
8226
8095
|
".txt": "text/plain",
|
|
@@ -8276,7 +8145,7 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
8276
8145
|
}
|
|
8277
8146
|
|
|
8278
8147
|
// src/daemon/handlers/project-handlers.ts
|
|
8279
|
-
var
|
|
8148
|
+
var path17 = __toESM(require("path"));
|
|
8280
8149
|
var fs16 = __toESM(require("fs"));
|
|
8281
8150
|
function validateSlug(slug, fieldName) {
|
|
8282
8151
|
if (!slug || typeof slug !== "string") {
|
|
@@ -8317,9 +8186,9 @@ async function handleProjectSetup(params) {
|
|
|
8317
8186
|
console.log(`[ProjectSetup] EP1199: Setting up project ${workspaceSlug}/${projectSlug}`);
|
|
8318
8187
|
try {
|
|
8319
8188
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
8320
|
-
const artifactsPath =
|
|
8321
|
-
const configDir =
|
|
8322
|
-
const configPath =
|
|
8189
|
+
const artifactsPath = path17.join(projectPath, "artifacts");
|
|
8190
|
+
const configDir = path17.join(projectPath, ".episoda");
|
|
8191
|
+
const configPath = path17.join(configDir, "config.json");
|
|
8323
8192
|
await fs16.promises.mkdir(artifactsPath, { recursive: true });
|
|
8324
8193
|
await fs16.promises.mkdir(configDir, { recursive: true });
|
|
8325
8194
|
let existingConfig = {};
|
|
@@ -8451,7 +8320,7 @@ async function cleanupStaleCommits(projectPath) {
|
|
|
8451
8320
|
|
|
8452
8321
|
// src/agent/claude-binary.ts
|
|
8453
8322
|
var import_child_process10 = require("child_process");
|
|
8454
|
-
var
|
|
8323
|
+
var path18 = __toESM(require("path"));
|
|
8455
8324
|
var fs17 = __toESM(require("fs"));
|
|
8456
8325
|
var cachedBinaryPath = null;
|
|
8457
8326
|
function isValidClaudeBinary(binaryPath) {
|
|
@@ -8489,11 +8358,11 @@ async function ensureClaudeBinary() {
|
|
|
8489
8358
|
}
|
|
8490
8359
|
const bundledPaths = [
|
|
8491
8360
|
// In production: node_modules/.bin/claude
|
|
8492
|
-
|
|
8361
|
+
path18.join(__dirname, "..", "..", "node_modules", ".bin", "claude"),
|
|
8493
8362
|
// In monorepo development: packages/episoda/node_modules/.bin/claude
|
|
8494
|
-
|
|
8363
|
+
path18.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "claude"),
|
|
8495
8364
|
// Root monorepo node_modules
|
|
8496
|
-
|
|
8365
|
+
path18.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "claude")
|
|
8497
8366
|
];
|
|
8498
8367
|
for (const bundledPath of bundledPaths) {
|
|
8499
8368
|
if (fs17.existsSync(bundledPath) && isValidClaudeBinary(bundledPath)) {
|
|
@@ -8522,7 +8391,7 @@ async function ensureClaudeBinary() {
|
|
|
8522
8391
|
|
|
8523
8392
|
// src/agent/codex-binary.ts
|
|
8524
8393
|
var import_child_process11 = require("child_process");
|
|
8525
|
-
var
|
|
8394
|
+
var path19 = __toESM(require("path"));
|
|
8526
8395
|
var fs18 = __toESM(require("fs"));
|
|
8527
8396
|
var cachedBinaryPath2 = null;
|
|
8528
8397
|
function isValidCodexBinary(binaryPath) {
|
|
@@ -8560,11 +8429,11 @@ async function ensureCodexBinary() {
|
|
|
8560
8429
|
}
|
|
8561
8430
|
const bundledPaths = [
|
|
8562
8431
|
// In production: node_modules/.bin/codex
|
|
8563
|
-
|
|
8432
|
+
path19.join(__dirname, "..", "..", "node_modules", ".bin", "codex"),
|
|
8564
8433
|
// In monorepo development: packages/episoda/node_modules/.bin/codex
|
|
8565
|
-
|
|
8434
|
+
path19.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "codex"),
|
|
8566
8435
|
// Root monorepo node_modules
|
|
8567
|
-
|
|
8436
|
+
path19.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "codex")
|
|
8568
8437
|
];
|
|
8569
8438
|
for (const bundledPath of bundledPaths) {
|
|
8570
8439
|
if (fs18.existsSync(bundledPath) && isValidCodexBinary(bundledPath)) {
|
|
@@ -8663,7 +8532,7 @@ function generateCodexMcpConfigToml(servers, projectPath) {
|
|
|
8663
8532
|
|
|
8664
8533
|
// src/agent/agent-manager.ts
|
|
8665
8534
|
var import_child_process12 = require("child_process");
|
|
8666
|
-
var
|
|
8535
|
+
var path20 = __toESM(require("path"));
|
|
8667
8536
|
var fs19 = __toESM(require("fs"));
|
|
8668
8537
|
var os7 = __toESM(require("os"));
|
|
8669
8538
|
|
|
@@ -8983,7 +8852,7 @@ var AgentManager = class {
|
|
|
8983
8852
|
this.initialized = false;
|
|
8984
8853
|
// EP1133: Lock for config file writes to prevent race conditions
|
|
8985
8854
|
this.configWriteLock = Promise.resolve();
|
|
8986
|
-
this.pidDir =
|
|
8855
|
+
this.pidDir = path20.join(os7.homedir(), ".episoda", "agent-pids");
|
|
8987
8856
|
}
|
|
8988
8857
|
/**
|
|
8989
8858
|
* EP1133: Acquire lock for config file writes
|
|
@@ -9040,12 +8909,12 @@ var AgentManager = class {
|
|
|
9040
8909
|
}
|
|
9041
8910
|
loadProviderTokens(provider, sessionDir, legacyDir) {
|
|
9042
8911
|
if (provider === "codex") {
|
|
9043
|
-
const sessionAuthPath =
|
|
9044
|
-
const legacyAuthPath =
|
|
8912
|
+
const sessionAuthPath = path20.join(sessionDir, "auth.json");
|
|
8913
|
+
const legacyAuthPath = path20.join(legacyDir, "auth.json");
|
|
9045
8914
|
return this.readCodexTokensFromPath(sessionAuthPath) || this.readCodexTokensFromPath(legacyAuthPath);
|
|
9046
8915
|
}
|
|
9047
|
-
const sessionCredentialsPath =
|
|
9048
|
-
const legacyCredentialsPath =
|
|
8916
|
+
const sessionCredentialsPath = path20.join(sessionDir, ".credentials.json");
|
|
8917
|
+
const legacyCredentialsPath = path20.join(legacyDir, ".credentials.json");
|
|
9049
8918
|
return this.readClaudeTokensFromPath(sessionCredentialsPath) || this.readClaudeTokensFromPath(legacyCredentialsPath);
|
|
9050
8919
|
}
|
|
9051
8920
|
applyTokensToSession(session, tokens) {
|
|
@@ -9123,10 +8992,10 @@ var AgentManager = class {
|
|
|
9123
8992
|
findCodexRequirementsToml(sessionProjectPath) {
|
|
9124
8993
|
const candidates = [];
|
|
9125
8994
|
if (sessionProjectPath) {
|
|
9126
|
-
candidates.push(
|
|
8995
|
+
candidates.push(path20.join(sessionProjectPath, ".codex", "requirements.toml"));
|
|
9127
8996
|
}
|
|
9128
|
-
const codexHome = process.env.CODEX_HOME ||
|
|
9129
|
-
candidates.push(
|
|
8997
|
+
const codexHome = process.env.CODEX_HOME || path20.join(os7.homedir(), ".codex");
|
|
8998
|
+
candidates.push(path20.join(codexHome, "requirements.toml"));
|
|
9130
8999
|
candidates.push("/etc/codex/requirements.toml");
|
|
9131
9000
|
for (const p of candidates) {
|
|
9132
9001
|
if (fs19.existsSync(p)) return p;
|
|
@@ -9600,10 +9469,10 @@ If changes are needed, explain what needs to be done.`;
|
|
|
9600
9469
|
}
|
|
9601
9470
|
const useOAuth = !!session.credentials.oauthToken;
|
|
9602
9471
|
const useApiKey = !useOAuth && !!session.credentials.apiKey;
|
|
9603
|
-
const sessionCodexDir =
|
|
9604
|
-
const sessionClaudeDir =
|
|
9605
|
-
const legacyCodexDir =
|
|
9606
|
-
const legacyClaudeDir =
|
|
9472
|
+
const sessionCodexDir = path20.join(os7.homedir(), ".codex", "sessions", sessionId);
|
|
9473
|
+
const sessionClaudeDir = path20.join(os7.homedir(), ".claude", "sessions", sessionId);
|
|
9474
|
+
const legacyCodexDir = path20.join(os7.homedir(), ".codex");
|
|
9475
|
+
const legacyClaudeDir = path20.join(os7.homedir(), ".claude");
|
|
9607
9476
|
const sessionConfigDir = provider === "codex" ? sessionCodexDir : sessionClaudeDir;
|
|
9608
9477
|
const legacyConfigDir = provider === "codex" ? legacyCodexDir : legacyClaudeDir;
|
|
9609
9478
|
if (useOAuth) {
|
|
@@ -9627,7 +9496,7 @@ If changes are needed, explain what needs to be done.`;
|
|
|
9627
9496
|
accountId: session.credentials.accountId,
|
|
9628
9497
|
expiresAt: session.credentials.expiresAt
|
|
9629
9498
|
});
|
|
9630
|
-
const authJsonPath =
|
|
9499
|
+
const authJsonPath = path20.join(sessionCodexDir, "auth.json");
|
|
9631
9500
|
fs19.writeFileSync(authJsonPath, codexConfig["auth.json"], { mode: 384 });
|
|
9632
9501
|
console.log(`[AgentManager] EP1260: Wrote Codex auth.json to ${authJsonPath}`);
|
|
9633
9502
|
} else if (useApiKey) {
|
|
@@ -9719,13 +9588,13 @@ If changes are needed, explain what needs to be done.`;
|
|
|
9719
9588
|
};
|
|
9720
9589
|
});
|
|
9721
9590
|
const configTomlContent = generateCodexMcpConfigToml(codexMcpServers, session.projectPath);
|
|
9722
|
-
const configTomlPath =
|
|
9591
|
+
const configTomlPath = path20.join(sessionCodexDir, "config.toml");
|
|
9723
9592
|
fs19.writeFileSync(configTomlPath, configTomlContent, { mode: 384 });
|
|
9724
9593
|
console.log(`[AgentManager] EP1287: Wrote Codex config.toml at ${configTomlPath} with ${codexMcpServers.length} MCP server(s): ${codexMcpServers.map((s) => s.name).join(", ")}`);
|
|
9725
9594
|
} else {
|
|
9726
9595
|
const configTomlContent = generateCodexMcpConfigToml([], session.projectPath);
|
|
9727
9596
|
if (configTomlContent.trim()) {
|
|
9728
|
-
const configTomlPath =
|
|
9597
|
+
const configTomlPath = path20.join(sessionCodexDir, "config.toml");
|
|
9729
9598
|
fs19.writeFileSync(configTomlPath, configTomlContent, { mode: 420 });
|
|
9730
9599
|
console.log(`[AgentManager] EP1287: Wrote Codex config.toml (project trust only) at ${configTomlPath}`);
|
|
9731
9600
|
}
|
|
@@ -9733,11 +9602,11 @@ If changes are needed, explain what needs to be done.`;
|
|
|
9733
9602
|
});
|
|
9734
9603
|
} else {
|
|
9735
9604
|
await this.withConfigLock(async () => {
|
|
9736
|
-
const statsigDir =
|
|
9605
|
+
const statsigDir = path20.join(sessionClaudeDir, "statsig");
|
|
9737
9606
|
fs19.mkdirSync(statsigDir, { recursive: true });
|
|
9738
9607
|
console.log(`[AgentManager] EP1260: Created session-specific Claude dir: ${sessionClaudeDir}`);
|
|
9739
9608
|
if (useOAuth) {
|
|
9740
|
-
const credentialsPath =
|
|
9609
|
+
const credentialsPath = path20.join(sessionClaudeDir, ".credentials.json");
|
|
9741
9610
|
const oauthCredentials = {
|
|
9742
9611
|
accessToken: session.credentials.oauthToken
|
|
9743
9612
|
};
|
|
@@ -9765,10 +9634,10 @@ If changes are needed, explain what needs to be done.`;
|
|
|
9765
9634
|
if (!hasEvaluations || !hasStableId) {
|
|
9766
9635
|
throw new Error(`Invalid statsig config: missing required files`);
|
|
9767
9636
|
}
|
|
9768
|
-
const settingsPath =
|
|
9637
|
+
const settingsPath = path20.join(sessionClaudeDir, "settings.json");
|
|
9769
9638
|
fs19.writeFileSync(settingsPath, claudeConfig["settings.json"], { mode: 384 });
|
|
9770
9639
|
for (const [filename, content] of Object.entries(claudeConfig.statsig)) {
|
|
9771
|
-
const filePath =
|
|
9640
|
+
const filePath = path20.join(statsigDir, filename);
|
|
9772
9641
|
fs19.writeFileSync(filePath, content, { mode: 420 });
|
|
9773
9642
|
}
|
|
9774
9643
|
console.log("[AgentManager] EP1260: Wrote Claude config files to session directory");
|
|
@@ -10163,7 +10032,7 @@ If changes are needed, explain what needs to be done.`;
|
|
|
10163
10032
|
cleanupSessionCredentials(sessionId, provider) {
|
|
10164
10033
|
const providers = provider ? [provider] : ["claude", "codex"];
|
|
10165
10034
|
for (const p of providers) {
|
|
10166
|
-
const sessionDir = p === "codex" ?
|
|
10035
|
+
const sessionDir = p === "codex" ? path20.join(os7.homedir(), ".codex", "sessions", sessionId) : path20.join(os7.homedir(), ".claude", "sessions", sessionId);
|
|
10167
10036
|
try {
|
|
10168
10037
|
if (fs19.existsSync(sessionDir)) {
|
|
10169
10038
|
fs19.rmSync(sessionDir, { recursive: true, force: true });
|
|
@@ -10254,7 +10123,7 @@ If changes are needed, explain what needs to be done.`;
|
|
|
10254
10123
|
}
|
|
10255
10124
|
const pidFiles = fs19.readdirSync(this.pidDir).filter((f) => f.endsWith(".pid"));
|
|
10256
10125
|
for (const pidFile of pidFiles) {
|
|
10257
|
-
const pidPath =
|
|
10126
|
+
const pidPath = path20.join(this.pidDir, pidFile);
|
|
10258
10127
|
try {
|
|
10259
10128
|
const pidStr = fs19.readFileSync(pidPath, "utf-8").trim();
|
|
10260
10129
|
const pid = parseInt(pidStr, 10);
|
|
@@ -10281,14 +10150,14 @@ If changes are needed, explain what needs to be done.`;
|
|
|
10281
10150
|
* Write PID file for session tracking
|
|
10282
10151
|
*/
|
|
10283
10152
|
writePidFile(sessionId, pid) {
|
|
10284
|
-
const pidPath =
|
|
10153
|
+
const pidPath = path20.join(this.pidDir, `${sessionId}.pid`);
|
|
10285
10154
|
fs19.writeFileSync(pidPath, pid.toString());
|
|
10286
10155
|
}
|
|
10287
10156
|
/**
|
|
10288
10157
|
* Remove PID file for session
|
|
10289
10158
|
*/
|
|
10290
10159
|
removePidFile(sessionId) {
|
|
10291
|
-
const pidPath =
|
|
10160
|
+
const pidPath = path20.join(this.pidDir, `${sessionId}.pid`);
|
|
10292
10161
|
try {
|
|
10293
10162
|
if (fs19.existsSync(pidPath)) {
|
|
10294
10163
|
fs19.unlinkSync(pidPath);
|
|
@@ -10504,7 +10373,7 @@ var AgentCommandQueue = class {
|
|
|
10504
10373
|
var import_child_process13 = require("child_process");
|
|
10505
10374
|
var import_core12 = __toESM(require_dist());
|
|
10506
10375
|
var fs20 = __toESM(require("fs"));
|
|
10507
|
-
var
|
|
10376
|
+
var path21 = __toESM(require("path"));
|
|
10508
10377
|
var MAX_RESTART_ATTEMPTS = 5;
|
|
10509
10378
|
var INITIAL_RESTART_DELAY_MS = 2e3;
|
|
10510
10379
|
var MAX_RESTART_DELAY_MS = 3e4;
|
|
@@ -10512,14 +10381,14 @@ var MAX_LOG_SIZE_BYTES = 5 * 1024 * 1024;
|
|
|
10512
10381
|
var NODE_MEMORY_LIMIT_MB = 2048;
|
|
10513
10382
|
var activeServers = /* @__PURE__ */ new Map();
|
|
10514
10383
|
function getLogsDir() {
|
|
10515
|
-
const logsDir =
|
|
10384
|
+
const logsDir = path21.join((0, import_core12.getConfigDir)(), "logs");
|
|
10516
10385
|
if (!fs20.existsSync(logsDir)) {
|
|
10517
10386
|
fs20.mkdirSync(logsDir, { recursive: true });
|
|
10518
10387
|
}
|
|
10519
10388
|
return logsDir;
|
|
10520
10389
|
}
|
|
10521
10390
|
function getLogFilePath(moduleUid) {
|
|
10522
|
-
return
|
|
10391
|
+
return path21.join(getLogsDir(), `dev-${moduleUid}.log`);
|
|
10523
10392
|
}
|
|
10524
10393
|
function rotateLogIfNeeded(logPath) {
|
|
10525
10394
|
try {
|
|
@@ -10531,7 +10400,7 @@ function rotateLogIfNeeded(logPath) {
|
|
|
10531
10400
|
fs20.unlinkSync(backupPath);
|
|
10532
10401
|
}
|
|
10533
10402
|
fs20.renameSync(logPath, backupPath);
|
|
10534
|
-
console.log(`[DevServer] EP932: Rotated log file for ${
|
|
10403
|
+
console.log(`[DevServer] EP932: Rotated log file for ${path21.basename(logPath)}`);
|
|
10535
10404
|
}
|
|
10536
10405
|
}
|
|
10537
10406
|
} catch (error) {
|
|
@@ -10723,7 +10592,7 @@ async function startDevServer(projectPath, port = 3e3, moduleUid = "default", op
|
|
|
10723
10592
|
});
|
|
10724
10593
|
injectedEnvVars = result.envVars;
|
|
10725
10594
|
console.log(`[DevServer] EP998: Loaded ${Object.keys(injectedEnvVars).length} env vars (from ${result.fromCache ? "cache" : "server"})`);
|
|
10726
|
-
const envFilePath =
|
|
10595
|
+
const envFilePath = path21.join(projectPath, ".env");
|
|
10727
10596
|
if (!fs20.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
|
|
10728
10597
|
console.log(`[DevServer] EP1004: .env file missing, writing ${Object.keys(injectedEnvVars).length} vars to ${envFilePath}`);
|
|
10729
10598
|
writeEnvFile(projectPath, injectedEnvVars);
|
|
@@ -10830,7 +10699,7 @@ function getDevServerStatus() {
|
|
|
10830
10699
|
}
|
|
10831
10700
|
|
|
10832
10701
|
// src/utils/worktree.ts
|
|
10833
|
-
var
|
|
10702
|
+
var path22 = __toESM(require("path"));
|
|
10834
10703
|
var fs21 = __toESM(require("fs"));
|
|
10835
10704
|
var os8 = __toESM(require("os"));
|
|
10836
10705
|
var import_core13 = __toESM(require_dist());
|
|
@@ -10841,11 +10710,11 @@ function getEpisodaRoot2() {
|
|
|
10841
10710
|
if (process.env.EPISODA_MODE === "cloud") {
|
|
10842
10711
|
return process.env.HOME || "/home/episoda";
|
|
10843
10712
|
}
|
|
10844
|
-
return
|
|
10713
|
+
return path22.join(os8.homedir(), "episoda");
|
|
10845
10714
|
}
|
|
10846
10715
|
function getWorktreeInfo(moduleUid, workspaceSlug, projectSlug) {
|
|
10847
10716
|
const root = getEpisodaRoot2();
|
|
10848
|
-
const worktreePath =
|
|
10717
|
+
const worktreePath = path22.join(root, workspaceSlug, projectSlug, moduleUid);
|
|
10849
10718
|
return {
|
|
10850
10719
|
path: worktreePath,
|
|
10851
10720
|
exists: fs21.existsSync(worktreePath),
|
|
@@ -10862,14 +10731,14 @@ async function getWorktreeInfoForModule(moduleUid) {
|
|
|
10862
10731
|
return null;
|
|
10863
10732
|
}
|
|
10864
10733
|
const root = getEpisodaRoot2();
|
|
10865
|
-
const workspaceRoot =
|
|
10734
|
+
const workspaceRoot = path22.join(root, config.workspace_slug);
|
|
10866
10735
|
try {
|
|
10867
10736
|
const entries = fs21.readdirSync(workspaceRoot, { withFileTypes: true });
|
|
10868
10737
|
for (const entry of entries) {
|
|
10869
10738
|
if (!entry.isDirectory()) {
|
|
10870
10739
|
continue;
|
|
10871
10740
|
}
|
|
10872
|
-
const worktreePath =
|
|
10741
|
+
const worktreePath = path22.join(workspaceRoot, entry.name, moduleUid);
|
|
10873
10742
|
if (fs21.existsSync(worktreePath)) {
|
|
10874
10743
|
return {
|
|
10875
10744
|
path: worktreePath,
|
|
@@ -10888,59 +10757,59 @@ async function getWorktreeInfoForModule(moduleUid) {
|
|
|
10888
10757
|
|
|
10889
10758
|
// src/framework-detector.ts
|
|
10890
10759
|
var fs22 = __toESM(require("fs"));
|
|
10891
|
-
var
|
|
10760
|
+
var path23 = __toESM(require("path"));
|
|
10892
10761
|
function getInstallCommand2(cwd) {
|
|
10893
|
-
if (fs22.existsSync(
|
|
10762
|
+
if (fs22.existsSync(path23.join(cwd, "bun.lockb"))) {
|
|
10894
10763
|
return {
|
|
10895
10764
|
command: ["bun", "install"],
|
|
10896
10765
|
description: "Installing dependencies with bun",
|
|
10897
10766
|
detectedFrom: "bun.lockb"
|
|
10898
10767
|
};
|
|
10899
10768
|
}
|
|
10900
|
-
if (fs22.existsSync(
|
|
10769
|
+
if (fs22.existsSync(path23.join(cwd, "pnpm-lock.yaml"))) {
|
|
10901
10770
|
return {
|
|
10902
10771
|
command: ["pnpm", "install"],
|
|
10903
10772
|
description: "Installing dependencies with pnpm",
|
|
10904
10773
|
detectedFrom: "pnpm-lock.yaml"
|
|
10905
10774
|
};
|
|
10906
10775
|
}
|
|
10907
|
-
if (fs22.existsSync(
|
|
10776
|
+
if (fs22.existsSync(path23.join(cwd, "yarn.lock"))) {
|
|
10908
10777
|
return {
|
|
10909
10778
|
command: ["yarn", "install"],
|
|
10910
10779
|
description: "Installing dependencies with yarn",
|
|
10911
10780
|
detectedFrom: "yarn.lock"
|
|
10912
10781
|
};
|
|
10913
10782
|
}
|
|
10914
|
-
if (fs22.existsSync(
|
|
10783
|
+
if (fs22.existsSync(path23.join(cwd, "package-lock.json"))) {
|
|
10915
10784
|
return {
|
|
10916
10785
|
command: ["npm", "ci"],
|
|
10917
10786
|
description: "Installing dependencies with npm ci",
|
|
10918
10787
|
detectedFrom: "package-lock.json"
|
|
10919
10788
|
};
|
|
10920
10789
|
}
|
|
10921
|
-
if (fs22.existsSync(
|
|
10790
|
+
if (fs22.existsSync(path23.join(cwd, "package.json"))) {
|
|
10922
10791
|
return {
|
|
10923
10792
|
command: ["npm", "install"],
|
|
10924
10793
|
description: "Installing dependencies with npm",
|
|
10925
10794
|
detectedFrom: "package.json"
|
|
10926
10795
|
};
|
|
10927
10796
|
}
|
|
10928
|
-
if (fs22.existsSync(
|
|
10797
|
+
if (fs22.existsSync(path23.join(cwd, "Pipfile.lock")) || fs22.existsSync(path23.join(cwd, "Pipfile"))) {
|
|
10929
10798
|
return {
|
|
10930
10799
|
command: ["pipenv", "install"],
|
|
10931
10800
|
description: "Installing dependencies with pipenv",
|
|
10932
|
-
detectedFrom: fs22.existsSync(
|
|
10801
|
+
detectedFrom: fs22.existsSync(path23.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
|
|
10933
10802
|
};
|
|
10934
10803
|
}
|
|
10935
|
-
if (fs22.existsSync(
|
|
10804
|
+
if (fs22.existsSync(path23.join(cwd, "poetry.lock"))) {
|
|
10936
10805
|
return {
|
|
10937
10806
|
command: ["poetry", "install"],
|
|
10938
10807
|
description: "Installing dependencies with poetry",
|
|
10939
10808
|
detectedFrom: "poetry.lock"
|
|
10940
10809
|
};
|
|
10941
10810
|
}
|
|
10942
|
-
if (fs22.existsSync(
|
|
10943
|
-
const pyprojectPath =
|
|
10811
|
+
if (fs22.existsSync(path23.join(cwd, "pyproject.toml"))) {
|
|
10812
|
+
const pyprojectPath = path23.join(cwd, "pyproject.toml");
|
|
10944
10813
|
const content = fs22.readFileSync(pyprojectPath, "utf-8");
|
|
10945
10814
|
if (content.includes("[tool.poetry]")) {
|
|
10946
10815
|
return {
|
|
@@ -10950,42 +10819,43 @@ function getInstallCommand2(cwd) {
|
|
|
10950
10819
|
};
|
|
10951
10820
|
}
|
|
10952
10821
|
}
|
|
10953
|
-
if (fs22.existsSync(
|
|
10822
|
+
if (fs22.existsSync(path23.join(cwd, "requirements.txt"))) {
|
|
10954
10823
|
return {
|
|
10955
10824
|
command: ["pip", "install", "-r", "requirements.txt"],
|
|
10956
10825
|
description: "Installing dependencies with pip",
|
|
10957
10826
|
detectedFrom: "requirements.txt"
|
|
10958
10827
|
};
|
|
10959
10828
|
}
|
|
10960
|
-
if (fs22.existsSync(
|
|
10829
|
+
if (fs22.existsSync(path23.join(cwd, "Gemfile.lock")) || fs22.existsSync(path23.join(cwd, "Gemfile"))) {
|
|
10961
10830
|
return {
|
|
10962
10831
|
command: ["bundle", "install"],
|
|
10963
10832
|
description: "Installing dependencies with bundler",
|
|
10964
|
-
detectedFrom: fs22.existsSync(
|
|
10833
|
+
detectedFrom: fs22.existsSync(path23.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
|
|
10965
10834
|
};
|
|
10966
10835
|
}
|
|
10967
|
-
if (fs22.existsSync(
|
|
10836
|
+
if (fs22.existsSync(path23.join(cwd, "go.sum")) || fs22.existsSync(path23.join(cwd, "go.mod"))) {
|
|
10968
10837
|
return {
|
|
10969
10838
|
command: ["go", "mod", "download"],
|
|
10970
10839
|
description: "Downloading Go modules",
|
|
10971
|
-
detectedFrom: fs22.existsSync(
|
|
10840
|
+
detectedFrom: fs22.existsSync(path23.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
|
|
10972
10841
|
};
|
|
10973
10842
|
}
|
|
10974
|
-
if (fs22.existsSync(
|
|
10843
|
+
if (fs22.existsSync(path23.join(cwd, "Cargo.lock")) || fs22.existsSync(path23.join(cwd, "Cargo.toml"))) {
|
|
10975
10844
|
return {
|
|
10976
10845
|
command: ["cargo", "build"],
|
|
10977
10846
|
description: "Building Rust project (downloads dependencies)",
|
|
10978
|
-
detectedFrom: fs22.existsSync(
|
|
10847
|
+
detectedFrom: fs22.existsSync(path23.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
|
|
10979
10848
|
};
|
|
10980
10849
|
}
|
|
10981
10850
|
return null;
|
|
10982
10851
|
}
|
|
10983
10852
|
|
|
10984
10853
|
// src/daemon/daemon-process.ts
|
|
10854
|
+
var import_child_process14 = require("child_process");
|
|
10985
10855
|
var fs23 = __toESM(require("fs"));
|
|
10986
10856
|
var http2 = __toESM(require("http"));
|
|
10987
10857
|
var os9 = __toESM(require("os"));
|
|
10988
|
-
var
|
|
10858
|
+
var path24 = __toESM(require("path"));
|
|
10989
10859
|
var packageJson = require_package();
|
|
10990
10860
|
function getBuildPackagesCommand2(installCmd) {
|
|
10991
10861
|
const runner = installCmd?.command?.[0];
|
|
@@ -11153,6 +11023,9 @@ var Daemon = class _Daemon {
|
|
|
11153
11023
|
this.pendingUpdateVersion = null;
|
|
11154
11024
|
// Deferred update when sessions are active
|
|
11155
11025
|
this.updateInProgress = false;
|
|
11026
|
+
// EP1324: Retry limiting for failed update attempts
|
|
11027
|
+
this.lastFailedUpdateVersion = null;
|
|
11028
|
+
this.updateFailedAttempts = 0;
|
|
11156
11029
|
this.ipcServer = new IPCServer();
|
|
11157
11030
|
}
|
|
11158
11031
|
static {
|
|
@@ -11189,6 +11062,9 @@ var Daemon = class _Daemon {
|
|
|
11189
11062
|
static {
|
|
11190
11063
|
this.UPDATE_CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
11191
11064
|
}
|
|
11065
|
+
static {
|
|
11066
|
+
this.MAX_UPDATE_ATTEMPTS = 3;
|
|
11067
|
+
}
|
|
11192
11068
|
/**
|
|
11193
11069
|
* Start the daemon
|
|
11194
11070
|
*/
|
|
@@ -11264,27 +11140,74 @@ var Daemon = class _Daemon {
|
|
|
11264
11140
|
}
|
|
11265
11141
|
async applyUpdateIfIdle(targetVersion, source) {
|
|
11266
11142
|
if (this.updateInProgress) return;
|
|
11143
|
+
if (targetVersion === packageJson.version) {
|
|
11144
|
+
console.log(`[Daemon] EP1324: Already running version ${targetVersion}, skipping update`);
|
|
11145
|
+
return;
|
|
11146
|
+
}
|
|
11147
|
+
if (this.lastFailedUpdateVersion === targetVersion && this.updateFailedAttempts >= _Daemon.MAX_UPDATE_ATTEMPTS) {
|
|
11148
|
+
console.log(`[Daemon] EP1324: Skipping update to ${targetVersion} after ${this.updateFailedAttempts} failed attempts`);
|
|
11149
|
+
return;
|
|
11150
|
+
}
|
|
11267
11151
|
const activeAgentSessions = this.getActiveAgentSessionCount();
|
|
11268
11152
|
if (activeAgentSessions > 0) {
|
|
11269
11153
|
this.pendingUpdateVersion = targetVersion;
|
|
11270
11154
|
console.log(`[Daemon] EP1319: Update available (${packageJson.version} \u2192 ${targetVersion}) but ${activeAgentSessions} active agent session(s) \u2014 deferring`);
|
|
11271
11155
|
return;
|
|
11272
11156
|
}
|
|
11157
|
+
const currentInstalled = getInstalledVersion();
|
|
11158
|
+
if (currentInstalled && currentInstalled === targetVersion) {
|
|
11159
|
+
console.log(`[Daemon] EP1343: Already installed version ${targetVersion} (embedded: ${packageJson.version}), skipping update`);
|
|
11160
|
+
return;
|
|
11161
|
+
}
|
|
11273
11162
|
this.updateInProgress = true;
|
|
11274
11163
|
console.log(`[Daemon] EP1319: Applying CLI update (${source}) to ${targetVersion} (idle)`);
|
|
11275
11164
|
try {
|
|
11276
|
-
const
|
|
11277
|
-
if (!
|
|
11278
|
-
|
|
11279
|
-
|
|
11165
|
+
const installResult = performSyncUpdate(targetVersion);
|
|
11166
|
+
if (!installResult.success) {
|
|
11167
|
+
this.recordUpdateFailure(targetVersion, `Install failed: ${installResult.error}`);
|
|
11168
|
+
return;
|
|
11280
11169
|
}
|
|
11170
|
+
const installedVersion = getInstalledVersion();
|
|
11171
|
+
if (installedVersion !== targetVersion) {
|
|
11172
|
+
this.recordUpdateFailure(targetVersion, `Version mismatch: expected ${targetVersion}, got ${installedVersion || "unknown"}`);
|
|
11173
|
+
return;
|
|
11174
|
+
}
|
|
11175
|
+
console.log(`[Daemon] EP1324: Update to ${targetVersion} installed, restarting daemon...`);
|
|
11176
|
+
await this.shutdown();
|
|
11177
|
+
const { getConfigDir: getConfigDir8 } = require_dist();
|
|
11178
|
+
const configDir = getConfigDir8();
|
|
11179
|
+
const logPath = path24.join(configDir, "daemon.log");
|
|
11180
|
+
const logFd = fs23.openSync(logPath, "a");
|
|
11181
|
+
const child = (0, import_child_process14.spawn)("node", [__filename], {
|
|
11182
|
+
detached: true,
|
|
11183
|
+
stdio: ["ignore", logFd, logFd],
|
|
11184
|
+
env: { ...process.env, EPISODA_DAEMON_MODE: "1" }
|
|
11185
|
+
});
|
|
11186
|
+
child.unref();
|
|
11187
|
+
const pidPath = getPidFilePath();
|
|
11188
|
+
fs23.writeFileSync(pidPath, child.pid.toString(), "utf-8");
|
|
11189
|
+
console.log(`[Daemon] EP1324: New daemon spawned (PID: ${child.pid}), exiting old process`);
|
|
11190
|
+
process.exit(0);
|
|
11281
11191
|
} catch (error) {
|
|
11282
|
-
|
|
11283
|
-
this.pendingUpdateVersion = targetVersion;
|
|
11192
|
+
this.recordUpdateFailure(targetVersion, error instanceof Error ? error.message : String(error));
|
|
11284
11193
|
} finally {
|
|
11285
11194
|
this.updateInProgress = false;
|
|
11286
11195
|
}
|
|
11287
11196
|
}
|
|
11197
|
+
/**
|
|
11198
|
+
* EP1324: Record a failed update attempt and defer for retry.
|
|
11199
|
+
* After MAX_UPDATE_ATTEMPTS for the same version, further attempts are blocked.
|
|
11200
|
+
*/
|
|
11201
|
+
recordUpdateFailure(version, reason) {
|
|
11202
|
+
if (this.lastFailedUpdateVersion === version) {
|
|
11203
|
+
this.updateFailedAttempts++;
|
|
11204
|
+
} else {
|
|
11205
|
+
this.lastFailedUpdateVersion = version;
|
|
11206
|
+
this.updateFailedAttempts = 1;
|
|
11207
|
+
}
|
|
11208
|
+
this.pendingUpdateVersion = version;
|
|
11209
|
+
console.warn(`[Daemon] EP1324: Update to ${version} failed (attempt ${this.updateFailedAttempts}/${_Daemon.MAX_UPDATE_ATTEMPTS}): ${reason}`);
|
|
11210
|
+
}
|
|
11288
11211
|
/**
|
|
11289
11212
|
* EP1319: Periodic update check for long-lived containers
|
|
11290
11213
|
* Checks npm registry for newer version. If found:
|
|
@@ -11323,9 +11246,9 @@ var Daemon = class _Daemon {
|
|
|
11323
11246
|
this.healthServer = http2.createServer((req, res) => {
|
|
11324
11247
|
if (req.url === "/health" || req.url === "/") {
|
|
11325
11248
|
const isConnected = this.liveConnections.size > 0;
|
|
11326
|
-
const projects = Array.from(this.connections.entries()).map(([
|
|
11327
|
-
path:
|
|
11328
|
-
connected: this.liveConnections.has(
|
|
11249
|
+
const projects = Array.from(this.connections.entries()).map(([path25, conn]) => ({
|
|
11250
|
+
path: path25,
|
|
11251
|
+
connected: this.liveConnections.has(path25)
|
|
11329
11252
|
}));
|
|
11330
11253
|
const status = {
|
|
11331
11254
|
status: isConnected ? "healthy" : "degraded",
|
|
@@ -11753,7 +11676,7 @@ var Daemon = class _Daemon {
|
|
|
11753
11676
|
client.updateActivity();
|
|
11754
11677
|
try {
|
|
11755
11678
|
const gitCmd = message.command;
|
|
11756
|
-
const bareRepoPath =
|
|
11679
|
+
const bareRepoPath = path24.join(projectPath, ".bare");
|
|
11757
11680
|
const cwd = gitCmd.worktreePath || bareRepoPath;
|
|
11758
11681
|
if (gitCmd.worktreePath) {
|
|
11759
11682
|
console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
|
|
@@ -12533,8 +12456,8 @@ var Daemon = class _Daemon {
|
|
|
12533
12456
|
* - workDir: The directory to run git commands in (cwd)
|
|
12534
12457
|
*/
|
|
12535
12458
|
getGitDirs(projectPath) {
|
|
12536
|
-
const bareDir =
|
|
12537
|
-
const gitPath =
|
|
12459
|
+
const bareDir = path24.join(projectPath, ".bare");
|
|
12460
|
+
const gitPath = path24.join(projectPath, ".git");
|
|
12538
12461
|
if (fs23.existsSync(bareDir) && fs23.statSync(bareDir).isDirectory()) {
|
|
12539
12462
|
return { gitDir: bareDir, workDir: projectPath };
|
|
12540
12463
|
}
|
|
@@ -12547,8 +12470,8 @@ var Daemon = class _Daemon {
|
|
|
12547
12470
|
const entries = fs23.readdirSync(projectPath, { withFileTypes: true });
|
|
12548
12471
|
for (const entry of entries) {
|
|
12549
12472
|
if (entry.isDirectory() && entry.name.startsWith("EP")) {
|
|
12550
|
-
const worktreePath =
|
|
12551
|
-
const worktreeGit =
|
|
12473
|
+
const worktreePath = path24.join(projectPath, entry.name);
|
|
12474
|
+
const worktreeGit = path24.join(worktreePath, ".git");
|
|
12552
12475
|
if (fs23.existsSync(worktreeGit)) {
|
|
12553
12476
|
return { gitDir: null, workDir: worktreePath };
|
|
12554
12477
|
}
|
|
@@ -12618,14 +12541,14 @@ var Daemon = class _Daemon {
|
|
|
12618
12541
|
async installGitHooks(projectPath) {
|
|
12619
12542
|
const hooks = ["post-checkout", "pre-commit", "post-commit"];
|
|
12620
12543
|
let hooksDir;
|
|
12621
|
-
const bareHooksDir =
|
|
12622
|
-
const gitHooksDir =
|
|
12544
|
+
const bareHooksDir = path24.join(projectPath, ".bare", "hooks");
|
|
12545
|
+
const gitHooksDir = path24.join(projectPath, ".git", "hooks");
|
|
12623
12546
|
if (fs23.existsSync(bareHooksDir)) {
|
|
12624
12547
|
hooksDir = bareHooksDir;
|
|
12625
|
-
} else if (fs23.existsSync(gitHooksDir) && fs23.statSync(
|
|
12548
|
+
} else if (fs23.existsSync(gitHooksDir) && fs23.statSync(path24.join(projectPath, ".git")).isDirectory()) {
|
|
12626
12549
|
hooksDir = gitHooksDir;
|
|
12627
12550
|
} else {
|
|
12628
|
-
const parentBareHooks =
|
|
12551
|
+
const parentBareHooks = path24.join(projectPath, "..", ".bare", "hooks");
|
|
12629
12552
|
if (fs23.existsSync(parentBareHooks)) {
|
|
12630
12553
|
hooksDir = parentBareHooks;
|
|
12631
12554
|
} else {
|
|
@@ -12643,8 +12566,8 @@ var Daemon = class _Daemon {
|
|
|
12643
12566
|
}
|
|
12644
12567
|
for (const hookName of hooks) {
|
|
12645
12568
|
try {
|
|
12646
|
-
const hookPath =
|
|
12647
|
-
const bundledHookPath =
|
|
12569
|
+
const hookPath = path24.join(hooksDir, hookName);
|
|
12570
|
+
const bundledHookPath = path24.join(__dirname, "..", "hooks", hookName);
|
|
12648
12571
|
if (!fs23.existsSync(bundledHookPath)) {
|
|
12649
12572
|
console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
|
|
12650
12573
|
continue;
|