episoda 0.2.105 → 0.2.106
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 +260 -167
- 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 +1 -1
|
@@ -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 fs23 = 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 fs23.access(rebaseMergePath);
|
|
1579
1579
|
inRebase = true;
|
|
1580
1580
|
} catch {
|
|
1581
1581
|
try {
|
|
1582
|
-
await
|
|
1582
|
+
await fs23.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 fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1637
1637
|
try {
|
|
1638
|
-
await
|
|
1638
|
+
await fs23.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 fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1693
1693
|
try {
|
|
1694
|
-
await
|
|
1694
|
+
await fs23.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 fs23.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 fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1864
|
+
const path24 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
1865
1865
|
try {
|
|
1866
|
-
await
|
|
1866
|
+
await fs23.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 = path24.dirname(command.path);
|
|
1876
1876
|
try {
|
|
1877
|
-
await
|
|
1877
|
+
await fs23.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 fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1926
|
+
const path24 = 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 = path24.join(currentPath, ".bare");
|
|
1932
|
+
const episodaDir = path24.join(currentPath, ".episoda");
|
|
1933
1933
|
try {
|
|
1934
|
-
await
|
|
1935
|
-
await
|
|
1934
|
+
await fs23.access(bareDir);
|
|
1935
|
+
await fs23.access(episodaDir);
|
|
1936
1936
|
projectPath = currentPath;
|
|
1937
1937
|
bareRepoPath = bareDir;
|
|
1938
1938
|
break;
|
|
1939
1939
|
} catch {
|
|
1940
|
-
const parentPath =
|
|
1940
|
+
const parentPath = path24.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 fs23 = __importStar(require("fs"));
|
|
2594
|
+
var path24 = __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 || path24.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 path24.join(getConfigDir8(), DEFAULT_CONFIG_FILE);
|
|
2606
2606
|
}
|
|
2607
2607
|
function ensureConfigDir(configPath) {
|
|
2608
|
-
const dir =
|
|
2609
|
-
const isNew = !
|
|
2608
|
+
const dir = path24.dirname(configPath);
|
|
2609
|
+
const isNew = !fs23.existsSync(dir);
|
|
2610
2610
|
if (isNew) {
|
|
2611
|
-
|
|
2611
|
+
fs23.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2612
2612
|
}
|
|
2613
2613
|
if (process.platform === "darwin") {
|
|
2614
|
-
const nosyncPath =
|
|
2615
|
-
if (isNew || !
|
|
2614
|
+
const nosyncPath = path24.join(dir, ".nosync");
|
|
2615
|
+
if (isNew || !fs23.existsSync(nosyncPath)) {
|
|
2616
2616
|
try {
|
|
2617
|
-
|
|
2617
|
+
fs23.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 (fs23.existsSync(fullPath)) {
|
|
2630
2630
|
try {
|
|
2631
|
-
const content =
|
|
2631
|
+
const content = fs23.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 (fs23.existsSync(workspaceConfigPath)) {
|
|
2642
2642
|
try {
|
|
2643
|
-
const content =
|
|
2643
|
+
const content = fs23.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
|
+
fs23.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",
|
|
@@ -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);
|
|
@@ -7730,6 +7736,85 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
7730
7736
|
}
|
|
7731
7737
|
}
|
|
7732
7738
|
|
|
7739
|
+
// src/daemon/handlers/project-handlers.ts
|
|
7740
|
+
var path16 = __toESM(require("path"));
|
|
7741
|
+
var fs15 = __toESM(require("fs"));
|
|
7742
|
+
function validateSlug(slug, fieldName) {
|
|
7743
|
+
if (!slug || typeof slug !== "string") {
|
|
7744
|
+
return `${fieldName} is required`;
|
|
7745
|
+
}
|
|
7746
|
+
const trimmed = slug.trim();
|
|
7747
|
+
if (!trimmed) {
|
|
7748
|
+
return `${fieldName} cannot be empty`;
|
|
7749
|
+
}
|
|
7750
|
+
if (trimmed.includes("..") || trimmed.includes("/") || trimmed.includes("\\")) {
|
|
7751
|
+
return `${fieldName} contains invalid characters`;
|
|
7752
|
+
}
|
|
7753
|
+
if (trimmed.includes("\0")) {
|
|
7754
|
+
return `${fieldName} contains invalid characters`;
|
|
7755
|
+
}
|
|
7756
|
+
if (trimmed.startsWith(".")) {
|
|
7757
|
+
return `${fieldName} cannot start with a dot`;
|
|
7758
|
+
}
|
|
7759
|
+
return null;
|
|
7760
|
+
}
|
|
7761
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7762
|
+
async function handleProjectSetup(params) {
|
|
7763
|
+
const { workspaceSlug, projectSlug, projectId } = params;
|
|
7764
|
+
const workspaceError = validateSlug(workspaceSlug, "workspaceSlug");
|
|
7765
|
+
if (workspaceError) {
|
|
7766
|
+
console.error(`[ProjectSetup] EP1199: Validation failed: ${workspaceError}`);
|
|
7767
|
+
return { success: false, error: workspaceError };
|
|
7768
|
+
}
|
|
7769
|
+
const projectError = validateSlug(projectSlug, "projectSlug");
|
|
7770
|
+
if (projectError) {
|
|
7771
|
+
console.error(`[ProjectSetup] EP1199: Validation failed: ${projectError}`);
|
|
7772
|
+
return { success: false, error: projectError };
|
|
7773
|
+
}
|
|
7774
|
+
if (!UUID_REGEX.test(projectId)) {
|
|
7775
|
+
console.error(`[ProjectSetup] EP1199: Invalid projectId format: ${projectId}`);
|
|
7776
|
+
return { success: false, error: "Invalid projectId format" };
|
|
7777
|
+
}
|
|
7778
|
+
console.log(`[ProjectSetup] EP1199: Setting up project ${workspaceSlug}/${projectSlug}`);
|
|
7779
|
+
try {
|
|
7780
|
+
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
7781
|
+
const artifactsPath = path16.join(projectPath, "artifacts");
|
|
7782
|
+
const configDir = path16.join(projectPath, ".episoda");
|
|
7783
|
+
const configPath = path16.join(configDir, "config.json");
|
|
7784
|
+
await fs15.promises.mkdir(artifactsPath, { recursive: true });
|
|
7785
|
+
await fs15.promises.mkdir(configDir, { recursive: true });
|
|
7786
|
+
let existingConfig = {};
|
|
7787
|
+
try {
|
|
7788
|
+
const existing = await fs15.promises.readFile(configPath, "utf-8");
|
|
7789
|
+
existingConfig = JSON.parse(existing);
|
|
7790
|
+
} catch {
|
|
7791
|
+
}
|
|
7792
|
+
const config = {
|
|
7793
|
+
...existingConfig,
|
|
7794
|
+
project_id: projectId,
|
|
7795
|
+
workspace_slug: workspaceSlug,
|
|
7796
|
+
project_slug: projectSlug,
|
|
7797
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7798
|
+
// Only set created_at if not already present
|
|
7799
|
+
created_at: existingConfig.created_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
7800
|
+
};
|
|
7801
|
+
await fs15.promises.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
7802
|
+
console.log(`[ProjectSetup] EP1199: Project setup complete at ${projectPath}`);
|
|
7803
|
+
return {
|
|
7804
|
+
success: true,
|
|
7805
|
+
projectPath,
|
|
7806
|
+
artifactsPath
|
|
7807
|
+
};
|
|
7808
|
+
} catch (error) {
|
|
7809
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7810
|
+
console.error(`[ProjectSetup] EP1199: Setup failed:`, errorMessage);
|
|
7811
|
+
return {
|
|
7812
|
+
success: false,
|
|
7813
|
+
error: errorMessage
|
|
7814
|
+
};
|
|
7815
|
+
}
|
|
7816
|
+
}
|
|
7817
|
+
|
|
7733
7818
|
// src/daemon/handlers/stale-commit-cleanup.ts
|
|
7734
7819
|
var import_child_process9 = require("child_process");
|
|
7735
7820
|
var import_util2 = require("util");
|
|
@@ -7827,12 +7912,12 @@ async function cleanupStaleCommits(projectPath) {
|
|
|
7827
7912
|
|
|
7828
7913
|
// src/agent/claude-binary.ts
|
|
7829
7914
|
var import_child_process10 = require("child_process");
|
|
7830
|
-
var
|
|
7831
|
-
var
|
|
7915
|
+
var path17 = __toESM(require("path"));
|
|
7916
|
+
var fs16 = __toESM(require("fs"));
|
|
7832
7917
|
var cachedBinaryPath = null;
|
|
7833
7918
|
function isValidClaudeBinary(binaryPath) {
|
|
7834
7919
|
try {
|
|
7835
|
-
|
|
7920
|
+
fs16.accessSync(binaryPath, fs16.constants.X_OK);
|
|
7836
7921
|
const version = (0, import_child_process10.execSync)(`"${binaryPath}" --version`, {
|
|
7837
7922
|
encoding: "utf-8",
|
|
7838
7923
|
timeout: 5e3,
|
|
@@ -7865,14 +7950,14 @@ async function ensureClaudeBinary() {
|
|
|
7865
7950
|
}
|
|
7866
7951
|
const bundledPaths = [
|
|
7867
7952
|
// In production: node_modules/.bin/claude
|
|
7868
|
-
|
|
7953
|
+
path17.join(__dirname, "..", "..", "node_modules", ".bin", "claude"),
|
|
7869
7954
|
// In monorepo development: packages/episoda/node_modules/.bin/claude
|
|
7870
|
-
|
|
7955
|
+
path17.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "claude"),
|
|
7871
7956
|
// Root monorepo node_modules
|
|
7872
|
-
|
|
7957
|
+
path17.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "claude")
|
|
7873
7958
|
];
|
|
7874
7959
|
for (const bundledPath of bundledPaths) {
|
|
7875
|
-
if (
|
|
7960
|
+
if (fs16.existsSync(bundledPath) && isValidClaudeBinary(bundledPath)) {
|
|
7876
7961
|
cachedBinaryPath = bundledPath;
|
|
7877
7962
|
return cachedBinaryPath;
|
|
7878
7963
|
}
|
|
@@ -7898,12 +7983,12 @@ async function ensureClaudeBinary() {
|
|
|
7898
7983
|
|
|
7899
7984
|
// src/agent/codex-binary.ts
|
|
7900
7985
|
var import_child_process11 = require("child_process");
|
|
7901
|
-
var
|
|
7902
|
-
var
|
|
7986
|
+
var path18 = __toESM(require("path"));
|
|
7987
|
+
var fs17 = __toESM(require("fs"));
|
|
7903
7988
|
var cachedBinaryPath2 = null;
|
|
7904
7989
|
function isValidCodexBinary(binaryPath) {
|
|
7905
7990
|
try {
|
|
7906
|
-
|
|
7991
|
+
fs17.accessSync(binaryPath, fs17.constants.X_OK);
|
|
7907
7992
|
const version = (0, import_child_process11.execSync)(`"${binaryPath}" --version`, {
|
|
7908
7993
|
encoding: "utf-8",
|
|
7909
7994
|
timeout: 5e3,
|
|
@@ -7936,14 +8021,14 @@ async function ensureCodexBinary() {
|
|
|
7936
8021
|
}
|
|
7937
8022
|
const bundledPaths = [
|
|
7938
8023
|
// In production: node_modules/.bin/codex
|
|
7939
|
-
|
|
8024
|
+
path18.join(__dirname, "..", "..", "node_modules", ".bin", "codex"),
|
|
7940
8025
|
// In monorepo development: packages/episoda/node_modules/.bin/codex
|
|
7941
|
-
|
|
8026
|
+
path18.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "codex"),
|
|
7942
8027
|
// Root monorepo node_modules
|
|
7943
|
-
|
|
8028
|
+
path18.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "codex")
|
|
7944
8029
|
];
|
|
7945
8030
|
for (const bundledPath of bundledPaths) {
|
|
7946
|
-
if (
|
|
8031
|
+
if (fs17.existsSync(bundledPath) && isValidCodexBinary(bundledPath)) {
|
|
7947
8032
|
cachedBinaryPath2 = bundledPath;
|
|
7948
8033
|
return cachedBinaryPath2;
|
|
7949
8034
|
}
|
|
@@ -8010,8 +8095,8 @@ function generateCodexConfig(credentials, projectPath) {
|
|
|
8010
8095
|
|
|
8011
8096
|
// src/agent/agent-manager.ts
|
|
8012
8097
|
var import_child_process12 = require("child_process");
|
|
8013
|
-
var
|
|
8014
|
-
var
|
|
8098
|
+
var path19 = __toESM(require("path"));
|
|
8099
|
+
var fs18 = __toESM(require("fs"));
|
|
8015
8100
|
var os6 = __toESM(require("os"));
|
|
8016
8101
|
|
|
8017
8102
|
// src/agent/claude-config.ts
|
|
@@ -8334,7 +8419,7 @@ var AgentManager = class {
|
|
|
8334
8419
|
this.initialized = false;
|
|
8335
8420
|
// EP1133: Lock for config file writes to prevent race conditions
|
|
8336
8421
|
this.configWriteLock = Promise.resolve();
|
|
8337
|
-
this.pidDir =
|
|
8422
|
+
this.pidDir = path19.join(os6.homedir(), ".episoda", "agent-pids");
|
|
8338
8423
|
}
|
|
8339
8424
|
/**
|
|
8340
8425
|
* EP1133: Acquire lock for config file writes
|
|
@@ -8363,8 +8448,8 @@ var AgentManager = class {
|
|
|
8363
8448
|
return;
|
|
8364
8449
|
}
|
|
8365
8450
|
console.log("[AgentManager] Initializing...");
|
|
8366
|
-
if (!
|
|
8367
|
-
|
|
8451
|
+
if (!fs18.existsSync(this.pidDir)) {
|
|
8452
|
+
fs18.mkdirSync(this.pidDir, { recursive: true });
|
|
8368
8453
|
}
|
|
8369
8454
|
await this.cleanupOrphanedProcesses();
|
|
8370
8455
|
try {
|
|
@@ -8611,9 +8696,9 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8611
8696
|
const useApiKey = !useOAuth && !!session.credentials.apiKey;
|
|
8612
8697
|
if (provider === "codex") {
|
|
8613
8698
|
await this.withConfigLock(async () => {
|
|
8614
|
-
const codexDir =
|
|
8615
|
-
if (!
|
|
8616
|
-
|
|
8699
|
+
const codexDir = path19.join(os6.homedir(), ".codex");
|
|
8700
|
+
if (!fs18.existsSync(codexDir)) {
|
|
8701
|
+
fs18.mkdirSync(codexDir, { recursive: true });
|
|
8617
8702
|
}
|
|
8618
8703
|
if (useOAuth) {
|
|
8619
8704
|
const codexConfig = generateCodexConfig({
|
|
@@ -8623,21 +8708,21 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8623
8708
|
accountId: session.credentials.accountId,
|
|
8624
8709
|
expiresAt: session.credentials.expiresAt
|
|
8625
8710
|
}, session.projectPath);
|
|
8626
|
-
const authJsonPath =
|
|
8627
|
-
|
|
8711
|
+
const authJsonPath = path19.join(codexDir, "auth.json");
|
|
8712
|
+
fs18.writeFileSync(authJsonPath, codexConfig["auth.json"], { mode: 384 });
|
|
8628
8713
|
console.log("[AgentManager] EP1133: Wrote Codex auth.json to ~/.codex/auth.json");
|
|
8629
8714
|
if (codexConfig["config.toml"]) {
|
|
8630
|
-
const configTomlPath =
|
|
8715
|
+
const configTomlPath = path19.join(codexDir, "config.toml");
|
|
8631
8716
|
let existingConfig = "";
|
|
8632
8717
|
try {
|
|
8633
|
-
existingConfig =
|
|
8718
|
+
existingConfig = fs18.readFileSync(configTomlPath, "utf-8");
|
|
8634
8719
|
} catch {
|
|
8635
8720
|
}
|
|
8636
8721
|
const escapedPathForRegex = session.projectPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8637
8722
|
const projectKeyPattern = new RegExp(`\\[projects\\."${escapedPathForRegex}"\\]`);
|
|
8638
8723
|
const projectAlreadyTrusted = projectKeyPattern.test(existingConfig);
|
|
8639
8724
|
if (!projectAlreadyTrusted) {
|
|
8640
|
-
|
|
8725
|
+
fs18.writeFileSync(configTomlPath, existingConfig + "\n" + codexConfig["config.toml"], { mode: 420 });
|
|
8641
8726
|
console.log("[AgentManager] EP1133: Updated Codex config.toml with project trust");
|
|
8642
8727
|
}
|
|
8643
8728
|
}
|
|
@@ -8647,14 +8732,14 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8647
8732
|
});
|
|
8648
8733
|
} else {
|
|
8649
8734
|
await this.withConfigLock(async () => {
|
|
8650
|
-
const claudeDir =
|
|
8651
|
-
const credentialsPath =
|
|
8652
|
-
const statsigDir =
|
|
8653
|
-
if (!
|
|
8654
|
-
|
|
8735
|
+
const claudeDir = path19.join(os6.homedir(), ".claude");
|
|
8736
|
+
const credentialsPath = path19.join(claudeDir, ".credentials.json");
|
|
8737
|
+
const statsigDir = path19.join(claudeDir, "statsig");
|
|
8738
|
+
if (!fs18.existsSync(claudeDir)) {
|
|
8739
|
+
fs18.mkdirSync(claudeDir, { recursive: true });
|
|
8655
8740
|
}
|
|
8656
|
-
if (!
|
|
8657
|
-
|
|
8741
|
+
if (!fs18.existsSync(statsigDir)) {
|
|
8742
|
+
fs18.mkdirSync(statsigDir, { recursive: true });
|
|
8658
8743
|
}
|
|
8659
8744
|
if (useOAuth) {
|
|
8660
8745
|
const oauthCredentials = {
|
|
@@ -8672,7 +8757,7 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8672
8757
|
const credentialsContent = JSON.stringify({
|
|
8673
8758
|
claudeAiOauth: oauthCredentials
|
|
8674
8759
|
}, null, 2);
|
|
8675
|
-
|
|
8760
|
+
fs18.writeFileSync(credentialsPath, credentialsContent, { mode: 384 });
|
|
8676
8761
|
console.log("[AgentManager] Wrote OAuth credentials to ~/.claude/.credentials.json");
|
|
8677
8762
|
try {
|
|
8678
8763
|
const claudeConfig = generateClaudeConfig({
|
|
@@ -8684,11 +8769,11 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8684
8769
|
if (!hasEvaluations || !hasStableId) {
|
|
8685
8770
|
throw new Error(`Invalid statsig config: missing required files`);
|
|
8686
8771
|
}
|
|
8687
|
-
const settingsPath =
|
|
8688
|
-
|
|
8772
|
+
const settingsPath = path19.join(claudeDir, "settings.json");
|
|
8773
|
+
fs18.writeFileSync(settingsPath, claudeConfig["settings.json"], { mode: 384 });
|
|
8689
8774
|
for (const [filename, content] of Object.entries(claudeConfig.statsig)) {
|
|
8690
|
-
const filePath =
|
|
8691
|
-
|
|
8775
|
+
const filePath = path19.join(statsigDir, filename);
|
|
8776
|
+
fs18.writeFileSync(filePath, content, { mode: 420 });
|
|
8692
8777
|
}
|
|
8693
8778
|
if (session.credentials.githubToken) {
|
|
8694
8779
|
console.log("[AgentManager] EP1146: GitHub MCP server enabled with installation token");
|
|
@@ -8958,14 +9043,14 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8958
9043
|
*/
|
|
8959
9044
|
async cleanupOrphanedProcesses() {
|
|
8960
9045
|
let cleaned = 0;
|
|
8961
|
-
if (!
|
|
9046
|
+
if (!fs18.existsSync(this.pidDir)) {
|
|
8962
9047
|
return { cleaned };
|
|
8963
9048
|
}
|
|
8964
|
-
const pidFiles =
|
|
9049
|
+
const pidFiles = fs18.readdirSync(this.pidDir).filter((f) => f.endsWith(".pid"));
|
|
8965
9050
|
for (const pidFile of pidFiles) {
|
|
8966
|
-
const pidPath =
|
|
9051
|
+
const pidPath = path19.join(this.pidDir, pidFile);
|
|
8967
9052
|
try {
|
|
8968
|
-
const pidStr =
|
|
9053
|
+
const pidStr = fs18.readFileSync(pidPath, "utf-8").trim();
|
|
8969
9054
|
const pid = parseInt(pidStr, 10);
|
|
8970
9055
|
if (!isNaN(pid)) {
|
|
8971
9056
|
try {
|
|
@@ -8976,7 +9061,7 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8976
9061
|
} catch {
|
|
8977
9062
|
}
|
|
8978
9063
|
}
|
|
8979
|
-
|
|
9064
|
+
fs18.unlinkSync(pidPath);
|
|
8980
9065
|
} catch (error) {
|
|
8981
9066
|
console.warn(`[AgentManager] Error cleaning PID file ${pidFile}:`, error);
|
|
8982
9067
|
}
|
|
@@ -8990,17 +9075,17 @@ If changes are needed, explain what needs to be done.`;
|
|
|
8990
9075
|
* Write PID file for session tracking
|
|
8991
9076
|
*/
|
|
8992
9077
|
writePidFile(sessionId, pid) {
|
|
8993
|
-
const pidPath =
|
|
8994
|
-
|
|
9078
|
+
const pidPath = path19.join(this.pidDir, `${sessionId}.pid`);
|
|
9079
|
+
fs18.writeFileSync(pidPath, pid.toString());
|
|
8995
9080
|
}
|
|
8996
9081
|
/**
|
|
8997
9082
|
* Remove PID file for session
|
|
8998
9083
|
*/
|
|
8999
9084
|
removePidFile(sessionId) {
|
|
9000
|
-
const pidPath =
|
|
9085
|
+
const pidPath = path19.join(this.pidDir, `${sessionId}.pid`);
|
|
9001
9086
|
try {
|
|
9002
|
-
if (
|
|
9003
|
-
|
|
9087
|
+
if (fs18.existsSync(pidPath)) {
|
|
9088
|
+
fs18.unlinkSync(pidPath);
|
|
9004
9089
|
}
|
|
9005
9090
|
} catch {
|
|
9006
9091
|
}
|
|
@@ -9010,8 +9095,8 @@ If changes are needed, explain what needs to be done.`;
|
|
|
9010
9095
|
// src/utils/dev-server.ts
|
|
9011
9096
|
var import_child_process13 = require("child_process");
|
|
9012
9097
|
var import_core11 = __toESM(require_dist());
|
|
9013
|
-
var
|
|
9014
|
-
var
|
|
9098
|
+
var fs19 = __toESM(require("fs"));
|
|
9099
|
+
var path20 = __toESM(require("path"));
|
|
9015
9100
|
var MAX_RESTART_ATTEMPTS = 5;
|
|
9016
9101
|
var INITIAL_RESTART_DELAY_MS = 2e3;
|
|
9017
9102
|
var MAX_RESTART_DELAY_MS = 3e4;
|
|
@@ -9019,26 +9104,26 @@ var MAX_LOG_SIZE_BYTES = 5 * 1024 * 1024;
|
|
|
9019
9104
|
var NODE_MEMORY_LIMIT_MB = 2048;
|
|
9020
9105
|
var activeServers = /* @__PURE__ */ new Map();
|
|
9021
9106
|
function getLogsDir() {
|
|
9022
|
-
const logsDir =
|
|
9023
|
-
if (!
|
|
9024
|
-
|
|
9107
|
+
const logsDir = path20.join((0, import_core11.getConfigDir)(), "logs");
|
|
9108
|
+
if (!fs19.existsSync(logsDir)) {
|
|
9109
|
+
fs19.mkdirSync(logsDir, { recursive: true });
|
|
9025
9110
|
}
|
|
9026
9111
|
return logsDir;
|
|
9027
9112
|
}
|
|
9028
9113
|
function getLogFilePath(moduleUid) {
|
|
9029
|
-
return
|
|
9114
|
+
return path20.join(getLogsDir(), `dev-${moduleUid}.log`);
|
|
9030
9115
|
}
|
|
9031
9116
|
function rotateLogIfNeeded(logPath) {
|
|
9032
9117
|
try {
|
|
9033
|
-
if (
|
|
9034
|
-
const stats =
|
|
9118
|
+
if (fs19.existsSync(logPath)) {
|
|
9119
|
+
const stats = fs19.statSync(logPath);
|
|
9035
9120
|
if (stats.size > MAX_LOG_SIZE_BYTES) {
|
|
9036
9121
|
const backupPath = `${logPath}.1`;
|
|
9037
|
-
if (
|
|
9038
|
-
|
|
9122
|
+
if (fs19.existsSync(backupPath)) {
|
|
9123
|
+
fs19.unlinkSync(backupPath);
|
|
9039
9124
|
}
|
|
9040
|
-
|
|
9041
|
-
console.log(`[DevServer] EP932: Rotated log file for ${
|
|
9125
|
+
fs19.renameSync(logPath, backupPath);
|
|
9126
|
+
console.log(`[DevServer] EP932: Rotated log file for ${path20.basename(logPath)}`);
|
|
9042
9127
|
}
|
|
9043
9128
|
}
|
|
9044
9129
|
} catch (error) {
|
|
@@ -9051,7 +9136,7 @@ function writeToLog(logPath, line, isError = false) {
|
|
|
9051
9136
|
const prefix = isError ? "ERR" : "OUT";
|
|
9052
9137
|
const logLine = `[${timestamp}] [${prefix}] ${line}
|
|
9053
9138
|
`;
|
|
9054
|
-
|
|
9139
|
+
fs19.appendFileSync(logPath, logLine);
|
|
9055
9140
|
} catch {
|
|
9056
9141
|
}
|
|
9057
9142
|
}
|
|
@@ -9230,8 +9315,8 @@ async function startDevServer(projectPath, port = 3e3, moduleUid = "default", op
|
|
|
9230
9315
|
});
|
|
9231
9316
|
injectedEnvVars = result.envVars;
|
|
9232
9317
|
console.log(`[DevServer] EP998: Loaded ${Object.keys(injectedEnvVars).length} env vars (from ${result.fromCache ? "cache" : "server"})`);
|
|
9233
|
-
const envFilePath =
|
|
9234
|
-
if (!
|
|
9318
|
+
const envFilePath = path20.join(projectPath, ".env");
|
|
9319
|
+
if (!fs19.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
|
|
9235
9320
|
console.log(`[DevServer] EP1004: .env file missing, writing ${Object.keys(injectedEnvVars).length} vars to ${envFilePath}`);
|
|
9236
9321
|
writeEnvFile(projectPath, injectedEnvVars);
|
|
9237
9322
|
}
|
|
@@ -9337,19 +9422,19 @@ function getDevServerStatus() {
|
|
|
9337
9422
|
}
|
|
9338
9423
|
|
|
9339
9424
|
// src/utils/worktree.ts
|
|
9340
|
-
var
|
|
9341
|
-
var
|
|
9425
|
+
var path21 = __toESM(require("path"));
|
|
9426
|
+
var fs20 = __toESM(require("fs"));
|
|
9342
9427
|
var os7 = __toESM(require("os"));
|
|
9343
9428
|
var import_core12 = __toESM(require_dist());
|
|
9344
9429
|
function getEpisodaRoot2() {
|
|
9345
|
-
return process.env.EPISODA_ROOT ||
|
|
9430
|
+
return process.env.EPISODA_ROOT || path21.join(os7.homedir(), "episoda");
|
|
9346
9431
|
}
|
|
9347
9432
|
function getWorktreeInfo(moduleUid, workspaceSlug, projectSlug) {
|
|
9348
9433
|
const root = getEpisodaRoot2();
|
|
9349
|
-
const worktreePath =
|
|
9434
|
+
const worktreePath = path21.join(root, workspaceSlug, projectSlug, moduleUid);
|
|
9350
9435
|
return {
|
|
9351
9436
|
path: worktreePath,
|
|
9352
|
-
exists:
|
|
9437
|
+
exists: fs20.existsSync(worktreePath),
|
|
9353
9438
|
moduleUid
|
|
9354
9439
|
};
|
|
9355
9440
|
}
|
|
@@ -9363,15 +9448,15 @@ async function getWorktreeInfoForModule(moduleUid) {
|
|
|
9363
9448
|
return null;
|
|
9364
9449
|
}
|
|
9365
9450
|
const root = getEpisodaRoot2();
|
|
9366
|
-
const workspaceRoot =
|
|
9451
|
+
const workspaceRoot = path21.join(root, config.workspace_slug);
|
|
9367
9452
|
try {
|
|
9368
|
-
const entries =
|
|
9453
|
+
const entries = fs20.readdirSync(workspaceRoot, { withFileTypes: true });
|
|
9369
9454
|
for (const entry of entries) {
|
|
9370
9455
|
if (!entry.isDirectory()) {
|
|
9371
9456
|
continue;
|
|
9372
9457
|
}
|
|
9373
|
-
const worktreePath =
|
|
9374
|
-
if (
|
|
9458
|
+
const worktreePath = path21.join(workspaceRoot, entry.name, moduleUid);
|
|
9459
|
+
if (fs20.existsSync(worktreePath)) {
|
|
9375
9460
|
return {
|
|
9376
9461
|
path: worktreePath,
|
|
9377
9462
|
exists: true,
|
|
@@ -9388,61 +9473,61 @@ async function getWorktreeInfoForModule(moduleUid) {
|
|
|
9388
9473
|
}
|
|
9389
9474
|
|
|
9390
9475
|
// src/framework-detector.ts
|
|
9391
|
-
var
|
|
9392
|
-
var
|
|
9476
|
+
var fs21 = __toESM(require("fs"));
|
|
9477
|
+
var path22 = __toESM(require("path"));
|
|
9393
9478
|
function getInstallCommand(cwd) {
|
|
9394
|
-
if (
|
|
9479
|
+
if (fs21.existsSync(path22.join(cwd, "bun.lockb"))) {
|
|
9395
9480
|
return {
|
|
9396
9481
|
command: ["bun", "install"],
|
|
9397
9482
|
description: "Installing dependencies with bun",
|
|
9398
9483
|
detectedFrom: "bun.lockb"
|
|
9399
9484
|
};
|
|
9400
9485
|
}
|
|
9401
|
-
if (
|
|
9486
|
+
if (fs21.existsSync(path22.join(cwd, "pnpm-lock.yaml"))) {
|
|
9402
9487
|
return {
|
|
9403
9488
|
command: ["pnpm", "install"],
|
|
9404
9489
|
description: "Installing dependencies with pnpm",
|
|
9405
9490
|
detectedFrom: "pnpm-lock.yaml"
|
|
9406
9491
|
};
|
|
9407
9492
|
}
|
|
9408
|
-
if (
|
|
9493
|
+
if (fs21.existsSync(path22.join(cwd, "yarn.lock"))) {
|
|
9409
9494
|
return {
|
|
9410
9495
|
command: ["yarn", "install"],
|
|
9411
9496
|
description: "Installing dependencies with yarn",
|
|
9412
9497
|
detectedFrom: "yarn.lock"
|
|
9413
9498
|
};
|
|
9414
9499
|
}
|
|
9415
|
-
if (
|
|
9500
|
+
if (fs21.existsSync(path22.join(cwd, "package-lock.json"))) {
|
|
9416
9501
|
return {
|
|
9417
9502
|
command: ["npm", "ci"],
|
|
9418
9503
|
description: "Installing dependencies with npm ci",
|
|
9419
9504
|
detectedFrom: "package-lock.json"
|
|
9420
9505
|
};
|
|
9421
9506
|
}
|
|
9422
|
-
if (
|
|
9507
|
+
if (fs21.existsSync(path22.join(cwd, "package.json"))) {
|
|
9423
9508
|
return {
|
|
9424
9509
|
command: ["npm", "install"],
|
|
9425
9510
|
description: "Installing dependencies with npm",
|
|
9426
9511
|
detectedFrom: "package.json"
|
|
9427
9512
|
};
|
|
9428
9513
|
}
|
|
9429
|
-
if (
|
|
9514
|
+
if (fs21.existsSync(path22.join(cwd, "Pipfile.lock")) || fs21.existsSync(path22.join(cwd, "Pipfile"))) {
|
|
9430
9515
|
return {
|
|
9431
9516
|
command: ["pipenv", "install"],
|
|
9432
9517
|
description: "Installing dependencies with pipenv",
|
|
9433
|
-
detectedFrom:
|
|
9518
|
+
detectedFrom: fs21.existsSync(path22.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
|
|
9434
9519
|
};
|
|
9435
9520
|
}
|
|
9436
|
-
if (
|
|
9521
|
+
if (fs21.existsSync(path22.join(cwd, "poetry.lock"))) {
|
|
9437
9522
|
return {
|
|
9438
9523
|
command: ["poetry", "install"],
|
|
9439
9524
|
description: "Installing dependencies with poetry",
|
|
9440
9525
|
detectedFrom: "poetry.lock"
|
|
9441
9526
|
};
|
|
9442
9527
|
}
|
|
9443
|
-
if (
|
|
9444
|
-
const pyprojectPath =
|
|
9445
|
-
const content =
|
|
9528
|
+
if (fs21.existsSync(path22.join(cwd, "pyproject.toml"))) {
|
|
9529
|
+
const pyprojectPath = path22.join(cwd, "pyproject.toml");
|
|
9530
|
+
const content = fs21.readFileSync(pyprojectPath, "utf-8");
|
|
9446
9531
|
if (content.includes("[tool.poetry]")) {
|
|
9447
9532
|
return {
|
|
9448
9533
|
command: ["poetry", "install"],
|
|
@@ -9451,42 +9536,42 @@ function getInstallCommand(cwd) {
|
|
|
9451
9536
|
};
|
|
9452
9537
|
}
|
|
9453
9538
|
}
|
|
9454
|
-
if (
|
|
9539
|
+
if (fs21.existsSync(path22.join(cwd, "requirements.txt"))) {
|
|
9455
9540
|
return {
|
|
9456
9541
|
command: ["pip", "install", "-r", "requirements.txt"],
|
|
9457
9542
|
description: "Installing dependencies with pip",
|
|
9458
9543
|
detectedFrom: "requirements.txt"
|
|
9459
9544
|
};
|
|
9460
9545
|
}
|
|
9461
|
-
if (
|
|
9546
|
+
if (fs21.existsSync(path22.join(cwd, "Gemfile.lock")) || fs21.existsSync(path22.join(cwd, "Gemfile"))) {
|
|
9462
9547
|
return {
|
|
9463
9548
|
command: ["bundle", "install"],
|
|
9464
9549
|
description: "Installing dependencies with bundler",
|
|
9465
|
-
detectedFrom:
|
|
9550
|
+
detectedFrom: fs21.existsSync(path22.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
|
|
9466
9551
|
};
|
|
9467
9552
|
}
|
|
9468
|
-
if (
|
|
9553
|
+
if (fs21.existsSync(path22.join(cwd, "go.sum")) || fs21.existsSync(path22.join(cwd, "go.mod"))) {
|
|
9469
9554
|
return {
|
|
9470
9555
|
command: ["go", "mod", "download"],
|
|
9471
9556
|
description: "Downloading Go modules",
|
|
9472
|
-
detectedFrom:
|
|
9557
|
+
detectedFrom: fs21.existsSync(path22.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
|
|
9473
9558
|
};
|
|
9474
9559
|
}
|
|
9475
|
-
if (
|
|
9560
|
+
if (fs21.existsSync(path22.join(cwd, "Cargo.lock")) || fs21.existsSync(path22.join(cwd, "Cargo.toml"))) {
|
|
9476
9561
|
return {
|
|
9477
9562
|
command: ["cargo", "build"],
|
|
9478
9563
|
description: "Building Rust project (downloads dependencies)",
|
|
9479
|
-
detectedFrom:
|
|
9564
|
+
detectedFrom: fs21.existsSync(path22.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
|
|
9480
9565
|
};
|
|
9481
9566
|
}
|
|
9482
9567
|
return null;
|
|
9483
9568
|
}
|
|
9484
9569
|
|
|
9485
9570
|
// src/daemon/daemon-process.ts
|
|
9486
|
-
var
|
|
9571
|
+
var fs22 = __toESM(require("fs"));
|
|
9487
9572
|
var http2 = __toESM(require("http"));
|
|
9488
9573
|
var os8 = __toESM(require("os"));
|
|
9489
|
-
var
|
|
9574
|
+
var path23 = __toESM(require("path"));
|
|
9490
9575
|
var packageJson = require_package();
|
|
9491
9576
|
async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
|
|
9492
9577
|
const now = Date.now();
|
|
@@ -9707,9 +9792,9 @@ var Daemon = class _Daemon {
|
|
|
9707
9792
|
this.healthServer = http2.createServer((req, res) => {
|
|
9708
9793
|
if (req.url === "/health" || req.url === "/") {
|
|
9709
9794
|
const isConnected = this.liveConnections.size > 0;
|
|
9710
|
-
const projects = Array.from(this.connections.entries()).map(([
|
|
9711
|
-
path:
|
|
9712
|
-
connected: this.liveConnections.has(
|
|
9795
|
+
const projects = Array.from(this.connections.entries()).map(([path24, conn]) => ({
|
|
9796
|
+
path: path24,
|
|
9797
|
+
connected: this.liveConnections.has(path24)
|
|
9713
9798
|
}));
|
|
9714
9799
|
const status = {
|
|
9715
9800
|
status: isConnected ? "healthy" : "degraded",
|
|
@@ -9939,9 +10024,12 @@ var Daemon = class _Daemon {
|
|
|
9939
10024
|
this.ipcServer.on("worktree-list", async (params) => {
|
|
9940
10025
|
return handleWorktreeList(params.workspaceSlug, params.projectSlug);
|
|
9941
10026
|
});
|
|
9942
|
-
this.ipcServer.on("project
|
|
10027
|
+
this.ipcServer.on("project:eject", async (params) => {
|
|
9943
10028
|
return handleProjectEject(params);
|
|
9944
10029
|
});
|
|
10030
|
+
this.ipcServer.on("project:setup", async (params) => {
|
|
10031
|
+
return handleProjectSetup(params);
|
|
10032
|
+
});
|
|
9945
10033
|
}
|
|
9946
10034
|
/**
|
|
9947
10035
|
* Restore WebSocket connections for tracked projects
|
|
@@ -10074,7 +10162,7 @@ var Daemon = class _Daemon {
|
|
|
10074
10162
|
client.updateActivity();
|
|
10075
10163
|
try {
|
|
10076
10164
|
const gitCmd = message.command;
|
|
10077
|
-
const bareRepoPath =
|
|
10165
|
+
const bareRepoPath = path23.join(projectPath, ".bare");
|
|
10078
10166
|
const cwd = gitCmd.worktreePath || bareRepoPath;
|
|
10079
10167
|
if (gitCmd.worktreePath) {
|
|
10080
10168
|
console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
|
|
@@ -10188,9 +10276,14 @@ var Daemon = class _Daemon {
|
|
|
10188
10276
|
);
|
|
10189
10277
|
break;
|
|
10190
10278
|
// EP1144: Project ejection for Tier 1 cleanup
|
|
10191
|
-
|
|
10279
|
+
// EP1199: Renamed from eject_project to project:eject for naming consistency
|
|
10280
|
+
case "project:eject":
|
|
10192
10281
|
result = await handleProjectEject(cmd);
|
|
10193
10282
|
break;
|
|
10283
|
+
// EP1199: Project setup for cloud containers
|
|
10284
|
+
case "project:setup":
|
|
10285
|
+
result = await handleProjectSetup(cmd);
|
|
10286
|
+
break;
|
|
10194
10287
|
default:
|
|
10195
10288
|
result = {
|
|
10196
10289
|
success: false,
|
|
@@ -10654,8 +10747,8 @@ var Daemon = class _Daemon {
|
|
|
10654
10747
|
let daemonPid;
|
|
10655
10748
|
try {
|
|
10656
10749
|
const pidPath = getPidFilePath();
|
|
10657
|
-
if (
|
|
10658
|
-
const pidStr =
|
|
10750
|
+
if (fs22.existsSync(pidPath)) {
|
|
10751
|
+
const pidStr = fs22.readFileSync(pidPath, "utf-8").trim();
|
|
10659
10752
|
daemonPid = parseInt(pidStr, 10);
|
|
10660
10753
|
}
|
|
10661
10754
|
} catch (pidError) {
|
|
@@ -10736,28 +10829,28 @@ var Daemon = class _Daemon {
|
|
|
10736
10829
|
* - workDir: The directory to run git commands in (cwd)
|
|
10737
10830
|
*/
|
|
10738
10831
|
getGitDirs(projectPath) {
|
|
10739
|
-
const bareDir =
|
|
10740
|
-
const gitPath =
|
|
10741
|
-
if (
|
|
10832
|
+
const bareDir = path23.join(projectPath, ".bare");
|
|
10833
|
+
const gitPath = path23.join(projectPath, ".git");
|
|
10834
|
+
if (fs22.existsSync(bareDir) && fs22.statSync(bareDir).isDirectory()) {
|
|
10742
10835
|
return { gitDir: bareDir, workDir: projectPath };
|
|
10743
10836
|
}
|
|
10744
|
-
if (
|
|
10837
|
+
if (fs22.existsSync(gitPath) && fs22.statSync(gitPath).isDirectory()) {
|
|
10745
10838
|
return { gitDir: null, workDir: projectPath };
|
|
10746
10839
|
}
|
|
10747
|
-
if (
|
|
10840
|
+
if (fs22.existsSync(gitPath) && fs22.statSync(gitPath).isFile()) {
|
|
10748
10841
|
return { gitDir: null, workDir: projectPath };
|
|
10749
10842
|
}
|
|
10750
|
-
const entries =
|
|
10843
|
+
const entries = fs22.readdirSync(projectPath, { withFileTypes: true });
|
|
10751
10844
|
for (const entry of entries) {
|
|
10752
10845
|
if (entry.isDirectory() && entry.name.startsWith("EP")) {
|
|
10753
|
-
const worktreePath =
|
|
10754
|
-
const worktreeGit =
|
|
10755
|
-
if (
|
|
10846
|
+
const worktreePath = path23.join(projectPath, entry.name);
|
|
10847
|
+
const worktreeGit = path23.join(worktreePath, ".git");
|
|
10848
|
+
if (fs22.existsSync(worktreeGit)) {
|
|
10756
10849
|
return { gitDir: null, workDir: worktreePath };
|
|
10757
10850
|
}
|
|
10758
10851
|
}
|
|
10759
10852
|
}
|
|
10760
|
-
if (
|
|
10853
|
+
if (fs22.existsSync(bareDir)) {
|
|
10761
10854
|
return { gitDir: bareDir, workDir: projectPath };
|
|
10762
10855
|
}
|
|
10763
10856
|
return { gitDir: null, workDir: projectPath };
|
|
@@ -10821,24 +10914,24 @@ var Daemon = class _Daemon {
|
|
|
10821
10914
|
async installGitHooks(projectPath) {
|
|
10822
10915
|
const hooks = ["post-checkout", "pre-commit", "post-commit"];
|
|
10823
10916
|
let hooksDir;
|
|
10824
|
-
const bareHooksDir =
|
|
10825
|
-
const gitHooksDir =
|
|
10826
|
-
if (
|
|
10917
|
+
const bareHooksDir = path23.join(projectPath, ".bare", "hooks");
|
|
10918
|
+
const gitHooksDir = path23.join(projectPath, ".git", "hooks");
|
|
10919
|
+
if (fs22.existsSync(bareHooksDir)) {
|
|
10827
10920
|
hooksDir = bareHooksDir;
|
|
10828
|
-
} else if (
|
|
10921
|
+
} else if (fs22.existsSync(gitHooksDir) && fs22.statSync(path23.join(projectPath, ".git")).isDirectory()) {
|
|
10829
10922
|
hooksDir = gitHooksDir;
|
|
10830
10923
|
} else {
|
|
10831
|
-
const parentBareHooks =
|
|
10832
|
-
if (
|
|
10924
|
+
const parentBareHooks = path23.join(projectPath, "..", ".bare", "hooks");
|
|
10925
|
+
if (fs22.existsSync(parentBareHooks)) {
|
|
10833
10926
|
hooksDir = parentBareHooks;
|
|
10834
10927
|
} else {
|
|
10835
10928
|
console.warn(`[Daemon] Hooks directory not found for: ${projectPath}`);
|
|
10836
10929
|
return;
|
|
10837
10930
|
}
|
|
10838
10931
|
}
|
|
10839
|
-
if (!
|
|
10932
|
+
if (!fs22.existsSync(hooksDir)) {
|
|
10840
10933
|
try {
|
|
10841
|
-
|
|
10934
|
+
fs22.mkdirSync(hooksDir, { recursive: true });
|
|
10842
10935
|
} catch (error) {
|
|
10843
10936
|
console.warn(`[Daemon] Hooks directory not found and could not create: ${hooksDir}`);
|
|
10844
10937
|
return;
|
|
@@ -10846,20 +10939,20 @@ var Daemon = class _Daemon {
|
|
|
10846
10939
|
}
|
|
10847
10940
|
for (const hookName of hooks) {
|
|
10848
10941
|
try {
|
|
10849
|
-
const hookPath =
|
|
10850
|
-
const bundledHookPath =
|
|
10851
|
-
if (!
|
|
10942
|
+
const hookPath = path23.join(hooksDir, hookName);
|
|
10943
|
+
const bundledHookPath = path23.join(__dirname, "..", "hooks", hookName);
|
|
10944
|
+
if (!fs22.existsSync(bundledHookPath)) {
|
|
10852
10945
|
console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
|
|
10853
10946
|
continue;
|
|
10854
10947
|
}
|
|
10855
|
-
const hookContent =
|
|
10856
|
-
if (
|
|
10857
|
-
const existingContent =
|
|
10948
|
+
const hookContent = fs22.readFileSync(bundledHookPath, "utf-8");
|
|
10949
|
+
if (fs22.existsSync(hookPath)) {
|
|
10950
|
+
const existingContent = fs22.readFileSync(hookPath, "utf-8");
|
|
10858
10951
|
if (existingContent === hookContent) {
|
|
10859
10952
|
continue;
|
|
10860
10953
|
}
|
|
10861
10954
|
}
|
|
10862
|
-
|
|
10955
|
+
fs22.writeFileSync(hookPath, hookContent, { mode: 493 });
|
|
10863
10956
|
console.log(`[Daemon] Installed git hook: ${hookName}`);
|
|
10864
10957
|
} catch (error) {
|
|
10865
10958
|
console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
|
|
@@ -11863,8 +11956,8 @@ var Daemon = class _Daemon {
|
|
|
11863
11956
|
await this.shutdown();
|
|
11864
11957
|
try {
|
|
11865
11958
|
const pidPath = getPidFilePath();
|
|
11866
|
-
if (
|
|
11867
|
-
|
|
11959
|
+
if (fs22.existsSync(pidPath)) {
|
|
11960
|
+
fs22.unlinkSync(pidPath);
|
|
11868
11961
|
console.log("[Daemon] PID file cleaned up");
|
|
11869
11962
|
}
|
|
11870
11963
|
} catch (error) {
|