@episoda/cli 0.2.164 → 0.2.166
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.
|
@@ -1640,15 +1640,15 @@ var require_git_executor = __commonJS({
|
|
|
1640
1640
|
try {
|
|
1641
1641
|
const { stdout: gitDir } = await execAsync3("git rev-parse --git-dir", { cwd, timeout: 5e3 });
|
|
1642
1642
|
const gitDirPath = gitDir.trim();
|
|
1643
|
-
const
|
|
1643
|
+
const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1644
1644
|
const rebaseMergePath = `${gitDirPath}/rebase-merge`;
|
|
1645
1645
|
const rebaseApplyPath = `${gitDirPath}/rebase-apply`;
|
|
1646
1646
|
try {
|
|
1647
|
-
await
|
|
1647
|
+
await fs30.access(rebaseMergePath);
|
|
1648
1648
|
inRebase = true;
|
|
1649
1649
|
} catch {
|
|
1650
1650
|
try {
|
|
1651
|
-
await
|
|
1651
|
+
await fs30.access(rebaseApplyPath);
|
|
1652
1652
|
inRebase = true;
|
|
1653
1653
|
} catch {
|
|
1654
1654
|
inRebase = false;
|
|
@@ -1704,9 +1704,9 @@ var require_git_executor = __commonJS({
|
|
|
1704
1704
|
};
|
|
1705
1705
|
}
|
|
1706
1706
|
}
|
|
1707
|
-
const
|
|
1707
|
+
const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1708
1708
|
try {
|
|
1709
|
-
await
|
|
1709
|
+
await fs30.access(command.path);
|
|
1710
1710
|
return {
|
|
1711
1711
|
success: false,
|
|
1712
1712
|
error: "WORKTREE_EXISTS",
|
|
@@ -1765,9 +1765,9 @@ var require_git_executor = __commonJS({
|
|
|
1765
1765
|
*/
|
|
1766
1766
|
async executeWorktreeRemove(command, cwd, options) {
|
|
1767
1767
|
try {
|
|
1768
|
-
const
|
|
1768
|
+
const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1769
1769
|
try {
|
|
1770
|
-
await
|
|
1770
|
+
await fs30.access(command.path);
|
|
1771
1771
|
} catch {
|
|
1772
1772
|
return {
|
|
1773
1773
|
success: false,
|
|
@@ -1802,7 +1802,7 @@ var require_git_executor = __commonJS({
|
|
|
1802
1802
|
const result = await this.runGitCommand(args, cwd, options);
|
|
1803
1803
|
if (result.success) {
|
|
1804
1804
|
try {
|
|
1805
|
-
await
|
|
1805
|
+
await fs30.rm(command.path, { recursive: true, force: true });
|
|
1806
1806
|
} catch {
|
|
1807
1807
|
}
|
|
1808
1808
|
return {
|
|
@@ -1936,10 +1936,10 @@ var require_git_executor = __commonJS({
|
|
|
1936
1936
|
*/
|
|
1937
1937
|
async executeCloneBare(command, options) {
|
|
1938
1938
|
try {
|
|
1939
|
-
const
|
|
1940
|
-
const
|
|
1939
|
+
const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
1940
|
+
const path31 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
1941
1941
|
try {
|
|
1942
|
-
await
|
|
1942
|
+
await fs30.access(command.path);
|
|
1943
1943
|
return {
|
|
1944
1944
|
success: false,
|
|
1945
1945
|
error: "BRANCH_ALREADY_EXISTS",
|
|
@@ -1948,9 +1948,9 @@ var require_git_executor = __commonJS({
|
|
|
1948
1948
|
};
|
|
1949
1949
|
} catch {
|
|
1950
1950
|
}
|
|
1951
|
-
const parentDir =
|
|
1951
|
+
const parentDir = path31.dirname(command.path);
|
|
1952
1952
|
try {
|
|
1953
|
-
await
|
|
1953
|
+
await fs30.mkdir(parentDir, { recursive: true });
|
|
1954
1954
|
} catch {
|
|
1955
1955
|
}
|
|
1956
1956
|
const { stdout, stderr } = await execAsync3(
|
|
@@ -1998,22 +1998,22 @@ var require_git_executor = __commonJS({
|
|
|
1998
1998
|
*/
|
|
1999
1999
|
async executeProjectInfo(cwd, options) {
|
|
2000
2000
|
try {
|
|
2001
|
-
const
|
|
2002
|
-
const
|
|
2001
|
+
const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
|
|
2002
|
+
const path31 = await Promise.resolve().then(() => __importStar(require("path")));
|
|
2003
2003
|
let currentPath = cwd;
|
|
2004
2004
|
let projectPath = cwd;
|
|
2005
2005
|
let bareRepoPath;
|
|
2006
2006
|
for (let i = 0; i < 10; i++) {
|
|
2007
|
-
const bareDir =
|
|
2008
|
-
const episodaDir =
|
|
2007
|
+
const bareDir = path31.join(currentPath, ".bare");
|
|
2008
|
+
const episodaDir = path31.join(currentPath, ".episoda");
|
|
2009
2009
|
try {
|
|
2010
|
-
await
|
|
2011
|
-
await
|
|
2010
|
+
await fs30.access(bareDir);
|
|
2011
|
+
await fs30.access(episodaDir);
|
|
2012
2012
|
projectPath = currentPath;
|
|
2013
2013
|
bareRepoPath = bareDir;
|
|
2014
2014
|
break;
|
|
2015
2015
|
} catch {
|
|
2016
|
-
const parentPath =
|
|
2016
|
+
const parentPath = path31.dirname(currentPath);
|
|
2017
2017
|
if (parentPath === currentPath) {
|
|
2018
2018
|
break;
|
|
2019
2019
|
}
|
|
@@ -2674,33 +2674,33 @@ var require_auth = __commonJS({
|
|
|
2674
2674
|
exports2.loadConfig = loadConfig16;
|
|
2675
2675
|
exports2.saveConfig = saveConfig4;
|
|
2676
2676
|
exports2.validateToken = validateToken;
|
|
2677
|
-
var
|
|
2678
|
-
var
|
|
2677
|
+
var fs30 = __importStar(require("fs"));
|
|
2678
|
+
var path31 = __importStar(require("path"));
|
|
2679
2679
|
var os13 = __importStar(require("os"));
|
|
2680
2680
|
var child_process_1 = require("child_process");
|
|
2681
2681
|
var DEFAULT_CONFIG_FILE = "config.json";
|
|
2682
2682
|
var hasWarnedMissingProjectId = false;
|
|
2683
2683
|
var hasWarnedMissingRequiredFields = false;
|
|
2684
2684
|
function getConfigDir10() {
|
|
2685
|
-
return process.env.EPISODA_CONFIG_DIR ||
|
|
2685
|
+
return process.env.EPISODA_CONFIG_DIR || path31.join(os13.homedir(), ".episoda");
|
|
2686
2686
|
}
|
|
2687
2687
|
function getConfigPath(configPath) {
|
|
2688
2688
|
if (configPath) {
|
|
2689
2689
|
return configPath;
|
|
2690
2690
|
}
|
|
2691
|
-
return
|
|
2691
|
+
return path31.join(getConfigDir10(), DEFAULT_CONFIG_FILE);
|
|
2692
2692
|
}
|
|
2693
2693
|
function ensureConfigDir(configPath) {
|
|
2694
|
-
const dir =
|
|
2695
|
-
const isNew = !
|
|
2694
|
+
const dir = path31.dirname(configPath);
|
|
2695
|
+
const isNew = !fs30.existsSync(dir);
|
|
2696
2696
|
if (isNew) {
|
|
2697
|
-
|
|
2697
|
+
fs30.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2698
2698
|
}
|
|
2699
2699
|
if (process.platform === "darwin") {
|
|
2700
|
-
const nosyncPath =
|
|
2701
|
-
if (isNew || !
|
|
2700
|
+
const nosyncPath = path31.join(dir, ".nosync");
|
|
2701
|
+
if (isNew || !fs30.existsSync(nosyncPath)) {
|
|
2702
2702
|
try {
|
|
2703
|
-
|
|
2703
|
+
fs30.writeFileSync(nosyncPath, "", { mode: 384 });
|
|
2704
2704
|
(0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
|
|
2705
2705
|
stdio: "ignore",
|
|
2706
2706
|
timeout: 5e3
|
|
@@ -2714,11 +2714,11 @@ var require_auth = __commonJS({
|
|
|
2714
2714
|
const fullPath = getConfigPath(configPath);
|
|
2715
2715
|
const isCloudMode = process.env.EPISODA_MODE === "cloud";
|
|
2716
2716
|
const readConfigFile = (pathToFile) => {
|
|
2717
|
-
if (!
|
|
2717
|
+
if (!fs30.existsSync(pathToFile)) {
|
|
2718
2718
|
return null;
|
|
2719
2719
|
}
|
|
2720
2720
|
try {
|
|
2721
|
-
const content =
|
|
2721
|
+
const content = fs30.readFileSync(pathToFile, "utf8");
|
|
2722
2722
|
return JSON.parse(content);
|
|
2723
2723
|
} catch (error) {
|
|
2724
2724
|
console.error("Error loading config:", error);
|
|
@@ -2757,11 +2757,11 @@ var require_auth = __commonJS({
|
|
|
2757
2757
|
}
|
|
2758
2758
|
const homeDir = process.env.HOME || require("os").homedir();
|
|
2759
2759
|
const workspaceConfigPath = require("path").join(homeDir, "episoda", process.env.EPISODA_WORKSPACE, ".episoda", "config.json");
|
|
2760
|
-
if (!
|
|
2760
|
+
if (!fs30.existsSync(workspaceConfigPath)) {
|
|
2761
2761
|
return null;
|
|
2762
2762
|
}
|
|
2763
2763
|
try {
|
|
2764
|
-
const content =
|
|
2764
|
+
const content = fs30.readFileSync(workspaceConfigPath, "utf8");
|
|
2765
2765
|
const workspaceConfig2 = JSON.parse(content);
|
|
2766
2766
|
const expiresAtEnv = envValue(process.env.EPISODA_ACCESS_TOKEN_EXPIRES_AT);
|
|
2767
2767
|
return {
|
|
@@ -2789,11 +2789,11 @@ var require_auth = __commonJS({
|
|
|
2789
2789
|
}
|
|
2790
2790
|
const homeDir = process.env.HOME || require("os").homedir();
|
|
2791
2791
|
const projectConfigPath = require("path").join(homeDir, "episoda", workspaceSlug, projectSlug, ".episoda", "config.json");
|
|
2792
|
-
if (!
|
|
2792
|
+
if (!fs30.existsSync(projectConfigPath)) {
|
|
2793
2793
|
return null;
|
|
2794
2794
|
}
|
|
2795
2795
|
try {
|
|
2796
|
-
const content =
|
|
2796
|
+
const content = fs30.readFileSync(projectConfigPath, "utf8");
|
|
2797
2797
|
const projectConfig2 = JSON.parse(content);
|
|
2798
2798
|
return {
|
|
2799
2799
|
project_id: projectConfig2.projectId || projectConfig2.project_id,
|
|
@@ -2861,7 +2861,7 @@ var require_auth = __commonJS({
|
|
|
2861
2861
|
ensureConfigDir(fullPath);
|
|
2862
2862
|
try {
|
|
2863
2863
|
const content = JSON.stringify(config, null, 2);
|
|
2864
|
-
|
|
2864
|
+
fs30.writeFileSync(fullPath, content, { mode: 384 });
|
|
2865
2865
|
} catch (error) {
|
|
2866
2866
|
throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
|
|
2867
2867
|
}
|
|
@@ -2978,7 +2978,7 @@ var require_package = __commonJS({
|
|
|
2978
2978
|
"package.json"(exports2, module2) {
|
|
2979
2979
|
module2.exports = {
|
|
2980
2980
|
name: "@episoda/cli",
|
|
2981
|
-
version: "0.2.
|
|
2981
|
+
version: "0.2.166",
|
|
2982
2982
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2983
2983
|
main: "dist/index.js",
|
|
2984
2984
|
types: "dist/index.d.ts",
|
|
@@ -4979,7 +4979,9 @@ var import_core9 = __toESM(require_dist());
|
|
|
4979
4979
|
|
|
4980
4980
|
// src/agent/claude-persistent-runtime.ts
|
|
4981
4981
|
var import_child_process7 = require("child_process");
|
|
4982
|
-
var
|
|
4982
|
+
var DEFAULT_STARTUP_GRACE_MS = 3e4;
|
|
4983
|
+
var HEARTBEAT_ACK_MARKER = "__EPISODA_HEARTBEAT_ACK__";
|
|
4984
|
+
var ECHO_TIMEOUT_MS = parseInt(process.env.AGENT_ECHO_TIMEOUT_MS || `${DEFAULT_STARTUP_GRACE_MS}`, 10);
|
|
4983
4985
|
var INACTIVITY_TIMEOUT_MS = parseInt(process.env.AGENT_STREAM_INACTIVITY_TIMEOUT_MS || "180000", 10);
|
|
4984
4986
|
var SHUTDOWN_SIGTERM_WAIT_MS = 2e3;
|
|
4985
4987
|
var SHUTDOWN_SIGKILL_WAIT_MS = 2e3;
|
|
@@ -5015,7 +5017,6 @@ var ClaudePersistentRuntime = class {
|
|
|
5015
5017
|
this.echoTimer = null;
|
|
5016
5018
|
this.inactivityTimer = null;
|
|
5017
5019
|
this.turnStartTime = 0;
|
|
5018
|
-
this.sawAnyStdoutThisTurn = false;
|
|
5019
5020
|
// EP1360: Instrumentation
|
|
5020
5021
|
this.spawnTimestamp = 0;
|
|
5021
5022
|
this.sessionId = options.sessionId;
|
|
@@ -5055,6 +5056,11 @@ var ClaudePersistentRuntime = class {
|
|
|
5055
5056
|
this.alive = true;
|
|
5056
5057
|
this.process.stderr?.on("data", (data) => {
|
|
5057
5058
|
const chunk = data.toString();
|
|
5059
|
+
this.resetInactivityTimer();
|
|
5060
|
+
if (this._turnState === "waiting_for_echo") {
|
|
5061
|
+
const source = chunk.includes(HEARTBEAT_ACK_MARKER) ? "stderr-marker" : "stderr";
|
|
5062
|
+
this.recordStartupHeartbeatAck(source);
|
|
5063
|
+
}
|
|
5058
5064
|
this.stderrTail = (this.stderrTail + chunk).slice(-this.maxStderrTailBytes);
|
|
5059
5065
|
if (RUNTIME_DEBUG) {
|
|
5060
5066
|
console.error(`[ClaudePersistentRuntime] stderr (session=${this.sessionId}): ${chunk.trimEnd()}`);
|
|
@@ -5062,6 +5068,7 @@ var ClaudePersistentRuntime = class {
|
|
|
5062
5068
|
});
|
|
5063
5069
|
this.process.stdout?.on("data", (data) => {
|
|
5064
5070
|
this.resetInactivityTimer();
|
|
5071
|
+
this.recordStartupHeartbeatAck("stdout");
|
|
5065
5072
|
this.stdoutBuffer += data.toString();
|
|
5066
5073
|
const lines = this.stdoutBuffer.split("\n");
|
|
5067
5074
|
this.stdoutBuffer = lines.pop() || "";
|
|
@@ -5112,7 +5119,6 @@ var ClaudePersistentRuntime = class {
|
|
|
5112
5119
|
this.turnStartTime = Date.now();
|
|
5113
5120
|
this.turnTtftLogged = false;
|
|
5114
5121
|
this.seenToolUseIds.clear();
|
|
5115
|
-
this.sawAnyStdoutThisTurn = false;
|
|
5116
5122
|
this._turnState = "waiting_for_echo";
|
|
5117
5123
|
const payload = JSON.stringify({ type: "user", message: { role: "user", content: message } }) + "\n";
|
|
5118
5124
|
try {
|
|
@@ -5125,9 +5131,9 @@ var ClaudePersistentRuntime = class {
|
|
|
5125
5131
|
}
|
|
5126
5132
|
this.echoTimer = setTimeout(() => {
|
|
5127
5133
|
if (this._turnState === "waiting_for_echo") {
|
|
5128
|
-
console.warn(`[ClaudePersistentRuntime]
|
|
5134
|
+
console.warn(`[ClaudePersistentRuntime] Startup heartbeat timeout after ${ECHO_TIMEOUT_MS}ms \u2014 auto-degrading. session=${this.sessionId}`);
|
|
5129
5135
|
if (this.callbacks) {
|
|
5130
|
-
this.callbacks.onError(`ECHO_TIMEOUT: No
|
|
5136
|
+
this.callbacks.onError(`ECHO_TIMEOUT: No startup heartbeat within ${ECHO_TIMEOUT_MS}ms after send`);
|
|
5131
5137
|
this.endTurn();
|
|
5132
5138
|
}
|
|
5133
5139
|
}
|
|
@@ -5210,14 +5216,7 @@ var ClaudePersistentRuntime = class {
|
|
|
5210
5216
|
}
|
|
5211
5217
|
handleParsedEvent(parsed) {
|
|
5212
5218
|
const type = parsed.type;
|
|
5213
|
-
|
|
5214
|
-
this.sawAnyStdoutThisTurn = true;
|
|
5215
|
-
this.clearEchoTimer();
|
|
5216
|
-
this._turnState = "streaming";
|
|
5217
|
-
if (RUNTIME_DEBUG) {
|
|
5218
|
-
console.log(`[ClaudePersistentRuntime] First stdout for turn \u2014 streaming started. session=${this.sessionId}`);
|
|
5219
|
-
}
|
|
5220
|
-
}
|
|
5219
|
+
this.recordStartupHeartbeatAck("stdout");
|
|
5221
5220
|
if (type === "user") {
|
|
5222
5221
|
return;
|
|
5223
5222
|
}
|
|
@@ -5403,6 +5402,14 @@ var ClaudePersistentRuntime = class {
|
|
|
5403
5402
|
this.endTurn();
|
|
5404
5403
|
cb.onComplete(this._agentSessionId, resultMeta);
|
|
5405
5404
|
}
|
|
5405
|
+
recordStartupHeartbeatAck(source) {
|
|
5406
|
+
if (this._turnState !== "waiting_for_echo") return;
|
|
5407
|
+
this.clearEchoTimer();
|
|
5408
|
+
this._turnState = "streaming";
|
|
5409
|
+
if (RUNTIME_DEBUG) {
|
|
5410
|
+
console.log(`[ClaudePersistentRuntime] Startup heartbeat ack via ${source}; streaming started. session=${this.sessionId}`);
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5406
5413
|
endTurn() {
|
|
5407
5414
|
this.clearTimers();
|
|
5408
5415
|
this.callbacks = null;
|
|
@@ -9472,7 +9479,7 @@ function getInstallCommand(cwd) {
|
|
|
9472
9479
|
}
|
|
9473
9480
|
|
|
9474
9481
|
// src/daemon/daemon-process.ts
|
|
9475
|
-
var
|
|
9482
|
+
var fs29 = __toESM(require("fs"));
|
|
9476
9483
|
var http2 = __toESM(require("http"));
|
|
9477
9484
|
var os12 = __toESM(require("os"));
|
|
9478
9485
|
|
|
@@ -10280,8 +10287,8 @@ async function handleExec(command, projectPath) {
|
|
|
10280
10287
|
}
|
|
10281
10288
|
|
|
10282
10289
|
// src/daemon/handlers/worktree-handlers.ts
|
|
10283
|
-
var
|
|
10284
|
-
var
|
|
10290
|
+
var path24 = __toESM(require("path"));
|
|
10291
|
+
var fs23 = __toESM(require("fs"));
|
|
10285
10292
|
var os10 = __toESM(require("os"));
|
|
10286
10293
|
var import_child_process15 = require("child_process");
|
|
10287
10294
|
var import_util2 = require("util");
|
|
@@ -11628,7 +11635,7 @@ function pnpmCommand(args) {
|
|
|
11628
11635
|
' echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2',
|
|
11629
11636
|
" exit 127",
|
|
11630
11637
|
"fi"
|
|
11631
|
-
].join("
|
|
11638
|
+
].join("\n");
|
|
11632
11639
|
}
|
|
11633
11640
|
var PACKAGE_MANAGERS = {
|
|
11634
11641
|
javascript: [
|
|
@@ -11765,6 +11772,51 @@ function detectPackageManager(worktreePath, preferredLanguages) {
|
|
|
11765
11772
|
};
|
|
11766
11773
|
}
|
|
11767
11774
|
|
|
11775
|
+
// src/daemon/build-packages.ts
|
|
11776
|
+
var fs22 = __toESM(require("fs"));
|
|
11777
|
+
var path23 = __toESM(require("path"));
|
|
11778
|
+
function hasPackageScript(worktreePath, scriptName) {
|
|
11779
|
+
try {
|
|
11780
|
+
const packageJsonPath = path23.join(worktreePath, "package.json");
|
|
11781
|
+
if (!fs22.existsSync(packageJsonPath)) {
|
|
11782
|
+
return false;
|
|
11783
|
+
}
|
|
11784
|
+
const packageJson2 = JSON.parse(fs22.readFileSync(packageJsonPath, "utf-8"));
|
|
11785
|
+
return typeof packageJson2.scripts?.[scriptName] === "string";
|
|
11786
|
+
} catch {
|
|
11787
|
+
return false;
|
|
11788
|
+
}
|
|
11789
|
+
}
|
|
11790
|
+
function getBuildPackagesCommand(packageManagerName, hasBuildPackagesScript) {
|
|
11791
|
+
if (!hasBuildPackagesScript) {
|
|
11792
|
+
return null;
|
|
11793
|
+
}
|
|
11794
|
+
switch (packageManagerName) {
|
|
11795
|
+
case "pnpm":
|
|
11796
|
+
return [
|
|
11797
|
+
"if command -v pnpm >/dev/null 2>&1; then",
|
|
11798
|
+
" pnpm run build:packages",
|
|
11799
|
+
"elif command -v corepack >/dev/null 2>&1; then",
|
|
11800
|
+
" corepack pnpm run build:packages",
|
|
11801
|
+
"else",
|
|
11802
|
+
' echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2',
|
|
11803
|
+
" exit 127",
|
|
11804
|
+
"fi"
|
|
11805
|
+
].join("\n");
|
|
11806
|
+
case "yarn":
|
|
11807
|
+
return "yarn build:packages";
|
|
11808
|
+
case "npm":
|
|
11809
|
+
return "npm run build:packages";
|
|
11810
|
+
case "bun":
|
|
11811
|
+
return "bun run build:packages";
|
|
11812
|
+
default:
|
|
11813
|
+
return null;
|
|
11814
|
+
}
|
|
11815
|
+
}
|
|
11816
|
+
function shouldRunBuildPackagesBootstrap(installSucceeded, buildPackagesCommand) {
|
|
11817
|
+
return installSucceeded && !!buildPackagesCommand;
|
|
11818
|
+
}
|
|
11819
|
+
|
|
11768
11820
|
// src/daemon/handlers/worktree-handlers.ts
|
|
11769
11821
|
async function getConfigForApi() {
|
|
11770
11822
|
if (process.env.EPISODA_MODE === "cloud" && process.env.EPISODA_ACCESS_TOKEN) {
|
|
@@ -11788,18 +11840,18 @@ function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
|
|
|
11788
11840
|
return;
|
|
11789
11841
|
}
|
|
11790
11842
|
const homeDir = process.env.HOME || os10.homedir();
|
|
11791
|
-
const workspaceConfigPath =
|
|
11843
|
+
const workspaceConfigPath = path24.join(
|
|
11792
11844
|
homeDir,
|
|
11793
11845
|
"episoda",
|
|
11794
11846
|
workspaceSlug,
|
|
11795
11847
|
".episoda",
|
|
11796
11848
|
"config.json"
|
|
11797
11849
|
);
|
|
11798
|
-
if (!
|
|
11850
|
+
if (!fs23.existsSync(workspaceConfigPath)) {
|
|
11799
11851
|
return;
|
|
11800
11852
|
}
|
|
11801
11853
|
try {
|
|
11802
|
-
const content =
|
|
11854
|
+
const content = fs23.readFileSync(workspaceConfigPath, "utf8");
|
|
11803
11855
|
const workspaceConfig = JSON.parse(content);
|
|
11804
11856
|
let changed = false;
|
|
11805
11857
|
if (projectId && workspaceConfig.projectId !== projectId && workspaceConfig.project_id !== projectId) {
|
|
@@ -11811,7 +11863,7 @@ function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
|
|
|
11811
11863
|
changed = true;
|
|
11812
11864
|
}
|
|
11813
11865
|
if (changed) {
|
|
11814
|
-
|
|
11866
|
+
fs23.writeFileSync(workspaceConfigPath, JSON.stringify(workspaceConfig, null, 2), "utf8");
|
|
11815
11867
|
console.log("[Worktree] Updated workspace config with project context");
|
|
11816
11868
|
}
|
|
11817
11869
|
} catch (error) {
|
|
@@ -11828,32 +11880,6 @@ async function autoDetectSetupScript(worktreePath) {
|
|
|
11828
11880
|
console.log(`[Worktree] EP1222: Detected ${name} (${language}) via ${detection.matchedFile}`);
|
|
11829
11881
|
return installCmd;
|
|
11830
11882
|
}
|
|
11831
|
-
function getBuildPackagesCommand(packageManagerName) {
|
|
11832
|
-
switch (packageManagerName) {
|
|
11833
|
-
case "pnpm":
|
|
11834
|
-
return 'if command -v pnpm >/dev/null 2>&1; then pnpm run build:packages; elif command -v corepack >/dev/null 2>&1; then corepack pnpm run build:packages; else echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2; exit 127; fi';
|
|
11835
|
-
case "yarn":
|
|
11836
|
-
return "yarn build:packages";
|
|
11837
|
-
case "npm":
|
|
11838
|
-
return "npm run build:packages";
|
|
11839
|
-
case "bun":
|
|
11840
|
-
return "bun run build:packages";
|
|
11841
|
-
default:
|
|
11842
|
-
return null;
|
|
11843
|
-
}
|
|
11844
|
-
}
|
|
11845
|
-
function hasPackageScript(worktreePath, scriptName) {
|
|
11846
|
-
try {
|
|
11847
|
-
const packageJsonPath = path23.join(worktreePath, "package.json");
|
|
11848
|
-
if (!fs22.existsSync(packageJsonPath)) {
|
|
11849
|
-
return false;
|
|
11850
|
-
}
|
|
11851
|
-
const packageJson2 = JSON.parse(fs22.readFileSync(packageJsonPath, "utf-8"));
|
|
11852
|
-
return typeof packageJson2.scripts?.[scriptName] === "string";
|
|
11853
|
-
} catch {
|
|
11854
|
-
return false;
|
|
11855
|
-
}
|
|
11856
|
-
}
|
|
11857
11883
|
async function handleWorktreeCreate(request2) {
|
|
11858
11884
|
const {
|
|
11859
11885
|
workspaceSlug,
|
|
@@ -11884,19 +11910,19 @@ async function handleWorktreeCreate(request2) {
|
|
|
11884
11910
|
}
|
|
11885
11911
|
try {
|
|
11886
11912
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
11887
|
-
const bareRepoPath =
|
|
11913
|
+
const bareRepoPath = path24.join(projectPath, ".bare");
|
|
11888
11914
|
const gitEnv = projectId ? { ...process.env, EPISODA_PROJECT_ID: projectId } : process.env;
|
|
11889
|
-
if (!
|
|
11915
|
+
if (!fs23.existsSync(bareRepoPath)) {
|
|
11890
11916
|
console.log(`[Worktree] K1273: Project not found, cloning lazily...`);
|
|
11891
11917
|
console.log(`[Worktree] Repo URL: ${repoUrl.replace(/\/\/[^@]*@/, "//***@")}`);
|
|
11892
|
-
const episodaDir =
|
|
11893
|
-
|
|
11918
|
+
const episodaDir = path24.join(projectPath, ".episoda");
|
|
11919
|
+
fs23.mkdirSync(episodaDir, { recursive: true });
|
|
11894
11920
|
try {
|
|
11895
11921
|
console.log(`[Worktree] K1273: Starting git clone...`);
|
|
11896
11922
|
await execAsync2(`git clone --bare "${repoUrl}" "${bareRepoPath}"`, { env: gitEnv });
|
|
11897
11923
|
console.log(`[Worktree] K1273: Clone successful`);
|
|
11898
11924
|
await execAsync2(`git -C "${bareRepoPath}" config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"`, { env: gitEnv });
|
|
11899
|
-
const configPath =
|
|
11925
|
+
const configPath = path24.join(episodaDir, "config.json");
|
|
11900
11926
|
const config = {
|
|
11901
11927
|
projectId,
|
|
11902
11928
|
workspaceSlug,
|
|
@@ -11905,7 +11931,7 @@ async function handleWorktreeCreate(request2) {
|
|
|
11905
11931
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11906
11932
|
worktrees: []
|
|
11907
11933
|
};
|
|
11908
|
-
|
|
11934
|
+
fs23.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
11909
11935
|
console.log(`[Worktree] K1273: Project initialized at ${projectPath}`);
|
|
11910
11936
|
} catch (cloneError) {
|
|
11911
11937
|
console.error(`[Worktree] K1273: Git clone failed: ${cloneError.message}`);
|
|
@@ -11940,16 +11966,16 @@ async function handleWorktreeCreate(request2) {
|
|
|
11940
11966
|
let finalError;
|
|
11941
11967
|
if (envVars && Object.keys(envVars).length > 0) {
|
|
11942
11968
|
const envContent = Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n");
|
|
11943
|
-
const envPath =
|
|
11944
|
-
|
|
11969
|
+
const envPath = path24.join(worktreePath, ".env");
|
|
11970
|
+
fs23.writeFileSync(envPath, envContent + "\n", "utf-8");
|
|
11945
11971
|
console.log(`[Worktree] EP1143: Wrote ${Object.keys(envVars).length} env vars to .env`);
|
|
11946
11972
|
}
|
|
11947
11973
|
const isCloud = process.env.EPISODA_MODE === "cloud";
|
|
11948
11974
|
let effectiveSetupScript = setupScript || await autoDetectSetupScript(worktreePath);
|
|
11949
11975
|
const detection = detectPackageManager(worktreePath);
|
|
11950
|
-
const buildCmd = getBuildPackagesCommand(detection.packageManager?.name);
|
|
11951
11976
|
const hasBuildPackages = hasPackageScript(worktreePath, "build:packages");
|
|
11952
|
-
|
|
11977
|
+
const buildCmd = getBuildPackagesCommand(detection.packageManager?.name, hasBuildPackages);
|
|
11978
|
+
if (buildCmd && !effectiveSetupScript?.includes("build:packages")) {
|
|
11953
11979
|
effectiveSetupScript = effectiveSetupScript ? `${effectiveSetupScript}
|
|
11954
11980
|
${buildCmd}` : buildCmd;
|
|
11955
11981
|
console.log(`[Worktree] EP1386: Added build:packages bootstrap for ${isCloud ? "cloud" : "local"} setup`);
|
|
@@ -12082,12 +12108,12 @@ async function handleProjectEject(request2) {
|
|
|
12082
12108
|
console.log(`[Worktree] EP1144: Ejecting project ${projectSlug} from workspace ${workspaceSlug}`);
|
|
12083
12109
|
try {
|
|
12084
12110
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
12085
|
-
const bareRepoPath =
|
|
12086
|
-
if (!
|
|
12111
|
+
const bareRepoPath = path24.join(projectPath, ".bare");
|
|
12112
|
+
if (!fs23.existsSync(projectPath)) {
|
|
12087
12113
|
console.log(`[Worktree] EP1144: Project path not found, nothing to eject: ${projectPath}`);
|
|
12088
12114
|
return { success: true };
|
|
12089
12115
|
}
|
|
12090
|
-
if (!
|
|
12116
|
+
if (!fs23.existsSync(bareRepoPath)) {
|
|
12091
12117
|
console.log(`[Worktree] EP1144: Bare repo not found, nothing to eject: ${bareRepoPath}`);
|
|
12092
12118
|
return { success: true };
|
|
12093
12119
|
}
|
|
@@ -12102,12 +12128,12 @@ async function handleProjectEject(request2) {
|
|
|
12102
12128
|
};
|
|
12103
12129
|
}
|
|
12104
12130
|
}
|
|
12105
|
-
const artifactsPath =
|
|
12106
|
-
if (
|
|
12131
|
+
const artifactsPath = path24.join(projectPath, "artifacts");
|
|
12132
|
+
if (fs23.existsSync(artifactsPath)) {
|
|
12107
12133
|
await persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug);
|
|
12108
12134
|
}
|
|
12109
12135
|
console.log(`[Worktree] EP1144: Removing project directory: ${projectPath}`);
|
|
12110
|
-
await
|
|
12136
|
+
await fs23.promises.rm(projectPath, { recursive: true, force: true });
|
|
12111
12137
|
console.log(`[Worktree] EP1144: Successfully ejected project ${projectSlug}`);
|
|
12112
12138
|
return { success: true };
|
|
12113
12139
|
} catch (error) {
|
|
@@ -12121,7 +12147,7 @@ async function handleProjectEject(request2) {
|
|
|
12121
12147
|
async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug) {
|
|
12122
12148
|
const MAX_ARTIFACT_SIZE = 10 * 1024 * 1024;
|
|
12123
12149
|
try {
|
|
12124
|
-
const files = await
|
|
12150
|
+
const files = await fs23.promises.readdir(artifactsPath);
|
|
12125
12151
|
if (files.length === 0) {
|
|
12126
12152
|
return;
|
|
12127
12153
|
}
|
|
@@ -12135,8 +12161,8 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
12135
12161
|
}
|
|
12136
12162
|
const artifacts = [];
|
|
12137
12163
|
for (const fileName of files) {
|
|
12138
|
-
const filePath =
|
|
12139
|
-
const stat = await
|
|
12164
|
+
const filePath = path24.join(artifactsPath, fileName);
|
|
12165
|
+
const stat = await fs23.promises.stat(filePath);
|
|
12140
12166
|
if (stat.isDirectory()) {
|
|
12141
12167
|
continue;
|
|
12142
12168
|
}
|
|
@@ -12145,9 +12171,9 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
12145
12171
|
continue;
|
|
12146
12172
|
}
|
|
12147
12173
|
try {
|
|
12148
|
-
const content = await
|
|
12174
|
+
const content = await fs23.promises.readFile(filePath);
|
|
12149
12175
|
const base64Content = content.toString("base64");
|
|
12150
|
-
const ext =
|
|
12176
|
+
const ext = path24.extname(fileName).toLowerCase();
|
|
12151
12177
|
const mimeTypes = {
|
|
12152
12178
|
".json": "application/json",
|
|
12153
12179
|
".txt": "text/plain",
|
|
@@ -12203,8 +12229,8 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
|
|
|
12203
12229
|
}
|
|
12204
12230
|
|
|
12205
12231
|
// src/daemon/handlers/project-handlers.ts
|
|
12206
|
-
var
|
|
12207
|
-
var
|
|
12232
|
+
var path25 = __toESM(require("path"));
|
|
12233
|
+
var fs24 = __toESM(require("fs"));
|
|
12208
12234
|
function validateSlug(slug, fieldName) {
|
|
12209
12235
|
if (!slug || typeof slug !== "string") {
|
|
12210
12236
|
return `${fieldName} is required`;
|
|
@@ -12244,14 +12270,14 @@ async function handleProjectSetup(params) {
|
|
|
12244
12270
|
console.log(`[ProjectSetup] EP1199: Setting up project ${workspaceSlug}/${projectSlug}`);
|
|
12245
12271
|
try {
|
|
12246
12272
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
12247
|
-
const artifactsPath =
|
|
12248
|
-
const configDir =
|
|
12249
|
-
const configPath =
|
|
12250
|
-
await
|
|
12251
|
-
await
|
|
12273
|
+
const artifactsPath = path25.join(projectPath, "artifacts");
|
|
12274
|
+
const configDir = path25.join(projectPath, ".episoda");
|
|
12275
|
+
const configPath = path25.join(configDir, "config.json");
|
|
12276
|
+
await fs24.promises.mkdir(artifactsPath, { recursive: true });
|
|
12277
|
+
await fs24.promises.mkdir(configDir, { recursive: true });
|
|
12252
12278
|
let existingConfig = {};
|
|
12253
12279
|
try {
|
|
12254
|
-
const existing = await
|
|
12280
|
+
const existing = await fs24.promises.readFile(configPath, "utf-8");
|
|
12255
12281
|
existingConfig = JSON.parse(existing);
|
|
12256
12282
|
} catch {
|
|
12257
12283
|
}
|
|
@@ -12264,7 +12290,7 @@ async function handleProjectSetup(params) {
|
|
|
12264
12290
|
// Only set created_at if not already present
|
|
12265
12291
|
created_at: existingConfig.created_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
12266
12292
|
};
|
|
12267
|
-
await
|
|
12293
|
+
await fs24.promises.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
12268
12294
|
console.log(`[ProjectSetup] EP1199: Project setup complete at ${projectPath}`);
|
|
12269
12295
|
return {
|
|
12270
12296
|
success: true,
|
|
@@ -12284,8 +12310,8 @@ async function handleProjectSetup(params) {
|
|
|
12284
12310
|
// src/utils/dev-server.ts
|
|
12285
12311
|
var import_child_process16 = require("child_process");
|
|
12286
12312
|
var import_core14 = __toESM(require_dist());
|
|
12287
|
-
var
|
|
12288
|
-
var
|
|
12313
|
+
var fs25 = __toESM(require("fs"));
|
|
12314
|
+
var path26 = __toESM(require("path"));
|
|
12289
12315
|
var MAX_RESTART_ATTEMPTS = 5;
|
|
12290
12316
|
var INITIAL_RESTART_DELAY_MS = 2e3;
|
|
12291
12317
|
var MAX_RESTART_DELAY_MS = 3e4;
|
|
@@ -12293,26 +12319,26 @@ var MAX_LOG_SIZE_BYTES2 = 5 * 1024 * 1024;
|
|
|
12293
12319
|
var NODE_MEMORY_LIMIT_MB = 2048;
|
|
12294
12320
|
var activeServers = /* @__PURE__ */ new Map();
|
|
12295
12321
|
function getLogsDir() {
|
|
12296
|
-
const logsDir =
|
|
12297
|
-
if (!
|
|
12298
|
-
|
|
12322
|
+
const logsDir = path26.join((0, import_core14.getConfigDir)(), "logs");
|
|
12323
|
+
if (!fs25.existsSync(logsDir)) {
|
|
12324
|
+
fs25.mkdirSync(logsDir, { recursive: true });
|
|
12299
12325
|
}
|
|
12300
12326
|
return logsDir;
|
|
12301
12327
|
}
|
|
12302
12328
|
function getLogFilePath(moduleUid) {
|
|
12303
|
-
return
|
|
12329
|
+
return path26.join(getLogsDir(), `dev-${moduleUid}.log`);
|
|
12304
12330
|
}
|
|
12305
12331
|
function rotateLogIfNeeded(logPath) {
|
|
12306
12332
|
try {
|
|
12307
|
-
if (
|
|
12308
|
-
const stats =
|
|
12333
|
+
if (fs25.existsSync(logPath)) {
|
|
12334
|
+
const stats = fs25.statSync(logPath);
|
|
12309
12335
|
if (stats.size > MAX_LOG_SIZE_BYTES2) {
|
|
12310
12336
|
const backupPath = `${logPath}.1`;
|
|
12311
|
-
if (
|
|
12312
|
-
|
|
12337
|
+
if (fs25.existsSync(backupPath)) {
|
|
12338
|
+
fs25.unlinkSync(backupPath);
|
|
12313
12339
|
}
|
|
12314
|
-
|
|
12315
|
-
console.log(`[DevServer] EP932: Rotated log file for ${
|
|
12340
|
+
fs25.renameSync(logPath, backupPath);
|
|
12341
|
+
console.log(`[DevServer] EP932: Rotated log file for ${path26.basename(logPath)}`);
|
|
12316
12342
|
}
|
|
12317
12343
|
}
|
|
12318
12344
|
} catch (error) {
|
|
@@ -12325,7 +12351,7 @@ function writeToLog(logPath, line, isError = false) {
|
|
|
12325
12351
|
const prefix = isError ? "ERR" : "OUT";
|
|
12326
12352
|
const logLine = `[${timestamp}] [${prefix}] ${line}
|
|
12327
12353
|
`;
|
|
12328
|
-
|
|
12354
|
+
fs25.appendFileSync(logPath, logLine);
|
|
12329
12355
|
} catch {
|
|
12330
12356
|
}
|
|
12331
12357
|
}
|
|
@@ -12504,8 +12530,8 @@ async function startDevServer(projectPath, port = 3e3, moduleUid = "default", op
|
|
|
12504
12530
|
});
|
|
12505
12531
|
injectedEnvVars = result.envVars;
|
|
12506
12532
|
console.log(`[DevServer] EP998: Loaded ${Object.keys(injectedEnvVars).length} env vars (from ${result.fromCache ? "cache" : "server"})`);
|
|
12507
|
-
const envFilePath =
|
|
12508
|
-
if (!
|
|
12533
|
+
const envFilePath = path26.join(projectPath, ".env");
|
|
12534
|
+
if (!fs25.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
|
|
12509
12535
|
console.log(`[DevServer] EP1004: .env file missing, writing ${Object.keys(injectedEnvVars).length} vars to ${envFilePath}`);
|
|
12510
12536
|
writeEnvFile(projectPath, injectedEnvVars);
|
|
12511
12537
|
}
|
|
@@ -12846,8 +12872,8 @@ var IPCRouter = class {
|
|
|
12846
12872
|
};
|
|
12847
12873
|
|
|
12848
12874
|
// src/daemon/update-manager.ts
|
|
12849
|
-
var
|
|
12850
|
-
var
|
|
12875
|
+
var fs26 = __toESM(require("fs"));
|
|
12876
|
+
var path27 = __toESM(require("path"));
|
|
12851
12877
|
var import_child_process18 = require("child_process");
|
|
12852
12878
|
var import_core17 = __toESM(require_dist());
|
|
12853
12879
|
var semver2 = __toESM(require("semver"));
|
|
@@ -13105,8 +13131,8 @@ var UpdateManager = class _UpdateManager {
|
|
|
13105
13131
|
console.log(`[Daemon] EP1324: Update to ${targetVersion} installed, restarting daemon...`);
|
|
13106
13132
|
await this.host.shutdown();
|
|
13107
13133
|
const configDir = (0, import_core17.getConfigDir)();
|
|
13108
|
-
const logPath =
|
|
13109
|
-
const logFd =
|
|
13134
|
+
const logPath = path27.join(configDir, "daemon.log");
|
|
13135
|
+
const logFd = fs26.openSync(logPath, "a");
|
|
13110
13136
|
const child = (0, import_child_process18.spawn)("node", [this.daemonEntryFile], {
|
|
13111
13137
|
detached: true,
|
|
13112
13138
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -13114,7 +13140,7 @@ var UpdateManager = class _UpdateManager {
|
|
|
13114
13140
|
});
|
|
13115
13141
|
if (!child.pid) {
|
|
13116
13142
|
try {
|
|
13117
|
-
|
|
13143
|
+
fs26.closeSync(logFd);
|
|
13118
13144
|
} catch {
|
|
13119
13145
|
}
|
|
13120
13146
|
this.recordUpdateFailure(targetVersion, "Failed to spawn replacement daemon (missing pid)");
|
|
@@ -13122,7 +13148,7 @@ var UpdateManager = class _UpdateManager {
|
|
|
13122
13148
|
}
|
|
13123
13149
|
child.unref();
|
|
13124
13150
|
const pidPath = getPidFilePath();
|
|
13125
|
-
|
|
13151
|
+
fs26.writeFileSync(pidPath, child.pid.toString(), "utf-8");
|
|
13126
13152
|
console.log(`[Daemon] EP1324: New daemon spawned (PID: ${child.pid}), exiting old process`);
|
|
13127
13153
|
process.exit(0);
|
|
13128
13154
|
} catch (error) {
|
|
@@ -13173,8 +13199,8 @@ var UpdateManager = class _UpdateManager {
|
|
|
13173
13199
|
};
|
|
13174
13200
|
|
|
13175
13201
|
// src/daemon/health-orchestrator.ts
|
|
13176
|
-
var
|
|
13177
|
-
var
|
|
13202
|
+
var fs27 = __toESM(require("fs"));
|
|
13203
|
+
var path28 = __toESM(require("path"));
|
|
13178
13204
|
var import_core18 = __toESM(require_dist());
|
|
13179
13205
|
var HealthOrchestrator = class _HealthOrchestrator {
|
|
13180
13206
|
constructor(host) {
|
|
@@ -13416,26 +13442,26 @@ var HealthOrchestrator = class _HealthOrchestrator {
|
|
|
13416
13442
|
checkAndRotateLog() {
|
|
13417
13443
|
try {
|
|
13418
13444
|
const configDir = (0, import_core18.getConfigDir)();
|
|
13419
|
-
const logPath =
|
|
13420
|
-
if (!
|
|
13421
|
-
const stats =
|
|
13445
|
+
const logPath = path28.join(configDir, "daemon.log");
|
|
13446
|
+
if (!fs27.existsSync(logPath)) return;
|
|
13447
|
+
const stats = fs27.statSync(logPath);
|
|
13422
13448
|
if (stats.size < _HealthOrchestrator.MAX_LOG_SIZE_BYTES) return;
|
|
13423
13449
|
console.log(`[Daemon] EP1351: daemon.log is ${Math.round(stats.size / 1024 / 1024)}MB, rotating...`);
|
|
13424
13450
|
for (let i = _HealthOrchestrator.MAX_LOG_FILES - 1; i >= 1; i--) {
|
|
13425
13451
|
const src = `${logPath}.${i}`;
|
|
13426
13452
|
const dst = `${logPath}.${i + 1}`;
|
|
13427
|
-
if (
|
|
13453
|
+
if (fs27.existsSync(src)) {
|
|
13428
13454
|
try {
|
|
13429
|
-
|
|
13455
|
+
fs27.renameSync(src, dst);
|
|
13430
13456
|
} catch {
|
|
13431
13457
|
}
|
|
13432
13458
|
}
|
|
13433
13459
|
}
|
|
13434
13460
|
try {
|
|
13435
|
-
|
|
13461
|
+
fs27.copyFileSync(logPath, `${logPath}.1`);
|
|
13436
13462
|
} catch {
|
|
13437
13463
|
}
|
|
13438
|
-
|
|
13464
|
+
fs27.truncateSync(logPath, 0);
|
|
13439
13465
|
console.log("[Daemon] EP1351: Log rotated successfully");
|
|
13440
13466
|
} catch (error) {
|
|
13441
13467
|
console.warn("[Daemon] EP1351: Log rotation failed:", error instanceof Error ? error.message : error);
|
|
@@ -13865,7 +13891,7 @@ function resolveDaemonWsEndpoint(config, env = process.env) {
|
|
|
13865
13891
|
|
|
13866
13892
|
// src/daemon/project-message-router.ts
|
|
13867
13893
|
var import_core19 = __toESM(require_dist());
|
|
13868
|
-
var
|
|
13894
|
+
var path29 = __toESM(require("path"));
|
|
13869
13895
|
var ProjectMessageRouter = class {
|
|
13870
13896
|
constructor(host) {
|
|
13871
13897
|
this.host = host;
|
|
@@ -13882,7 +13908,7 @@ var ProjectMessageRouter = class {
|
|
|
13882
13908
|
client.updateActivity();
|
|
13883
13909
|
try {
|
|
13884
13910
|
const gitCmd = message.command;
|
|
13885
|
-
const bareRepoPath =
|
|
13911
|
+
const bareRepoPath = path29.join(projectPath, ".bare");
|
|
13886
13912
|
const cwd = gitCmd.worktreePath || bareRepoPath;
|
|
13887
13913
|
if (gitCmd.worktreePath) {
|
|
13888
13914
|
console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
|
|
@@ -14222,32 +14248,32 @@ async function fetchEnvVars2(projectId) {
|
|
|
14222
14248
|
}
|
|
14223
14249
|
|
|
14224
14250
|
// src/daemon/project-git-config.ts
|
|
14225
|
-
var
|
|
14226
|
-
var
|
|
14251
|
+
var fs28 = __toESM(require("fs"));
|
|
14252
|
+
var path30 = __toESM(require("path"));
|
|
14227
14253
|
var import_core21 = __toESM(require_dist());
|
|
14228
14254
|
function getGitDirs(projectPath) {
|
|
14229
|
-
const bareDir =
|
|
14230
|
-
const gitPath =
|
|
14231
|
-
if (
|
|
14255
|
+
const bareDir = path30.join(projectPath, ".bare");
|
|
14256
|
+
const gitPath = path30.join(projectPath, ".git");
|
|
14257
|
+
if (fs28.existsSync(bareDir) && fs28.statSync(bareDir).isDirectory()) {
|
|
14232
14258
|
return { gitDir: bareDir, workDir: projectPath };
|
|
14233
14259
|
}
|
|
14234
|
-
if (
|
|
14260
|
+
if (fs28.existsSync(gitPath) && fs28.statSync(gitPath).isDirectory()) {
|
|
14235
14261
|
return { gitDir: null, workDir: projectPath };
|
|
14236
14262
|
}
|
|
14237
|
-
if (
|
|
14263
|
+
if (fs28.existsSync(gitPath) && fs28.statSync(gitPath).isFile()) {
|
|
14238
14264
|
return { gitDir: null, workDir: projectPath };
|
|
14239
14265
|
}
|
|
14240
|
-
const entries =
|
|
14266
|
+
const entries = fs28.readdirSync(projectPath, { withFileTypes: true });
|
|
14241
14267
|
for (const entry of entries) {
|
|
14242
14268
|
if (entry.isDirectory() && entry.name.startsWith("EP")) {
|
|
14243
|
-
const worktreePath =
|
|
14244
|
-
const worktreeGit =
|
|
14245
|
-
if (
|
|
14269
|
+
const worktreePath = path30.join(projectPath, entry.name);
|
|
14270
|
+
const worktreeGit = path30.join(worktreePath, ".git");
|
|
14271
|
+
if (fs28.existsSync(worktreeGit)) {
|
|
14246
14272
|
return { gitDir: null, workDir: worktreePath };
|
|
14247
14273
|
}
|
|
14248
14274
|
}
|
|
14249
14275
|
}
|
|
14250
|
-
if (
|
|
14276
|
+
if (fs28.existsSync(bareDir)) {
|
|
14251
14277
|
return { gitDir: bareDir, workDir: projectPath };
|
|
14252
14278
|
}
|
|
14253
14279
|
return { gitDir: null, workDir: projectPath };
|
|
@@ -14292,24 +14318,24 @@ async function configureGitUser(projectPath, userId, workspaceId, machineId, pro
|
|
|
14292
14318
|
async function installGitHooks(projectPath) {
|
|
14293
14319
|
const hooks = ["post-checkout", "pre-commit", "post-commit"];
|
|
14294
14320
|
let hooksDir;
|
|
14295
|
-
const bareHooksDir =
|
|
14296
|
-
const gitHooksDir =
|
|
14297
|
-
if (
|
|
14321
|
+
const bareHooksDir = path30.join(projectPath, ".bare", "hooks");
|
|
14322
|
+
const gitHooksDir = path30.join(projectPath, ".git", "hooks");
|
|
14323
|
+
if (fs28.existsSync(bareHooksDir)) {
|
|
14298
14324
|
hooksDir = bareHooksDir;
|
|
14299
|
-
} else if (
|
|
14325
|
+
} else if (fs28.existsSync(gitHooksDir) && fs28.statSync(path30.join(projectPath, ".git")).isDirectory()) {
|
|
14300
14326
|
hooksDir = gitHooksDir;
|
|
14301
14327
|
} else {
|
|
14302
|
-
const parentBareHooks =
|
|
14303
|
-
if (
|
|
14328
|
+
const parentBareHooks = path30.join(projectPath, "..", ".bare", "hooks");
|
|
14329
|
+
if (fs28.existsSync(parentBareHooks)) {
|
|
14304
14330
|
hooksDir = parentBareHooks;
|
|
14305
14331
|
} else {
|
|
14306
14332
|
console.warn(`[Daemon] Hooks directory not found for: ${projectPath}`);
|
|
14307
14333
|
return;
|
|
14308
14334
|
}
|
|
14309
14335
|
}
|
|
14310
|
-
if (!
|
|
14336
|
+
if (!fs28.existsSync(hooksDir)) {
|
|
14311
14337
|
try {
|
|
14312
|
-
|
|
14338
|
+
fs28.mkdirSync(hooksDir, { recursive: true });
|
|
14313
14339
|
} catch {
|
|
14314
14340
|
console.warn(`[Daemon] Hooks directory not found and could not create: ${hooksDir}`);
|
|
14315
14341
|
return;
|
|
@@ -14317,20 +14343,20 @@ async function installGitHooks(projectPath) {
|
|
|
14317
14343
|
}
|
|
14318
14344
|
for (const hookName of hooks) {
|
|
14319
14345
|
try {
|
|
14320
|
-
const hookPath =
|
|
14321
|
-
const bundledHookPath =
|
|
14322
|
-
if (!
|
|
14346
|
+
const hookPath = path30.join(hooksDir, hookName);
|
|
14347
|
+
const bundledHookPath = path30.join(__dirname, "..", "hooks", hookName);
|
|
14348
|
+
if (!fs28.existsSync(bundledHookPath)) {
|
|
14323
14349
|
console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
|
|
14324
14350
|
continue;
|
|
14325
14351
|
}
|
|
14326
|
-
const hookContent =
|
|
14327
|
-
if (
|
|
14328
|
-
const existingContent =
|
|
14352
|
+
const hookContent = fs28.readFileSync(bundledHookPath, "utf-8");
|
|
14353
|
+
if (fs28.existsSync(hookPath)) {
|
|
14354
|
+
const existingContent = fs28.readFileSync(hookPath, "utf-8");
|
|
14329
14355
|
if (existingContent === hookContent) {
|
|
14330
14356
|
continue;
|
|
14331
14357
|
}
|
|
14332
14358
|
}
|
|
14333
|
-
|
|
14359
|
+
fs28.writeFileSync(hookPath, hookContent, { mode: 493 });
|
|
14334
14360
|
console.log(`[Daemon] Installed git hook: ${hookName}`);
|
|
14335
14361
|
} catch (error) {
|
|
14336
14362
|
console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
|
|
@@ -14362,21 +14388,6 @@ async function cacheMachineUuid(machineUuid, machineId) {
|
|
|
14362
14388
|
|
|
14363
14389
|
// src/daemon/daemon-process.ts
|
|
14364
14390
|
var packageJson = require_package();
|
|
14365
|
-
function getBuildPackagesCommand2(installCmd) {
|
|
14366
|
-
const runner = installCmd?.command?.[0];
|
|
14367
|
-
switch (runner) {
|
|
14368
|
-
case "pnpm":
|
|
14369
|
-
return 'if command -v pnpm >/dev/null 2>&1; then pnpm run build:packages; elif command -v corepack >/dev/null 2>&1; then corepack pnpm run build:packages; else echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2; exit 127; fi';
|
|
14370
|
-
case "yarn":
|
|
14371
|
-
return "yarn build:packages";
|
|
14372
|
-
case "npm":
|
|
14373
|
-
return "npm run build:packages";
|
|
14374
|
-
case "bun":
|
|
14375
|
-
return "bun run build:packages";
|
|
14376
|
-
default:
|
|
14377
|
-
return null;
|
|
14378
|
-
}
|
|
14379
|
-
}
|
|
14380
14391
|
var Daemon = class _Daemon {
|
|
14381
14392
|
constructor() {
|
|
14382
14393
|
this.machineId = "";
|
|
@@ -14488,9 +14499,9 @@ var Daemon = class _Daemon {
|
|
|
14488
14499
|
this.healthServer = http2.createServer((req, res) => {
|
|
14489
14500
|
if (req.url === "/health" || req.url === "/") {
|
|
14490
14501
|
const isConnected = this.connectionManager.liveConnectionCount() > 0;
|
|
14491
|
-
const projects = Array.from(this.connectionManager.entries()).map(([
|
|
14492
|
-
path:
|
|
14493
|
-
connected: this.connectionManager.hasLiveConnection(
|
|
14502
|
+
const projects = Array.from(this.connectionManager.entries()).map(([path31, conn]) => ({
|
|
14503
|
+
path: path31,
|
|
14504
|
+
connected: this.connectionManager.hasLiveConnection(path31)
|
|
14494
14505
|
}));
|
|
14495
14506
|
const status = {
|
|
14496
14507
|
status: isConnected ? "healthy" : "degraded",
|
|
@@ -14563,8 +14574,8 @@ var Daemon = class _Daemon {
|
|
|
14563
14574
|
await this.shutdown();
|
|
14564
14575
|
try {
|
|
14565
14576
|
const pidPath = getPidFilePath();
|
|
14566
|
-
if (
|
|
14567
|
-
|
|
14577
|
+
if (fs29.existsSync(pidPath)) {
|
|
14578
|
+
fs29.unlinkSync(pidPath);
|
|
14568
14579
|
console.log("[Daemon] PID file cleaned up (watchdog)");
|
|
14569
14580
|
}
|
|
14570
14581
|
} catch (error) {
|
|
@@ -14830,7 +14841,7 @@ var Daemon = class _Daemon {
|
|
|
14830
14841
|
const resolvedProjectPath = getProjectPath(cmd.workspaceSlug, cmd.projectSlug);
|
|
14831
14842
|
if (resolvedProjectPath !== projectPath) {
|
|
14832
14843
|
try {
|
|
14833
|
-
await
|
|
14844
|
+
await fs29.promises.access(resolvedProjectPath);
|
|
14834
14845
|
agentWorkingDir = resolvedProjectPath;
|
|
14835
14846
|
console.log(`[Daemon] EP1230: Agent for ${cmd.moduleUid || "project"} in resolved project path: ${agentWorkingDir}`);
|
|
14836
14847
|
} catch {
|
|
@@ -15162,8 +15173,8 @@ var Daemon = class _Daemon {
|
|
|
15162
15173
|
let daemonPid;
|
|
15163
15174
|
try {
|
|
15164
15175
|
const pidPath = getPidFilePath();
|
|
15165
|
-
if (
|
|
15166
|
-
const pidStr =
|
|
15176
|
+
if (fs29.existsSync(pidPath)) {
|
|
15177
|
+
const pidStr = fs29.readFileSync(pidPath, "utf-8").trim();
|
|
15167
15178
|
daemonPid = parseInt(pidStr, 10);
|
|
15168
15179
|
}
|
|
15169
15180
|
} catch (pidError) {
|
|
@@ -15633,23 +15644,25 @@ var Daemon = class _Daemon {
|
|
|
15633
15644
|
} else {
|
|
15634
15645
|
console.log(`[Daemon] EP1002: No package manager detected, skipping dependency installation`);
|
|
15635
15646
|
}
|
|
15636
|
-
|
|
15637
|
-
|
|
15638
|
-
|
|
15639
|
-
|
|
15640
|
-
|
|
15641
|
-
|
|
15642
|
-
|
|
15643
|
-
|
|
15644
|
-
|
|
15645
|
-
|
|
15646
|
-
|
|
15647
|
-
}
|
|
15648
|
-
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15652
|
-
|
|
15647
|
+
const hasBuildPackages = hasPackageScript(worktreePath, "build:packages");
|
|
15648
|
+
const buildCmd = getBuildPackagesCommand(installCmd?.command?.[0], hasBuildPackages);
|
|
15649
|
+
if (buildCmd && shouldRunBuildPackagesBootstrap(installSucceeded, buildCmd)) {
|
|
15650
|
+
const bootstrapCmd = buildCmd;
|
|
15651
|
+
console.log(`[Daemon] EP1386: Bootstrapping packages after dependency install (${bootstrapCmd})`);
|
|
15652
|
+
try {
|
|
15653
|
+
const { execSync: execSync10 } = await import("child_process");
|
|
15654
|
+
execSync10(bootstrapCmd, {
|
|
15655
|
+
cwd: worktreePath,
|
|
15656
|
+
stdio: "inherit",
|
|
15657
|
+
timeout: 10 * 60 * 1e3,
|
|
15658
|
+
env: { ...process.env, CI: "true" }
|
|
15659
|
+
});
|
|
15660
|
+
console.log("[Daemon] EP1386: Package bootstrap completed");
|
|
15661
|
+
} catch (buildError) {
|
|
15662
|
+
const errorMsg = buildError instanceof Error ? buildError.message : String(buildError);
|
|
15663
|
+
await worktreeManager.updateWorktreeStatus(moduleUid, "error", errorMsg);
|
|
15664
|
+
await this.updateModuleWorktreeStatus(moduleUid, "error", worktreePath, errorMsg);
|
|
15665
|
+
throw new Error(`Package bootstrap failed: ${errorMsg}`);
|
|
15653
15666
|
}
|
|
15654
15667
|
}
|
|
15655
15668
|
if (setupScript) {
|
|
@@ -15731,8 +15744,8 @@ var Daemon = class _Daemon {
|
|
|
15731
15744
|
await this.shutdown();
|
|
15732
15745
|
try {
|
|
15733
15746
|
const pidPath = getPidFilePath();
|
|
15734
|
-
if (
|
|
15735
|
-
|
|
15747
|
+
if (fs29.existsSync(pidPath)) {
|
|
15748
|
+
fs29.unlinkSync(pidPath);
|
|
15736
15749
|
console.log("[Daemon] PID file cleaned up");
|
|
15737
15750
|
}
|
|
15738
15751
|
} catch (error) {
|