episoda 0.2.105 → 0.2.107
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 +436 -194
- package/dist/daemon/daemon-process.js.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1571,15 +1571,15 @@ var require_git_executor = __commonJS({
|
|
|
1571
1571
|
try {
|
|
1572
1572
|
const { stdout: gitDir } = await execAsync3("git rev-parse --git-dir", { cwd, timeout: 5e3 });
|
|
1573
1573
|
const gitDirPath = gitDir.trim();
|
|
1574
|
-
const
|
|
1574
|
+
const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1575
1575
|
const rebaseMergePath = `${gitDirPath}/rebase-merge`;
|
|
1576
1576
|
const rebaseApplyPath = `${gitDirPath}/rebase-apply`;
|
|
1577
1577
|
try {
|
|
1578
|
-
await
|
|
1578
|
+
await fs24.access(rebaseMergePath);
|
|
1579
1579
|
inRebase = true;
|
|
1580
1580
|
} catch {
|
|
1581
1581
|
try {
|
|
1582
|
-
await
|
|
1582
|
+
await fs24.access(rebaseApplyPath);
|
|
1583
1583
|
inRebase = true;
|
|
1584
1584
|
} catch {
|
|
1585
1585
|
inRebase = false;
|
|
@@ -1633,9 +1633,9 @@ var require_git_executor = __commonJS({
|
|
|
1633
1633
|
error: validation.error || "UNKNOWN_ERROR"
|
|
1634
1634
|
};
|
|
1635
1635
|
}
|
|
1636
|
-
const
|
|
1636
|
+
const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1637
1637
|
try {
|
|
1638
|
-
await
|
|
1638
|
+
await fs24.access(command.path);
|
|
1639
1639
|
return {
|
|
1640
1640
|
success: false,
|
|
1641
1641
|
error: "WORKTREE_EXISTS",
|
|
@@ -1689,9 +1689,9 @@ var require_git_executor = __commonJS({
|
|
|
1689
1689
|
*/
|
|
1690
1690
|
async executeWorktreeRemove(command, cwd, options) {
|
|
1691
1691
|
try {
|
|
1692
|
-
const
|
|
1692
|
+
const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1693
1693
|
try {
|
|
1694
|
-
await
|
|
1694
|
+
await fs24.access(command.path);
|
|
1695
1695
|
} catch {
|
|
1696
1696
|
return {
|
|
1697
1697
|
success: false,
|
|
@@ -1726,7 +1726,7 @@ var require_git_executor = __commonJS({
|
|
|
1726
1726
|
const result = await this.runGitCommand(args, cwd, options);
|
|
1727
1727
|
if (result.success) {
|
|
1728
1728
|
try {
|
|
1729
|
-
await
|
|
1729
|
+
await fs24.rm(command.path, { recursive: true, force: true });
|
|
1730
1730
|
} catch {
|
|
1731
1731
|
}
|
|
1732
1732
|
return {
|
|
@@ -1860,10 +1860,10 @@ var require_git_executor = __commonJS({
|
|
|
1860
1860
|
*/
|
|
1861
1861
|
async executeCloneBare(command, options) {
|
|
1862
1862
|
try {
|
|
1863
|
-
const
|
|
1864
|
-
const
|
|
1863
|
+
const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1864
|
+
const path25 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
1865
1865
|
try {
|
|
1866
|
-
await
|
|
1866
|
+
await fs24.access(command.path);
|
|
1867
1867
|
return {
|
|
1868
1868
|
success: false,
|
|
1869
1869
|
error: "BRANCH_ALREADY_EXISTS",
|
|
@@ -1872,9 +1872,9 @@ var require_git_executor = __commonJS({
|
|
|
1872
1872
|
};
|
|
1873
1873
|
} catch {
|
|
1874
1874
|
}
|
|
1875
|
-
const parentDir =
|
|
1875
|
+
const parentDir = path25.dirname(command.path);
|
|
1876
1876
|
try {
|
|
1877
|
-
await
|
|
1877
|
+
await fs24.mkdir(parentDir, { recursive: true });
|
|
1878
1878
|
} catch {
|
|
1879
1879
|
}
|
|
1880
1880
|
const { stdout, stderr } = await execAsync3(
|
|
@@ -1922,22 +1922,22 @@ var require_git_executor = __commonJS({
|
|
|
1922
1922
|
*/
|
|
1923
1923
|
async executeProjectInfo(cwd, options) {
|
|
1924
1924
|
try {
|
|
1925
|
-
const
|
|
1926
|
-
const
|
|
1925
|
+
const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1926
|
+
const path25 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
1927
1927
|
let currentPath = cwd;
|
|
1928
1928
|
let projectPath = cwd;
|
|
1929
1929
|
let bareRepoPath;
|
|
1930
1930
|
for (let i = 0; i < 10; i++) {
|
|
1931
|
-
const bareDir =
|
|
1932
|
-
const episodaDir =
|
|
1931
|
+
const bareDir = path25.join(currentPath, ".bare");
|
|
1932
|
+
const episodaDir = path25.join(currentPath, ".episoda");
|
|
1933
1933
|
try {
|
|
1934
|
-
await
|
|
1935
|
-
await
|
|
1934
|
+
await fs24.access(bareDir);
|
|
1935
|
+
await fs24.access(episodaDir);
|
|
1936
1936
|
projectPath = currentPath;
|
|
1937
1937
|
bareRepoPath = bareDir;
|
|
1938
1938
|
break;
|
|
1939
1939
|
} catch {
|
|
1940
|
-
const parentPath =
|
|
1940
|
+
const parentPath = path25.dirname(currentPath);
|
|
1941
1941
|
if (parentPath === currentPath) {
|
|
1942
1942
|
break;
|
|
1943
1943
|
}
|
|
@@ -2590,31 +2590,31 @@ var require_auth = __commonJS({
|
|
|
2590
2590
|
exports2.loadConfig = loadConfig8;
|
|
2591
2591
|
exports2.saveConfig = saveConfig2;
|
|
2592
2592
|
exports2.validateToken = validateToken;
|
|
2593
|
-
var
|
|
2594
|
-
var
|
|
2593
|
+
var fs24 = __importStar(require("fs"));
|
|
2594
|
+
var path25 = __importStar(require("path"));
|
|
2595
2595
|
var os9 = __importStar(require("os"));
|
|
2596
2596
|
var child_process_1 = require("child_process");
|
|
2597
2597
|
var DEFAULT_CONFIG_FILE = "config.json";
|
|
2598
2598
|
function getConfigDir8() {
|
|
2599
|
-
return process.env.EPISODA_CONFIG_DIR ||
|
|
2599
|
+
return process.env.EPISODA_CONFIG_DIR || path25.join(os9.homedir(), ".episoda");
|
|
2600
2600
|
}
|
|
2601
2601
|
function getConfigPath(configPath) {
|
|
2602
2602
|
if (configPath) {
|
|
2603
2603
|
return configPath;
|
|
2604
2604
|
}
|
|
2605
|
-
return
|
|
2605
|
+
return path25.join(getConfigDir8(), DEFAULT_CONFIG_FILE);
|
|
2606
2606
|
}
|
|
2607
2607
|
function ensureConfigDir(configPath) {
|
|
2608
|
-
const dir =
|
|
2609
|
-
const isNew = !
|
|
2608
|
+
const dir = path25.dirname(configPath);
|
|
2609
|
+
const isNew = !fs24.existsSync(dir);
|
|
2610
2610
|
if (isNew) {
|
|
2611
|
-
|
|
2611
|
+
fs24.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2612
2612
|
}
|
|
2613
2613
|
if (process.platform === "darwin") {
|
|
2614
|
-
const nosyncPath =
|
|
2615
|
-
if (isNew || !
|
|
2614
|
+
const nosyncPath = path25.join(dir, ".nosync");
|
|
2615
|
+
if (isNew || !fs24.existsSync(nosyncPath)) {
|
|
2616
2616
|
try {
|
|
2617
|
-
|
|
2617
|
+
fs24.writeFileSync(nosyncPath, "", { mode: 384 });
|
|
2618
2618
|
(0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
|
|
2619
2619
|
stdio: "ignore",
|
|
2620
2620
|
timeout: 5e3
|
|
@@ -2626,9 +2626,9 @@ var require_auth = __commonJS({
|
|
|
2626
2626
|
}
|
|
2627
2627
|
async function loadConfig8(configPath) {
|
|
2628
2628
|
const fullPath = getConfigPath(configPath);
|
|
2629
|
-
if (
|
|
2629
|
+
if (fs24.existsSync(fullPath)) {
|
|
2630
2630
|
try {
|
|
2631
|
-
const content =
|
|
2631
|
+
const content = fs24.readFileSync(fullPath, "utf8");
|
|
2632
2632
|
const config = JSON.parse(content);
|
|
2633
2633
|
return config;
|
|
2634
2634
|
} catch (error) {
|
|
@@ -2638,9 +2638,9 @@ var require_auth = __commonJS({
|
|
|
2638
2638
|
if (process.env.EPISODA_MODE === "cloud" && process.env.EPISODA_WORKSPACE) {
|
|
2639
2639
|
const homeDir = process.env.HOME || require("os").homedir();
|
|
2640
2640
|
const workspaceConfigPath = require("path").join(homeDir, "episoda", process.env.EPISODA_WORKSPACE, ".episoda", "config.json");
|
|
2641
|
-
if (
|
|
2641
|
+
if (fs24.existsSync(workspaceConfigPath)) {
|
|
2642
2642
|
try {
|
|
2643
|
-
const content =
|
|
2643
|
+
const content = fs24.readFileSync(workspaceConfigPath, "utf8");
|
|
2644
2644
|
const workspaceConfig = JSON.parse(content);
|
|
2645
2645
|
return {
|
|
2646
2646
|
access_token: process.env.EPISODA_ACCESS_TOKEN || workspaceConfig.accessToken,
|
|
@@ -2687,7 +2687,7 @@ var require_auth = __commonJS({
|
|
|
2687
2687
|
ensureConfigDir(fullPath);
|
|
2688
2688
|
try {
|
|
2689
2689
|
const content = JSON.stringify(config, null, 2);
|
|
2690
|
-
|
|
2690
|
+
fs24.writeFileSync(fullPath, content, { mode: 384 });
|
|
2691
2691
|
} catch (error) {
|
|
2692
2692
|
throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
|
|
2693
2693
|
}
|
|
@@ -2804,7 +2804,7 @@ var require_package = __commonJS({
|
|
|
2804
2804
|
"package.json"(exports2, module2) {
|
|
2805
2805
|
module2.exports = {
|
|
2806
2806
|
name: "episoda",
|
|
2807
|
-
version: "0.2.
|
|
2807
|
+
version: "0.2.106",
|
|
2808
2808
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2809
2809
|
main: "dist/index.js",
|
|
2810
2810
|
types: "dist/index.d.ts",
|
|
@@ -2843,7 +2843,7 @@ var require_package = __commonJS({
|
|
|
2843
2843
|
"@modelcontextprotocol/server-github": "^0.6.0"
|
|
2844
2844
|
},
|
|
2845
2845
|
devDependencies: {
|
|
2846
|
-
"@episoda/core": "
|
|
2846
|
+
"@episoda/core": "workspace:*",
|
|
2847
2847
|
"@types/node": "^20.11.24",
|
|
2848
2848
|
"@types/semver": "7.7.1",
|
|
2849
2849
|
"@types/tar": "6.1.13",
|
|
@@ -4058,8 +4058,8 @@ async function handleExec(command, projectPath) {
|
|
|
4058
4058
|
}
|
|
4059
4059
|
|
|
4060
4060
|
// src/daemon/handlers/worktree-handlers.ts
|
|
4061
|
-
var
|
|
4062
|
-
var
|
|
4061
|
+
var path16 = __toESM(require("path"));
|
|
4062
|
+
var fs15 = __toESM(require("fs"));
|
|
4063
4063
|
var import_child_process8 = require("child_process");
|
|
4064
4064
|
var import_util = require("util");
|
|
4065
4065
|
|
|
@@ -4781,7 +4781,13 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
4781
4781
|
}
|
|
4782
4782
|
};
|
|
4783
4783
|
function getEpisodaRoot() {
|
|
4784
|
-
|
|
4784
|
+
if (process.env.EPISODA_ROOT) {
|
|
4785
|
+
return process.env.EPISODA_ROOT;
|
|
4786
|
+
}
|
|
4787
|
+
if (process.env.EPISODA_MODE === "cloud") {
|
|
4788
|
+
return process.env.HOME || "/home/episoda";
|
|
4789
|
+
}
|
|
4790
|
+
return path7.join(require("os").homedir(), "episoda");
|
|
4785
4791
|
}
|
|
4786
4792
|
function getProjectPath(workspaceSlug, projectSlug) {
|
|
4787
4793
|
return path7.join(getEpisodaRoot(), workspaceSlug, projectSlug);
|
|
@@ -7326,6 +7332,144 @@ async function deleteWorktree(config, moduleUid) {
|
|
|
7326
7332
|
}
|
|
7327
7333
|
}
|
|
7328
7334
|
|
|
7335
|
+
// src/daemon/package-manager.ts
|
|
7336
|
+
var fs14 = __toESM(require("fs"));
|
|
7337
|
+
var path15 = __toESM(require("path"));
|
|
7338
|
+
var PACKAGE_MANAGERS = {
|
|
7339
|
+
javascript: [
|
|
7340
|
+
{
|
|
7341
|
+
name: "pnpm",
|
|
7342
|
+
detector: (p) => {
|
|
7343
|
+
if (fs14.existsSync(path15.join(p, "pnpm-lock.yaml"))) {
|
|
7344
|
+
return "pnpm-lock.yaml";
|
|
7345
|
+
}
|
|
7346
|
+
const pkgJsonPath = path15.join(p, "package.json");
|
|
7347
|
+
if (fs14.existsSync(pkgJsonPath)) {
|
|
7348
|
+
try {
|
|
7349
|
+
const pkg = JSON.parse(fs14.readFileSync(pkgJsonPath, "utf-8"));
|
|
7350
|
+
if (pkg.packageManager?.startsWith("pnpm")) {
|
|
7351
|
+
return "package.json (packageManager field)";
|
|
7352
|
+
}
|
|
7353
|
+
} catch {
|
|
7354
|
+
}
|
|
7355
|
+
}
|
|
7356
|
+
return null;
|
|
7357
|
+
},
|
|
7358
|
+
config: {
|
|
7359
|
+
installCmd: "pnpm install --frozen-lockfile",
|
|
7360
|
+
cacheEnvVar: "PNPM_HOME"
|
|
7361
|
+
}
|
|
7362
|
+
},
|
|
7363
|
+
{
|
|
7364
|
+
name: "yarn",
|
|
7365
|
+
detector: (p) => fs14.existsSync(path15.join(p, "yarn.lock")) ? "yarn.lock" : null,
|
|
7366
|
+
config: {
|
|
7367
|
+
installCmd: "yarn install --frozen-lockfile",
|
|
7368
|
+
cacheEnvVar: "YARN_CACHE_FOLDER"
|
|
7369
|
+
}
|
|
7370
|
+
},
|
|
7371
|
+
{
|
|
7372
|
+
name: "bun",
|
|
7373
|
+
detector: (p) => fs14.existsSync(path15.join(p, "bun.lockb")) ? "bun.lockb" : null,
|
|
7374
|
+
config: {
|
|
7375
|
+
installCmd: "bun install --frozen-lockfile"
|
|
7376
|
+
}
|
|
7377
|
+
},
|
|
7378
|
+
{
|
|
7379
|
+
name: "npm",
|
|
7380
|
+
detector: (p) => fs14.existsSync(path15.join(p, "package-lock.json")) ? "package-lock.json" : null,
|
|
7381
|
+
config: {
|
|
7382
|
+
installCmd: "npm ci"
|
|
7383
|
+
}
|
|
7384
|
+
},
|
|
7385
|
+
{
|
|
7386
|
+
// EP1222: Default to pnpm for new projects without lockfile
|
|
7387
|
+
// This encourages standardization on pnpm across Episoda projects
|
|
7388
|
+
name: "pnpm",
|
|
7389
|
+
detector: (p) => fs14.existsSync(path15.join(p, "package.json")) ? "package.json (no lockfile - defaulting to pnpm)" : null,
|
|
7390
|
+
config: {
|
|
7391
|
+
installCmd: "pnpm install",
|
|
7392
|
+
cacheEnvVar: "PNPM_HOME"
|
|
7393
|
+
}
|
|
7394
|
+
}
|
|
7395
|
+
],
|
|
7396
|
+
python: [
|
|
7397
|
+
{
|
|
7398
|
+
name: "uv",
|
|
7399
|
+
detector: (p) => {
|
|
7400
|
+
const pyprojectPath = path15.join(p, "pyproject.toml");
|
|
7401
|
+
if (fs14.existsSync(path15.join(p, "uv.lock"))) {
|
|
7402
|
+
return "uv.lock";
|
|
7403
|
+
}
|
|
7404
|
+
if (fs14.existsSync(pyprojectPath)) {
|
|
7405
|
+
try {
|
|
7406
|
+
const content = fs14.readFileSync(pyprojectPath, "utf-8");
|
|
7407
|
+
if (content.includes("[tool.uv]") || content.includes("[project]")) {
|
|
7408
|
+
return "pyproject.toml";
|
|
7409
|
+
}
|
|
7410
|
+
} catch {
|
|
7411
|
+
}
|
|
7412
|
+
}
|
|
7413
|
+
return null;
|
|
7414
|
+
},
|
|
7415
|
+
config: {
|
|
7416
|
+
installCmd: "uv sync",
|
|
7417
|
+
cacheEnvVar: "UV_CACHE_DIR"
|
|
7418
|
+
}
|
|
7419
|
+
},
|
|
7420
|
+
{
|
|
7421
|
+
name: "pip",
|
|
7422
|
+
detector: (p) => fs14.existsSync(path15.join(p, "requirements.txt")) ? "requirements.txt" : null,
|
|
7423
|
+
config: {
|
|
7424
|
+
installCmd: "pip install -r requirements.txt"
|
|
7425
|
+
}
|
|
7426
|
+
}
|
|
7427
|
+
]
|
|
7428
|
+
// Future: Add more languages here
|
|
7429
|
+
// rust: [
|
|
7430
|
+
// {
|
|
7431
|
+
// name: 'cargo',
|
|
7432
|
+
// detector: (p) => fs.existsSync(path.join(p, 'Cargo.toml')) ? 'Cargo.toml' : null,
|
|
7433
|
+
// config: { installCmd: 'cargo build' }
|
|
7434
|
+
// }
|
|
7435
|
+
// ],
|
|
7436
|
+
// go: [
|
|
7437
|
+
// {
|
|
7438
|
+
// name: 'go',
|
|
7439
|
+
// detector: (p) => fs.existsSync(path.join(p, 'go.mod')) ? 'go.mod' : null,
|
|
7440
|
+
// config: { installCmd: 'go mod download' }
|
|
7441
|
+
// }
|
|
7442
|
+
// ],
|
|
7443
|
+
};
|
|
7444
|
+
function detectPackageManager(worktreePath, preferredLanguages) {
|
|
7445
|
+
const checkedFiles = [];
|
|
7446
|
+
const languages = preferredLanguages || Object.keys(PACKAGE_MANAGERS);
|
|
7447
|
+
for (const language of languages) {
|
|
7448
|
+
const managers = PACKAGE_MANAGERS[language];
|
|
7449
|
+
if (!managers) continue;
|
|
7450
|
+
for (const { name, detector, config } of managers) {
|
|
7451
|
+
const matchedFile = detector(worktreePath);
|
|
7452
|
+
if (matchedFile) {
|
|
7453
|
+
checkedFiles.push(matchedFile);
|
|
7454
|
+
return {
|
|
7455
|
+
detected: true,
|
|
7456
|
+
packageManager: {
|
|
7457
|
+
name,
|
|
7458
|
+
language,
|
|
7459
|
+
...config
|
|
7460
|
+
},
|
|
7461
|
+
checkedFiles,
|
|
7462
|
+
matchedFile
|
|
7463
|
+
};
|
|
7464
|
+
}
|
|
7465
|
+
}
|
|
7466
|
+
}
|
|
7467
|
+
return {
|
|
7468
|
+
detected: false,
|
|
7469
|
+
checkedFiles
|
|
7470
|
+
};
|
|
7471
|
+
}
|
|
7472
|
+
|
|
7329
7473
|
// src/daemon/handlers/worktree-handlers.ts
|
|
7330
7474
|
async function getConfigForApi() {
|
|
7331
7475
|
if (process.env.EPISODA_MODE === "cloud" && process.env.EPISODA_ACCESS_TOKEN) {
|
|
@@ -7344,6 +7488,16 @@ async function getConfigForApi() {
|
|
|
7344
7488
|
return (0, import_core9.loadConfig)();
|
|
7345
7489
|
}
|
|
7346
7490
|
var execAsync = (0, import_util.promisify)(import_child_process8.exec);
|
|
7491
|
+
async function autoDetectSetupScript(worktreePath) {
|
|
7492
|
+
const detection = detectPackageManager(worktreePath);
|
|
7493
|
+
if (!detection.detected || !detection.packageManager) {
|
|
7494
|
+
console.log(`[Worktree] EP1222: No package manager detected in ${worktreePath}`);
|
|
7495
|
+
return null;
|
|
7496
|
+
}
|
|
7497
|
+
const { name, language, installCmd } = detection.packageManager;
|
|
7498
|
+
console.log(`[Worktree] EP1222: Detected ${name} (${language}) via ${detection.matchedFile}`);
|
|
7499
|
+
return installCmd;
|
|
7500
|
+
}
|
|
7347
7501
|
async function handleWorktreeCreate(request2) {
|
|
7348
7502
|
const {
|
|
7349
7503
|
workspaceSlug,
|
|
@@ -7368,18 +7522,18 @@ async function handleWorktreeCreate(request2) {
|
|
|
7368
7522
|
}
|
|
7369
7523
|
try {
|
|
7370
7524
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
7371
|
-
const bareRepoPath =
|
|
7372
|
-
if (!
|
|
7525
|
+
const bareRepoPath = path16.join(projectPath, ".bare");
|
|
7526
|
+
if (!fs15.existsSync(bareRepoPath)) {
|
|
7373
7527
|
console.log(`[Worktree] K1273: Project not found, cloning lazily...`);
|
|
7374
7528
|
console.log(`[Worktree] Repo URL: ${repoUrl.replace(/\/\/[^@]*@/, "//***@")}`);
|
|
7375
|
-
const episodaDir =
|
|
7376
|
-
|
|
7529
|
+
const episodaDir = path16.join(projectPath, ".episoda");
|
|
7530
|
+
fs15.mkdirSync(episodaDir, { recursive: true });
|
|
7377
7531
|
try {
|
|
7378
7532
|
console.log(`[Worktree] K1273: Starting git clone...`);
|
|
7379
7533
|
await execAsync(`git clone --bare "${repoUrl}" "${bareRepoPath}"`);
|
|
7380
7534
|
console.log(`[Worktree] K1273: Clone successful`);
|
|
7381
7535
|
await execAsync(`git -C "${bareRepoPath}" config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"`);
|
|
7382
|
-
const configPath =
|
|
7536
|
+
const configPath = path16.join(episodaDir, "config.json");
|
|
7383
7537
|
const config2 = {
|
|
7384
7538
|
projectId,
|
|
7385
7539
|
workspaceSlug,
|
|
@@ -7388,7 +7542,7 @@ async function handleWorktreeCreate(request2) {
|
|
|
7388
7542
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7389
7543
|
worktrees: []
|
|
7390
7544
|
};
|
|
7391
|
-
|
|
7545
|
+
fs15.writeFileSync(configPath, JSON.stringify(config2, null, 2), "utf-8");
|
|
7392
7546
|
console.log(`[Worktree] K1273: Project initialized at ${projectPath}`);
|
|
7393
7547
|
} catch (cloneError) {
|
|
7394
7548
|
console.error(`[Worktree] K1273: Git clone failed: ${cloneError.message}`);
|
|
@@ -7436,11 +7590,12 @@ async function handleWorktreeCreate(request2) {
|
|
|
7436
7590
|
}
|
|
7437
7591
|
if (envVars && Object.keys(envVars).length > 0) {
|
|
7438
7592
|
const envContent = Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n");
|
|
7439
|
-
const envPath =
|
|
7440
|
-
|
|
7593
|
+
const envPath = path16.join(worktreePath, ".env");
|
|
7594
|
+
fs15.writeFileSync(envPath, envContent + "\n", "utf-8");
|
|
7441
7595
|
console.log(`[Worktree] EP1143: Wrote ${Object.keys(envVars).length} env vars to .env`);
|
|
7442
7596
|
}
|
|
7443
|
-
|
|
7597
|
+
const effectiveSetupScript = setupScript || await autoDetectSetupScript(worktreePath);
|
|
7598
|
+
if (effectiveSetupScript) {
|
|
7444
7599
|
await manager.updateWorktreeStatus(moduleUid, "setup");
|
|
7445
7600
|
if (config?.access_token) {
|
|
7446
7601
|
await updateWorktree(config, {
|
|
@@ -7452,7 +7607,7 @@ async function handleWorktreeCreate(request2) {
|
|
|
7452
7607
|
});
|
|
7453
7608
|
}
|
|
7454
7609
|
console.log(`[Worktree] EP1143: Running setup script...`);
|
|
7455
|
-
const scriptResult = await manager.runSetupScript(moduleUid,
|
|
7610
|
+
const scriptResult = await manager.runSetupScript(moduleUid, effectiveSetupScript);
|
|
7456
7611
|
if (!scriptResult.success) {
|
|
7457
7612
|
console.error(`[Worktree] EP1143: Setup script failed: ${scriptResult.error}`);
|
|
7458
7613
|
await manager.updateWorktreeStatus(moduleUid, "error", scriptResult.error);
|
|
@@ -7610,12 +7765,12 @@ async function handleProjectEject(request2) {
|
|
|
7610
7765
|
console.log(`[Worktree] EP1144: Ejecting project ${projectSlug} from workspace ${workspaceSlug}`);
|
|
7611
7766
|
try {
|
|
7612
7767
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
7613
|
-
const bareRepoPath =
|
|
7614
|
-
if (!
|
|
7768
|
+
const bareRepoPath = path16.join(projectPath, ".bare");
|
|
7769
|
+
if (!fs15.existsSync(projectPath)) {
|
|
7615
7770
|
console.log(`[Worktree] EP1144: Project path not found, nothing to eject: ${projectPath}`);
|
|
7616
7771
|
return { success: true };
|
|
7617
7772
|
}
|
|
7618
|
-
if (!
|
|
7773
|
+
if (!fs15.existsSync(bareRepoPath)) {
|
|
7619
7774
|
console.log(`[Worktree] EP1144: Bare repo not found, nothing to eject: ${bareRepoPath}`);
|
|
7620
7775
|
return { success: true };
|
|
7621
7776
|
}
|
|
@@ -7630,12 +7785,12 @@ async function handleProjectEject(request2) {
|
|
|
7630
7785
|
};
|
|
7631
7786
|
}
|
|
7632
7787
|
}
|
|
7633
|
-
const artifactsPath =
|
|
7634
|
-
if (
|
|
7788
|
+
const artifactsPath = path16.join(projectPath, "artifacts");
|
|
7789
|
+
if (fs15.existsSync(artifactsPath)) {
|
|
7635
7790
|
await persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug);
|
|
7636
7791
|
}
|
|
7637
7792
|
console.log(`[Worktree] EP1144: Removing project directory: ${projectPath}`);
|
|
7638
|
-
await
|
|
7793
|
+
await fs15.promises.rm(projectPath, { recursive: true, force: true });
|
|
7639
7794
|
console.log(`[Worktree] EP1144: Successfully ejected project ${projectSlug}`);
|
|
7640
7795
|
return { success: true };
|
|
7641
7796
|
} catch (error) {
|
|
@@ -7649,7 +7804,7 @@ async function handleProjectEject(request2) {
|
|
|
7649
7804
|
async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug) {
|
|
7650
7805
|
const MAX_ARTIFACT_SIZE = 10 * 1024 * 1024;
|
|
7651
7806
|
try {
|
|
7652
|
-
const files = await
|
|
7807
|
+
const files = await fs15.promises.readdir(artifactsPath);
|
|
7653
7808
|
if (files.length === 0) {
|
|
7654
7809
|
return;
|
|
7655
7810
|
}
|
|
@@ -7663,8 +7818,8 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
7663
7818
|
}
|
|
7664
7819
|
const artifacts = [];
|
|
7665
7820
|
for (const fileName of files) {
|
|
7666
|
-
const filePath =
|
|
7667
|
-
const stat = await
|
|
7821
|
+
const filePath = path16.join(artifactsPath, fileName);
|
|
7822
|
+
const stat = await fs15.promises.stat(filePath);
|
|
7668
7823
|
if (stat.isDirectory()) {
|
|
7669
7824
|
continue;
|
|
7670
7825
|
}
|
|
@@ -7673,9 +7828,9 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
7673
7828
|
continue;
|
|
7674
7829
|
}
|
|
7675
7830
|
try {
|
|
7676
|
-
const content = await
|
|
7831
|
+
const content = await fs15.promises.readFile(filePath);
|
|
7677
7832
|
const base64Content = content.toString("base64");
|
|
7678
|
-
const ext =
|
|
7833
|
+
const ext = path16.extname(fileName).toLowerCase();
|
|
7679
7834
|
const mimeTypes = {
|
|
7680
7835
|
".json": "application/json",
|
|
7681
7836
|
".txt": "text/plain",
|
|
@@ -7730,6 +7885,85 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
7730
7885
|
}
|
|
7731
7886
|
}
|
|
7732
7887
|
|
|
7888
|
+
// src/daemon/handlers/project-handlers.ts
|
|
7889
|
+
var path17 = __toESM(require("path"));
|
|
7890
|
+
var fs16 = __toESM(require("fs"));
|
|
7891
|
+
function validateSlug(slug, fieldName) {
|
|
7892
|
+
if (!slug || typeof slug !== "string") {
|
|
7893
|
+
return `${fieldName} is required`;
|
|
7894
|
+
}
|
|
7895
|
+
const trimmed = slug.trim();
|
|
7896
|
+
if (!trimmed) {
|
|
7897
|
+
return `${fieldName} cannot be empty`;
|
|
7898
|
+
}
|
|
7899
|
+
if (trimmed.includes("..") || trimmed.includes("/") || trimmed.includes("\\")) {
|
|
7900
|
+
return `${fieldName} contains invalid characters`;
|
|
7901
|
+
}
|
|
7902
|
+
if (trimmed.includes("\0")) {
|
|
7903
|
+
return `${fieldName} contains invalid characters`;
|
|
7904
|
+
}
|
|
7905
|
+
if (trimmed.startsWith(".")) {
|
|
7906
|
+
return `${fieldName} cannot start with a dot`;
|
|
7907
|
+
}
|
|
7908
|
+
return null;
|
|
7909
|
+
}
|
|
7910
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7911
|
+
async function handleProjectSetup(params) {
|
|
7912
|
+
const { workspaceSlug, projectSlug, projectId } = params;
|
|
7913
|
+
const workspaceError = validateSlug(workspaceSlug, "workspaceSlug");
|
|
7914
|
+
if (workspaceError) {
|
|
7915
|
+
console.error(`[ProjectSetup] EP1199: Validation failed: ${workspaceError}`);
|
|
7916
|
+
return { success: false, error: workspaceError };
|
|
7917
|
+
}
|
|
7918
|
+
const projectError = validateSlug(projectSlug, "projectSlug");
|
|
7919
|
+
if (projectError) {
|
|
7920
|
+
console.error(`[ProjectSetup] EP1199: Validation failed: ${projectError}`);
|
|
7921
|
+
return { success: false, error: projectError };
|
|
7922
|
+
}
|
|
7923
|
+
if (!UUID_REGEX.test(projectId)) {
|
|
7924
|
+
console.error(`[ProjectSetup] EP1199: Invalid projectId format: ${projectId}`);
|
|
7925
|
+
return { success: false, error: "Invalid projectId format" };
|
|
7926
|
+
}
|
|
7927
|
+
console.log(`[ProjectSetup] EP1199: Setting up project ${workspaceSlug}/${projectSlug}`);
|
|
7928
|
+
try {
|
|
7929
|
+
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
7930
|
+
const artifactsPath = path17.join(projectPath, "artifacts");
|
|
7931
|
+
const configDir = path17.join(projectPath, ".episoda");
|
|
7932
|
+
const configPath = path17.join(configDir, "config.json");
|
|
7933
|
+
await fs16.promises.mkdir(artifactsPath, { recursive: true });
|
|
7934
|
+
await fs16.promises.mkdir(configDir, { recursive: true });
|
|
7935
|
+
let existingConfig = {};
|
|
7936
|
+
try {
|
|
7937
|
+
const existing = await fs16.promises.readFile(configPath, "utf-8");
|
|
7938
|
+
existingConfig = JSON.parse(existing);
|
|
7939
|
+
} catch {
|
|
7940
|
+
}
|
|
7941
|
+
const config = {
|
|
7942
|
+
...existingConfig,
|
|
7943
|
+
project_id: projectId,
|
|
7944
|
+
workspace_slug: workspaceSlug,
|
|
7945
|
+
project_slug: projectSlug,
|
|
7946
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7947
|
+
// Only set created_at if not already present
|
|
7948
|
+
created_at: existingConfig.created_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
7949
|
+
};
|
|
7950
|
+
await fs16.promises.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
7951
|
+
console.log(`[ProjectSetup] EP1199: Project setup complete at ${projectPath}`);
|
|
7952
|
+
return {
|
|
7953
|
+
success: true,
|
|
7954
|
+
projectPath,
|
|
7955
|
+
artifactsPath
|
|
7956
|
+
};
|
|
7957
|
+
} catch (error) {
|
|
7958
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7959
|
+
console.error(`[ProjectSetup] EP1199: Setup failed:`, errorMessage);
|
|
7960
|
+
return {
|
|
7961
|
+
success: false,
|
|
7962
|
+
error: errorMessage
|
|
7963
|
+
};
|
|
7964
|
+
}
|
|
7965
|
+
}
|
|
7966
|
+
|
|
7733
7967
|
// src/daemon/handlers/stale-commit-cleanup.ts
|
|
7734
7968
|
var import_child_process9 = require("child_process");
|
|
7735
7969
|
var import_util2 = require("util");
|
|
@@ -7827,12 +8061,12 @@ async function cleanupStaleCommits(projectPath) {
|
|
|
7827
8061
|
|
|
7828
8062
|
// src/agent/claude-binary.ts
|
|
7829
8063
|
var import_child_process10 = require("child_process");
|
|
7830
|
-
var
|
|
7831
|
-
var
|
|
8064
|
+
var path18 = __toESM(require("path"));
|
|
8065
|
+
var fs17 = __toESM(require("fs"));
|
|
7832
8066
|
var cachedBinaryPath = null;
|
|
7833
8067
|
function isValidClaudeBinary(binaryPath) {
|
|
7834
8068
|
try {
|
|
7835
|
-
|
|
8069
|
+
fs17.accessSync(binaryPath, fs17.constants.X_OK);
|
|
7836
8070
|
const version = (0, import_child_process10.execSync)(`"${binaryPath}" --version`, {
|
|
7837
8071
|
encoding: "utf-8",
|
|
7838
8072
|
timeout: 5e3,
|
|
@@ -7865,14 +8099,14 @@ async function ensureClaudeBinary() {
|
|
|
7865
8099
|
}
|
|
7866
8100
|
const bundledPaths = [
|
|
7867
8101
|
// In production: node_modules/.bin/claude
|
|
7868
|
-
|
|
8102
|
+
path18.join(__dirname, "..", "..", "node_modules", ".bin", "claude"),
|
|
7869
8103
|
// In monorepo development: packages/episoda/node_modules/.bin/claude
|
|
7870
|
-
|
|
8104
|
+
path18.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "claude"),
|
|
7871
8105
|
// Root monorepo node_modules
|
|
7872
|
-
|
|
8106
|
+
path18.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "claude")
|
|
7873
8107
|
];
|
|
7874
8108
|
for (const bundledPath of bundledPaths) {
|
|
7875
|
-
if (
|
|
8109
|
+
if (fs17.existsSync(bundledPath) && isValidClaudeBinary(bundledPath)) {
|
|
7876
8110
|
cachedBinaryPath = bundledPath;
|
|
7877
8111
|
return cachedBinaryPath;
|
|
7878
8112
|
}
|
|
@@ -7898,12 +8132,12 @@ async function ensureClaudeBinary() {
|
|
|
7898
8132
|
|
|
7899
8133
|
// src/agent/codex-binary.ts
|
|
7900
8134
|
var import_child_process11 = require("child_process");
|
|
7901
|
-
var
|
|
7902
|
-
var
|
|
8135
|
+
var path19 = __toESM(require("path"));
|
|
8136
|
+
var fs18 = __toESM(require("fs"));
|
|
7903
8137
|
var cachedBinaryPath2 = null;
|
|
7904
8138
|
function isValidCodexBinary(binaryPath) {
|
|
7905
8139
|
try {
|
|
7906
|
-
|
|
8140
|
+
fs18.accessSync(binaryPath, fs18.constants.X_OK);
|
|
7907
8141
|
const version = (0, import_child_process11.execSync)(`"${binaryPath}" --version`, {
|
|
7908
8142
|
encoding: "utf-8",
|
|
7909
8143
|
timeout: 5e3,
|
|
@@ -7936,14 +8170,14 @@ async function ensureCodexBinary() {
|
|
|
7936
8170
|
}
|
|
7937
8171
|
const bundledPaths = [
|
|
7938
8172
|
// In production: node_modules/.bin/codex
|
|
7939
|
-
|
|
8173
|
+
path19.join(__dirname, "..", "..", "node_modules", ".bin", "codex"),
|
|
7940
8174
|
// In monorepo development: packages/episoda/node_modules/.bin/codex
|
|
7941
|
-
|
|
8175
|
+
path19.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "codex"),
|
|
7942
8176
|
// Root monorepo node_modules
|
|
7943
|
-
|
|
8177
|
+
path19.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "codex")
|
|
7944
8178
|
];
|
|
7945
8179
|
for (const bundledPath of bundledPaths) {
|
|
7946
|
-
if (
|
|
8180
|
+
if (fs18.existsSync(bundledPath) && isValidCodexBinary(bundledPath)) {
|
|
7947
8181
|
cachedBinaryPath2 = bundledPath;
|
|
7948
8182
|
return cachedBinaryPath2;
|
|
7949
8183
|
}
|
|
@@ -8010,8 +8244,8 @@ function generateCodexConfig(credentials, projectPath) {
|
|
|
8010
8244
|
|
|
8011
8245
|
// src/agent/agent-manager.ts
|
|
8012
8246
|
var import_child_process12 = require("child_process");
|
|
8013
|
-
var
|
|
8014
|
-
var
|
|
8247
|
+
var path20 = __toESM(require("path"));
|
|
8248
|
+
var fs19 = __toESM(require("fs"));
|
|
8015
8249
|
var os6 = __toESM(require("os"));
|
|
8016
8250
|
|
|
8017
8251
|
// src/agent/claude-config.ts
|
|
@@ -8334,7 +8568,7 @@ var AgentManager = class {
|
|
|
8334
8568
|
this.initialized = false;
|
|
8335
8569
|
// EP1133: Lock for config file writes to prevent race conditions
|
|
8336
8570
|
this.configWriteLock = Promise.resolve();
|
|
8337
|
-
this.pidDir =
|
|
8571
|
+
this.pidDir = path20.join(os6.homedir(), ".episoda", "agent-pids");
|
|
8338
8572
|
}
|
|
8339
8573
|
/**
|
|
8340
8574
|
* EP1133: Acquire lock for config file writes
|
|
@@ -8363,8 +8597,8 @@ var AgentManager = class {
|
|
|
8363
8597
|
return;
|
|
8364
8598
|
}
|
|
8365
8599
|
console.log("[AgentManager] Initializing...");
|
|
8366
|
-
if (!
|
|
8367
|
-
|
|
8600
|
+
if (!fs19.existsSync(this.pidDir)) {
|
|
8601
|
+
fs19.mkdirSync(this.pidDir, { recursive: true });
|
|
8368
8602
|
}
|
|
8369
8603
|
await this.cleanupOrphanedProcesses();
|
|
8370
8604
|
try {
|
|
@@ -8611,9 +8845,9 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8611
8845
|
const useApiKey = !useOAuth && !!session.credentials.apiKey;
|
|
8612
8846
|
if (provider === "codex") {
|
|
8613
8847
|
await this.withConfigLock(async () => {
|
|
8614
|
-
const codexDir =
|
|
8615
|
-
if (!
|
|
8616
|
-
|
|
8848
|
+
const codexDir = path20.join(os6.homedir(), ".codex");
|
|
8849
|
+
if (!fs19.existsSync(codexDir)) {
|
|
8850
|
+
fs19.mkdirSync(codexDir, { recursive: true });
|
|
8617
8851
|
}
|
|
8618
8852
|
if (useOAuth) {
|
|
8619
8853
|
const codexConfig = generateCodexConfig({
|
|
@@ -8623,21 +8857,21 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8623
8857
|
accountId: session.credentials.accountId,
|
|
8624
8858
|
expiresAt: session.credentials.expiresAt
|
|
8625
8859
|
}, session.projectPath);
|
|
8626
|
-
const authJsonPath =
|
|
8627
|
-
|
|
8860
|
+
const authJsonPath = path20.join(codexDir, "auth.json");
|
|
8861
|
+
fs19.writeFileSync(authJsonPath, codexConfig["auth.json"], { mode: 384 });
|
|
8628
8862
|
console.log("[AgentManager] EP1133: Wrote Codex auth.json to ~/.codex/auth.json");
|
|
8629
8863
|
if (codexConfig["config.toml"]) {
|
|
8630
|
-
const configTomlPath =
|
|
8864
|
+
const configTomlPath = path20.join(codexDir, "config.toml");
|
|
8631
8865
|
let existingConfig = "";
|
|
8632
8866
|
try {
|
|
8633
|
-
existingConfig =
|
|
8867
|
+
existingConfig = fs19.readFileSync(configTomlPath, "utf-8");
|
|
8634
8868
|
} catch {
|
|
8635
8869
|
}
|
|
8636
8870
|
const escapedPathForRegex = session.projectPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8637
8871
|
const projectKeyPattern = new RegExp(`\\[projects\\."${escapedPathForRegex}"\\]`);
|
|
8638
8872
|
const projectAlreadyTrusted = projectKeyPattern.test(existingConfig);
|
|
8639
8873
|
if (!projectAlreadyTrusted) {
|
|
8640
|
-
|
|
8874
|
+
fs19.writeFileSync(configTomlPath, existingConfig + "\n" + codexConfig["config.toml"], { mode: 420 });
|
|
8641
8875
|
console.log("[AgentManager] EP1133: Updated Codex config.toml with project trust");
|
|
8642
8876
|
}
|
|
8643
8877
|
}
|
|
@@ -8647,14 +8881,14 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8647
8881
|
});
|
|
8648
8882
|
} else {
|
|
8649
8883
|
await this.withConfigLock(async () => {
|
|
8650
|
-
const claudeDir =
|
|
8651
|
-
const credentialsPath =
|
|
8652
|
-
const statsigDir =
|
|
8653
|
-
if (!
|
|
8654
|
-
|
|
8884
|
+
const claudeDir = path20.join(os6.homedir(), ".claude");
|
|
8885
|
+
const credentialsPath = path20.join(claudeDir, ".credentials.json");
|
|
8886
|
+
const statsigDir = path20.join(claudeDir, "statsig");
|
|
8887
|
+
if (!fs19.existsSync(claudeDir)) {
|
|
8888
|
+
fs19.mkdirSync(claudeDir, { recursive: true });
|
|
8655
8889
|
}
|
|
8656
|
-
if (!
|
|
8657
|
-
|
|
8890
|
+
if (!fs19.existsSync(statsigDir)) {
|
|
8891
|
+
fs19.mkdirSync(statsigDir, { recursive: true });
|
|
8658
8892
|
}
|
|
8659
8893
|
if (useOAuth) {
|
|
8660
8894
|
const oauthCredentials = {
|
|
@@ -8672,7 +8906,7 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8672
8906
|
const credentialsContent = JSON.stringify({
|
|
8673
8907
|
claudeAiOauth: oauthCredentials
|
|
8674
8908
|
}, null, 2);
|
|
8675
|
-
|
|
8909
|
+
fs19.writeFileSync(credentialsPath, credentialsContent, { mode: 384 });
|
|
8676
8910
|
console.log("[AgentManager] Wrote OAuth credentials to ~/.claude/.credentials.json");
|
|
8677
8911
|
try {
|
|
8678
8912
|
const claudeConfig = generateClaudeConfig({
|
|
@@ -8684,11 +8918,11 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8684
8918
|
if (!hasEvaluations || !hasStableId) {
|
|
8685
8919
|
throw new Error(`Invalid statsig config: missing required files`);
|
|
8686
8920
|
}
|
|
8687
|
-
const settingsPath =
|
|
8688
|
-
|
|
8921
|
+
const settingsPath = path20.join(claudeDir, "settings.json");
|
|
8922
|
+
fs19.writeFileSync(settingsPath, claudeConfig["settings.json"], { mode: 384 });
|
|
8689
8923
|
for (const [filename, content] of Object.entries(claudeConfig.statsig)) {
|
|
8690
|
-
const filePath =
|
|
8691
|
-
|
|
8924
|
+
const filePath = path20.join(statsigDir, filename);
|
|
8925
|
+
fs19.writeFileSync(filePath, content, { mode: 420 });
|
|
8692
8926
|
}
|
|
8693
8927
|
if (session.credentials.githubToken) {
|
|
8694
8928
|
console.log("[AgentManager] EP1146: GitHub MCP server enabled with installation token");
|
|
@@ -8958,14 +9192,14 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8958
9192
|
*/
|
|
8959
9193
|
async cleanupOrphanedProcesses() {
|
|
8960
9194
|
let cleaned = 0;
|
|
8961
|
-
if (!
|
|
9195
|
+
if (!fs19.existsSync(this.pidDir)) {
|
|
8962
9196
|
return { cleaned };
|
|
8963
9197
|
}
|
|
8964
|
-
const pidFiles =
|
|
9198
|
+
const pidFiles = fs19.readdirSync(this.pidDir).filter((f) => f.endsWith(".pid"));
|
|
8965
9199
|
for (const pidFile of pidFiles) {
|
|
8966
|
-
const pidPath =
|
|
9200
|
+
const pidPath = path20.join(this.pidDir, pidFile);
|
|
8967
9201
|
try {
|
|
8968
|
-
const pidStr =
|
|
9202
|
+
const pidStr = fs19.readFileSync(pidPath, "utf-8").trim();
|
|
8969
9203
|
const pid = parseInt(pidStr, 10);
|
|
8970
9204
|
if (!isNaN(pid)) {
|
|
8971
9205
|
try {
|
|
@@ -8976,7 +9210,7 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8976
9210
|
} catch {
|
|
8977
9211
|
}
|
|
8978
9212
|
}
|
|
8979
|
-
|
|
9213
|
+
fs19.unlinkSync(pidPath);
|
|
8980
9214
|
} catch (error) {
|
|
8981
9215
|
console.warn(`[AgentManager] Error cleaning PID file ${pidFile}:`, error);
|
|
8982
9216
|
}
|
|
@@ -8990,17 +9224,17 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8990
9224
|
* Write PID file for session tracking
|
|
8991
9225
|
*/
|
|
8992
9226
|
writePidFile(sessionId, pid) {
|
|
8993
|
-
const pidPath =
|
|
8994
|
-
|
|
9227
|
+
const pidPath = path20.join(this.pidDir, `${sessionId}.pid`);
|
|
9228
|
+
fs19.writeFileSync(pidPath, pid.toString());
|
|
8995
9229
|
}
|
|
8996
9230
|
/**
|
|
8997
9231
|
* Remove PID file for session
|
|
8998
9232
|
*/
|
|
8999
9233
|
removePidFile(sessionId) {
|
|
9000
|
-
const pidPath =
|
|
9234
|
+
const pidPath = path20.join(this.pidDir, `${sessionId}.pid`);
|
|
9001
9235
|
try {
|
|
9002
|
-
if (
|
|
9003
|
-
|
|
9236
|
+
if (fs19.existsSync(pidPath)) {
|
|
9237
|
+
fs19.unlinkSync(pidPath);
|
|
9004
9238
|
}
|
|
9005
9239
|
} catch {
|
|
9006
9240
|
}
|
|
@@ -9010,8 +9244,8 @@ If changes are needed, explain what needs to be done.`;
|
|
|
9010
9244
|
// src/utils/dev-server.ts
|
|
9011
9245
|
var import_child_process13 = require("child_process");
|
|
9012
9246
|
var import_core11 = __toESM(require_dist());
|
|
9013
|
-
var
|
|
9014
|
-
var
|
|
9247
|
+
var fs20 = __toESM(require("fs"));
|
|
9248
|
+
var path21 = __toESM(require("path"));
|
|
9015
9249
|
var MAX_RESTART_ATTEMPTS = 5;
|
|
9016
9250
|
var INITIAL_RESTART_DELAY_MS = 2e3;
|
|
9017
9251
|
var MAX_RESTART_DELAY_MS = 3e4;
|
|
@@ -9019,26 +9253,26 @@ var MAX_LOG_SIZE_BYTES = 5 * 1024 * 1024;
|
|
|
9019
9253
|
var NODE_MEMORY_LIMIT_MB = 2048;
|
|
9020
9254
|
var activeServers = /* @__PURE__ */ new Map();
|
|
9021
9255
|
function getLogsDir() {
|
|
9022
|
-
const logsDir =
|
|
9023
|
-
if (!
|
|
9024
|
-
|
|
9256
|
+
const logsDir = path21.join((0, import_core11.getConfigDir)(), "logs");
|
|
9257
|
+
if (!fs20.existsSync(logsDir)) {
|
|
9258
|
+
fs20.mkdirSync(logsDir, { recursive: true });
|
|
9025
9259
|
}
|
|
9026
9260
|
return logsDir;
|
|
9027
9261
|
}
|
|
9028
9262
|
function getLogFilePath(moduleUid) {
|
|
9029
|
-
return
|
|
9263
|
+
return path21.join(getLogsDir(), `dev-${moduleUid}.log`);
|
|
9030
9264
|
}
|
|
9031
9265
|
function rotateLogIfNeeded(logPath) {
|
|
9032
9266
|
try {
|
|
9033
|
-
if (
|
|
9034
|
-
const stats =
|
|
9267
|
+
if (fs20.existsSync(logPath)) {
|
|
9268
|
+
const stats = fs20.statSync(logPath);
|
|
9035
9269
|
if (stats.size > MAX_LOG_SIZE_BYTES) {
|
|
9036
9270
|
const backupPath = `${logPath}.1`;
|
|
9037
|
-
if (
|
|
9038
|
-
|
|
9271
|
+
if (fs20.existsSync(backupPath)) {
|
|
9272
|
+
fs20.unlinkSync(backupPath);
|
|
9039
9273
|
}
|
|
9040
|
-
|
|
9041
|
-
console.log(`[DevServer] EP932: Rotated log file for ${
|
|
9274
|
+
fs20.renameSync(logPath, backupPath);
|
|
9275
|
+
console.log(`[DevServer] EP932: Rotated log file for ${path21.basename(logPath)}`);
|
|
9042
9276
|
}
|
|
9043
9277
|
}
|
|
9044
9278
|
} catch (error) {
|
|
@@ -9051,7 +9285,7 @@ function writeToLog(logPath, line, isError = false) {
|
|
|
9051
9285
|
const prefix = isError ? "ERR" : "OUT";
|
|
9052
9286
|
const logLine = `[${timestamp}] [${prefix}] ${line}
|
|
9053
9287
|
`;
|
|
9054
|
-
|
|
9288
|
+
fs20.appendFileSync(logPath, logLine);
|
|
9055
9289
|
} catch {
|
|
9056
9290
|
}
|
|
9057
9291
|
}
|
|
@@ -9230,8 +9464,8 @@ async function startDevServer(projectPath, port = 3e3, moduleUid = "default", op
|
|
|
9230
9464
|
});
|
|
9231
9465
|
injectedEnvVars = result.envVars;
|
|
9232
9466
|
console.log(`[DevServer] EP998: Loaded ${Object.keys(injectedEnvVars).length} env vars (from ${result.fromCache ? "cache" : "server"})`);
|
|
9233
|
-
const envFilePath =
|
|
9234
|
-
if (!
|
|
9467
|
+
const envFilePath = path21.join(projectPath, ".env");
|
|
9468
|
+
if (!fs20.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
|
|
9235
9469
|
console.log(`[DevServer] EP1004: .env file missing, writing ${Object.keys(injectedEnvVars).length} vars to ${envFilePath}`);
|
|
9236
9470
|
writeEnvFile(projectPath, injectedEnvVars);
|
|
9237
9471
|
}
|
|
@@ -9337,19 +9571,19 @@ function getDevServerStatus() {
|
|
|
9337
9571
|
}
|
|
9338
9572
|
|
|
9339
9573
|
// src/utils/worktree.ts
|
|
9340
|
-
var
|
|
9341
|
-
var
|
|
9574
|
+
var path22 = __toESM(require("path"));
|
|
9575
|
+
var fs21 = __toESM(require("fs"));
|
|
9342
9576
|
var os7 = __toESM(require("os"));
|
|
9343
9577
|
var import_core12 = __toESM(require_dist());
|
|
9344
9578
|
function getEpisodaRoot2() {
|
|
9345
|
-
return process.env.EPISODA_ROOT ||
|
|
9579
|
+
return process.env.EPISODA_ROOT || path22.join(os7.homedir(), "episoda");
|
|
9346
9580
|
}
|
|
9347
9581
|
function getWorktreeInfo(moduleUid, workspaceSlug, projectSlug) {
|
|
9348
9582
|
const root = getEpisodaRoot2();
|
|
9349
|
-
const worktreePath =
|
|
9583
|
+
const worktreePath = path22.join(root, workspaceSlug, projectSlug, moduleUid);
|
|
9350
9584
|
return {
|
|
9351
9585
|
path: worktreePath,
|
|
9352
|
-
exists:
|
|
9586
|
+
exists: fs21.existsSync(worktreePath),
|
|
9353
9587
|
moduleUid
|
|
9354
9588
|
};
|
|
9355
9589
|
}
|
|
@@ -9363,15 +9597,15 @@ async function getWorktreeInfoForModule(moduleUid) {
|
|
|
9363
9597
|
return null;
|
|
9364
9598
|
}
|
|
9365
9599
|
const root = getEpisodaRoot2();
|
|
9366
|
-
const workspaceRoot =
|
|
9600
|
+
const workspaceRoot = path22.join(root, config.workspace_slug);
|
|
9367
9601
|
try {
|
|
9368
|
-
const entries =
|
|
9602
|
+
const entries = fs21.readdirSync(workspaceRoot, { withFileTypes: true });
|
|
9369
9603
|
for (const entry of entries) {
|
|
9370
9604
|
if (!entry.isDirectory()) {
|
|
9371
9605
|
continue;
|
|
9372
9606
|
}
|
|
9373
|
-
const worktreePath =
|
|
9374
|
-
if (
|
|
9607
|
+
const worktreePath = path22.join(workspaceRoot, entry.name, moduleUid);
|
|
9608
|
+
if (fs21.existsSync(worktreePath)) {
|
|
9375
9609
|
return {
|
|
9376
9610
|
path: worktreePath,
|
|
9377
9611
|
exists: true,
|
|
@@ -9388,61 +9622,61 @@ async function getWorktreeInfoForModule(moduleUid) {
|
|
|
9388
9622
|
}
|
|
9389
9623
|
|
|
9390
9624
|
// src/framework-detector.ts
|
|
9391
|
-
var
|
|
9392
|
-
var
|
|
9393
|
-
function
|
|
9394
|
-
if (
|
|
9625
|
+
var fs22 = __toESM(require("fs"));
|
|
9626
|
+
var path23 = __toESM(require("path"));
|
|
9627
|
+
function getInstallCommand2(cwd) {
|
|
9628
|
+
if (fs22.existsSync(path23.join(cwd, "bun.lockb"))) {
|
|
9395
9629
|
return {
|
|
9396
9630
|
command: ["bun", "install"],
|
|
9397
9631
|
description: "Installing dependencies with bun",
|
|
9398
9632
|
detectedFrom: "bun.lockb"
|
|
9399
9633
|
};
|
|
9400
9634
|
}
|
|
9401
|
-
if (
|
|
9635
|
+
if (fs22.existsSync(path23.join(cwd, "pnpm-lock.yaml"))) {
|
|
9402
9636
|
return {
|
|
9403
9637
|
command: ["pnpm", "install"],
|
|
9404
9638
|
description: "Installing dependencies with pnpm",
|
|
9405
9639
|
detectedFrom: "pnpm-lock.yaml"
|
|
9406
9640
|
};
|
|
9407
9641
|
}
|
|
9408
|
-
if (
|
|
9642
|
+
if (fs22.existsSync(path23.join(cwd, "yarn.lock"))) {
|
|
9409
9643
|
return {
|
|
9410
9644
|
command: ["yarn", "install"],
|
|
9411
9645
|
description: "Installing dependencies with yarn",
|
|
9412
9646
|
detectedFrom: "yarn.lock"
|
|
9413
9647
|
};
|
|
9414
9648
|
}
|
|
9415
|
-
if (
|
|
9649
|
+
if (fs22.existsSync(path23.join(cwd, "package-lock.json"))) {
|
|
9416
9650
|
return {
|
|
9417
9651
|
command: ["npm", "ci"],
|
|
9418
9652
|
description: "Installing dependencies with npm ci",
|
|
9419
9653
|
detectedFrom: "package-lock.json"
|
|
9420
9654
|
};
|
|
9421
9655
|
}
|
|
9422
|
-
if (
|
|
9656
|
+
if (fs22.existsSync(path23.join(cwd, "package.json"))) {
|
|
9423
9657
|
return {
|
|
9424
9658
|
command: ["npm", "install"],
|
|
9425
9659
|
description: "Installing dependencies with npm",
|
|
9426
9660
|
detectedFrom: "package.json"
|
|
9427
9661
|
};
|
|
9428
9662
|
}
|
|
9429
|
-
if (
|
|
9663
|
+
if (fs22.existsSync(path23.join(cwd, "Pipfile.lock")) || fs22.existsSync(path23.join(cwd, "Pipfile"))) {
|
|
9430
9664
|
return {
|
|
9431
9665
|
command: ["pipenv", "install"],
|
|
9432
9666
|
description: "Installing dependencies with pipenv",
|
|
9433
|
-
detectedFrom:
|
|
9667
|
+
detectedFrom: fs22.existsSync(path23.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
|
|
9434
9668
|
};
|
|
9435
9669
|
}
|
|
9436
|
-
if (
|
|
9670
|
+
if (fs22.existsSync(path23.join(cwd, "poetry.lock"))) {
|
|
9437
9671
|
return {
|
|
9438
9672
|
command: ["poetry", "install"],
|
|
9439
9673
|
description: "Installing dependencies with poetry",
|
|
9440
9674
|
detectedFrom: "poetry.lock"
|
|
9441
9675
|
};
|
|
9442
9676
|
}
|
|
9443
|
-
if (
|
|
9444
|
-
const pyprojectPath =
|
|
9445
|
-
const content =
|
|
9677
|
+
if (fs22.existsSync(path23.join(cwd, "pyproject.toml"))) {
|
|
9678
|
+
const pyprojectPath = path23.join(cwd, "pyproject.toml");
|
|
9679
|
+
const content = fs22.readFileSync(pyprojectPath, "utf-8");
|
|
9446
9680
|
if (content.includes("[tool.poetry]")) {
|
|
9447
9681
|
return {
|
|
9448
9682
|
command: ["poetry", "install"],
|
|
@@ -9451,42 +9685,42 @@ function getInstallCommand(cwd) {
|
|
|
9451
9685
|
};
|
|
9452
9686
|
}
|
|
9453
9687
|
}
|
|
9454
|
-
if (
|
|
9688
|
+
if (fs22.existsSync(path23.join(cwd, "requirements.txt"))) {
|
|
9455
9689
|
return {
|
|
9456
9690
|
command: ["pip", "install", "-r", "requirements.txt"],
|
|
9457
9691
|
description: "Installing dependencies with pip",
|
|
9458
9692
|
detectedFrom: "requirements.txt"
|
|
9459
9693
|
};
|
|
9460
9694
|
}
|
|
9461
|
-
if (
|
|
9695
|
+
if (fs22.existsSync(path23.join(cwd, "Gemfile.lock")) || fs22.existsSync(path23.join(cwd, "Gemfile"))) {
|
|
9462
9696
|
return {
|
|
9463
9697
|
command: ["bundle", "install"],
|
|
9464
9698
|
description: "Installing dependencies with bundler",
|
|
9465
|
-
detectedFrom:
|
|
9699
|
+
detectedFrom: fs22.existsSync(path23.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
|
|
9466
9700
|
};
|
|
9467
9701
|
}
|
|
9468
|
-
if (
|
|
9702
|
+
if (fs22.existsSync(path23.join(cwd, "go.sum")) || fs22.existsSync(path23.join(cwd, "go.mod"))) {
|
|
9469
9703
|
return {
|
|
9470
9704
|
command: ["go", "mod", "download"],
|
|
9471
9705
|
description: "Downloading Go modules",
|
|
9472
|
-
detectedFrom:
|
|
9706
|
+
detectedFrom: fs22.existsSync(path23.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
|
|
9473
9707
|
};
|
|
9474
9708
|
}
|
|
9475
|
-
if (
|
|
9709
|
+
if (fs22.existsSync(path23.join(cwd, "Cargo.lock")) || fs22.existsSync(path23.join(cwd, "Cargo.toml"))) {
|
|
9476
9710
|
return {
|
|
9477
9711
|
command: ["cargo", "build"],
|
|
9478
9712
|
description: "Building Rust project (downloads dependencies)",
|
|
9479
|
-
detectedFrom:
|
|
9713
|
+
detectedFrom: fs22.existsSync(path23.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
|
|
9480
9714
|
};
|
|
9481
9715
|
}
|
|
9482
9716
|
return null;
|
|
9483
9717
|
}
|
|
9484
9718
|
|
|
9485
9719
|
// src/daemon/daemon-process.ts
|
|
9486
|
-
var
|
|
9720
|
+
var fs23 = __toESM(require("fs"));
|
|
9487
9721
|
var http2 = __toESM(require("http"));
|
|
9488
9722
|
var os8 = __toESM(require("os"));
|
|
9489
|
-
var
|
|
9723
|
+
var path24 = __toESM(require("path"));
|
|
9490
9724
|
var packageJson = require_package();
|
|
9491
9725
|
async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
|
|
9492
9726
|
const now = Date.now();
|
|
@@ -9707,9 +9941,9 @@ var Daemon = class _Daemon {
|
|
|
9707
9941
|
this.healthServer = http2.createServer((req, res) => {
|
|
9708
9942
|
if (req.url === "/health" || req.url === "/") {
|
|
9709
9943
|
const isConnected = this.liveConnections.size > 0;
|
|
9710
|
-
const projects = Array.from(this.connections.entries()).map(([
|
|
9711
|
-
path:
|
|
9712
|
-
connected: this.liveConnections.has(
|
|
9944
|
+
const projects = Array.from(this.connections.entries()).map(([path25, conn]) => ({
|
|
9945
|
+
path: path25,
|
|
9946
|
+
connected: this.liveConnections.has(path25)
|
|
9713
9947
|
}));
|
|
9714
9948
|
const status = {
|
|
9715
9949
|
status: isConnected ? "healthy" : "degraded",
|
|
@@ -9939,9 +10173,12 @@ var Daemon = class _Daemon {
|
|
|
9939
10173
|
this.ipcServer.on("worktree-list", async (params) => {
|
|
9940
10174
|
return handleWorktreeList(params.workspaceSlug, params.projectSlug);
|
|
9941
10175
|
});
|
|
9942
|
-
this.ipcServer.on("project
|
|
10176
|
+
this.ipcServer.on("project:eject", async (params) => {
|
|
9943
10177
|
return handleProjectEject(params);
|
|
9944
10178
|
});
|
|
10179
|
+
this.ipcServer.on("project:setup", async (params) => {
|
|
10180
|
+
return handleProjectSetup(params);
|
|
10181
|
+
});
|
|
9945
10182
|
}
|
|
9946
10183
|
/**
|
|
9947
10184
|
* Restore WebSocket connections for tracked projects
|
|
@@ -10074,7 +10311,7 @@ var Daemon = class _Daemon {
|
|
|
10074
10311
|
client.updateActivity();
|
|
10075
10312
|
try {
|
|
10076
10313
|
const gitCmd = message.command;
|
|
10077
|
-
const bareRepoPath =
|
|
10314
|
+
const bareRepoPath = path24.join(projectPath, ".bare");
|
|
10078
10315
|
const cwd = gitCmd.worktreePath || bareRepoPath;
|
|
10079
10316
|
if (gitCmd.worktreePath) {
|
|
10080
10317
|
console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
|
|
@@ -10188,9 +10425,14 @@ var Daemon = class _Daemon {
|
|
|
10188
10425
|
);
|
|
10189
10426
|
break;
|
|
10190
10427
|
// EP1144: Project ejection for Tier 1 cleanup
|
|
10191
|
-
|
|
10428
|
+
// EP1199: Renamed from eject_project to project:eject for naming consistency
|
|
10429
|
+
case "project:eject":
|
|
10192
10430
|
result = await handleProjectEject(cmd);
|
|
10193
10431
|
break;
|
|
10432
|
+
// EP1199: Project setup for cloud containers
|
|
10433
|
+
case "project:setup":
|
|
10434
|
+
result = await handleProjectSetup(cmd);
|
|
10435
|
+
break;
|
|
10194
10436
|
default:
|
|
10195
10437
|
result = {
|
|
10196
10438
|
success: false,
|
|
@@ -10654,8 +10896,8 @@ var Daemon = class _Daemon {
|
|
|
10654
10896
|
let daemonPid;
|
|
10655
10897
|
try {
|
|
10656
10898
|
const pidPath = getPidFilePath();
|
|
10657
|
-
if (
|
|
10658
|
-
const pidStr =
|
|
10899
|
+
if (fs23.existsSync(pidPath)) {
|
|
10900
|
+
const pidStr = fs23.readFileSync(pidPath, "utf-8").trim();
|
|
10659
10901
|
daemonPid = parseInt(pidStr, 10);
|
|
10660
10902
|
}
|
|
10661
10903
|
} catch (pidError) {
|
|
@@ -10736,28 +10978,28 @@ var Daemon = class _Daemon {
|
|
|
10736
10978
|
* - workDir: The directory to run git commands in (cwd)
|
|
10737
10979
|
*/
|
|
10738
10980
|
getGitDirs(projectPath) {
|
|
10739
|
-
const bareDir =
|
|
10740
|
-
const gitPath =
|
|
10741
|
-
if (
|
|
10981
|
+
const bareDir = path24.join(projectPath, ".bare");
|
|
10982
|
+
const gitPath = path24.join(projectPath, ".git");
|
|
10983
|
+
if (fs23.existsSync(bareDir) && fs23.statSync(bareDir).isDirectory()) {
|
|
10742
10984
|
return { gitDir: bareDir, workDir: projectPath };
|
|
10743
10985
|
}
|
|
10744
|
-
if (
|
|
10986
|
+
if (fs23.existsSync(gitPath) && fs23.statSync(gitPath).isDirectory()) {
|
|
10745
10987
|
return { gitDir: null, workDir: projectPath };
|
|
10746
10988
|
}
|
|
10747
|
-
if (
|
|
10989
|
+
if (fs23.existsSync(gitPath) && fs23.statSync(gitPath).isFile()) {
|
|
10748
10990
|
return { gitDir: null, workDir: projectPath };
|
|
10749
10991
|
}
|
|
10750
|
-
const entries =
|
|
10992
|
+
const entries = fs23.readdirSync(projectPath, { withFileTypes: true });
|
|
10751
10993
|
for (const entry of entries) {
|
|
10752
10994
|
if (entry.isDirectory() && entry.name.startsWith("EP")) {
|
|
10753
|
-
const worktreePath =
|
|
10754
|
-
const worktreeGit =
|
|
10755
|
-
if (
|
|
10995
|
+
const worktreePath = path24.join(projectPath, entry.name);
|
|
10996
|
+
const worktreeGit = path24.join(worktreePath, ".git");
|
|
10997
|
+
if (fs23.existsSync(worktreeGit)) {
|
|
10756
10998
|
return { gitDir: null, workDir: worktreePath };
|
|
10757
10999
|
}
|
|
10758
11000
|
}
|
|
10759
11001
|
}
|
|
10760
|
-
if (
|
|
11002
|
+
if (fs23.existsSync(bareDir)) {
|
|
10761
11003
|
return { gitDir: bareDir, workDir: projectPath };
|
|
10762
11004
|
}
|
|
10763
11005
|
return { gitDir: null, workDir: projectPath };
|
|
@@ -10821,24 +11063,24 @@ var Daemon = class _Daemon {
|
|
|
10821
11063
|
async installGitHooks(projectPath) {
|
|
10822
11064
|
const hooks = ["post-checkout", "pre-commit", "post-commit"];
|
|
10823
11065
|
let hooksDir;
|
|
10824
|
-
const bareHooksDir =
|
|
10825
|
-
const gitHooksDir =
|
|
10826
|
-
if (
|
|
11066
|
+
const bareHooksDir = path24.join(projectPath, ".bare", "hooks");
|
|
11067
|
+
const gitHooksDir = path24.join(projectPath, ".git", "hooks");
|
|
11068
|
+
if (fs23.existsSync(bareHooksDir)) {
|
|
10827
11069
|
hooksDir = bareHooksDir;
|
|
10828
|
-
} else if (
|
|
11070
|
+
} else if (fs23.existsSync(gitHooksDir) && fs23.statSync(path24.join(projectPath, ".git")).isDirectory()) {
|
|
10829
11071
|
hooksDir = gitHooksDir;
|
|
10830
11072
|
} else {
|
|
10831
|
-
const parentBareHooks =
|
|
10832
|
-
if (
|
|
11073
|
+
const parentBareHooks = path24.join(projectPath, "..", ".bare", "hooks");
|
|
11074
|
+
if (fs23.existsSync(parentBareHooks)) {
|
|
10833
11075
|
hooksDir = parentBareHooks;
|
|
10834
11076
|
} else {
|
|
10835
11077
|
console.warn(`[Daemon] Hooks directory not found for: ${projectPath}`);
|
|
10836
11078
|
return;
|
|
10837
11079
|
}
|
|
10838
11080
|
}
|
|
10839
|
-
if (!
|
|
11081
|
+
if (!fs23.existsSync(hooksDir)) {
|
|
10840
11082
|
try {
|
|
10841
|
-
|
|
11083
|
+
fs23.mkdirSync(hooksDir, { recursive: true });
|
|
10842
11084
|
} catch (error) {
|
|
10843
11085
|
console.warn(`[Daemon] Hooks directory not found and could not create: ${hooksDir}`);
|
|
10844
11086
|
return;
|
|
@@ -10846,20 +11088,20 @@ var Daemon = class _Daemon {
|
|
|
10846
11088
|
}
|
|
10847
11089
|
for (const hookName of hooks) {
|
|
10848
11090
|
try {
|
|
10849
|
-
const hookPath =
|
|
10850
|
-
const bundledHookPath =
|
|
10851
|
-
if (!
|
|
11091
|
+
const hookPath = path24.join(hooksDir, hookName);
|
|
11092
|
+
const bundledHookPath = path24.join(__dirname, "..", "hooks", hookName);
|
|
11093
|
+
if (!fs23.existsSync(bundledHookPath)) {
|
|
10852
11094
|
console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
|
|
10853
11095
|
continue;
|
|
10854
11096
|
}
|
|
10855
|
-
const hookContent =
|
|
10856
|
-
if (
|
|
10857
|
-
const existingContent =
|
|
11097
|
+
const hookContent = fs23.readFileSync(bundledHookPath, "utf-8");
|
|
11098
|
+
if (fs23.existsSync(hookPath)) {
|
|
11099
|
+
const existingContent = fs23.readFileSync(hookPath, "utf-8");
|
|
10858
11100
|
if (existingContent === hookContent) {
|
|
10859
11101
|
continue;
|
|
10860
11102
|
}
|
|
10861
11103
|
}
|
|
10862
|
-
|
|
11104
|
+
fs23.writeFileSync(hookPath, hookContent, { mode: 493 });
|
|
10863
11105
|
console.log(`[Daemon] Installed git hook: ${hookName}`);
|
|
10864
11106
|
} catch (error) {
|
|
10865
11107
|
console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
|
|
@@ -11197,7 +11439,7 @@ var Daemon = class _Daemon {
|
|
|
11197
11439
|
console.log(`[Daemon] EP1002: Writing .env with ${Object.keys(envVars).length} variables`);
|
|
11198
11440
|
writeEnvFile(worktreePath, envVars);
|
|
11199
11441
|
}
|
|
11200
|
-
const installCmd =
|
|
11442
|
+
const installCmd = getInstallCommand2(worktreePath);
|
|
11201
11443
|
if (installCmd) {
|
|
11202
11444
|
console.log(`[Daemon] EP1002: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
|
|
11203
11445
|
console.log(`[Daemon] EP1002: Running: ${installCmd.command.join(" ")}`);
|
|
@@ -11251,7 +11493,7 @@ var Daemon = class _Daemon {
|
|
|
11251
11493
|
console.warn(`[Daemon] EP964: File copy failed (non-fatal): ${copyResult.error}`);
|
|
11252
11494
|
}
|
|
11253
11495
|
}
|
|
11254
|
-
const installCmd =
|
|
11496
|
+
const installCmd = getInstallCommand2(worktreePath);
|
|
11255
11497
|
if (installCmd) {
|
|
11256
11498
|
console.log(`[Daemon] EP986: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
|
|
11257
11499
|
console.log(`[Daemon] EP986: Running: ${installCmd.command.join(" ")}`);
|
|
@@ -11863,8 +12105,8 @@ var Daemon = class _Daemon {
|
|
|
11863
12105
|
await this.shutdown();
|
|
11864
12106
|
try {
|
|
11865
12107
|
const pidPath = getPidFilePath();
|
|
11866
|
-
if (
|
|
11867
|
-
|
|
12108
|
+
if (fs23.existsSync(pidPath)) {
|
|
12109
|
+
fs23.unlinkSync(pidPath);
|
|
11868
12110
|
console.log("[Daemon] PID file cleaned up");
|
|
11869
12111
|
}
|
|
11870
12112
|
} catch (error) {
|