@episoda/cli 0.2.174 → 0.2.175
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.
|
@@ -2996,7 +2996,7 @@ var require_package = __commonJS({
|
|
|
2996
2996
|
"package.json"(exports2, module2) {
|
|
2997
2997
|
module2.exports = {
|
|
2998
2998
|
name: "@episoda/cli",
|
|
2999
|
-
version: "0.2.
|
|
2999
|
+
version: "0.2.175",
|
|
3000
3000
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
3001
3001
|
main: "dist/index.js",
|
|
3002
3002
|
types: "dist/index.d.ts",
|
|
@@ -7630,26 +7630,12 @@ var AgentControlPlane = class {
|
|
|
7630
7630
|
const existingSession = this.sessions.get(sessionId);
|
|
7631
7631
|
if (existingSession) {
|
|
7632
7632
|
if (existingSession.provider === provider && existingSession.moduleId === moduleId) {
|
|
7633
|
-
console.log(`[AgentManager]
|
|
7633
|
+
console.log(`[AgentManager] EP1417: Session ${sessionId} already exists, acknowledging duplicate start`);
|
|
7634
7634
|
if (requestedWorkspaceId && !normalizeWorkspaceId(existingSession.workspaceId)) {
|
|
7635
7635
|
existingSession.workspaceId = requestedWorkspaceId;
|
|
7636
7636
|
console.log(`[AgentManager] EP1357: Updated session ${sessionId} workspaceId from start options`);
|
|
7637
7637
|
}
|
|
7638
|
-
return
|
|
7639
|
-
sessionId,
|
|
7640
|
-
message,
|
|
7641
|
-
isFirstMessage: false,
|
|
7642
|
-
// Not first since session exists
|
|
7643
|
-
canWrite,
|
|
7644
|
-
readOnlyReason,
|
|
7645
|
-
onChunk,
|
|
7646
|
-
onToolUse,
|
|
7647
|
-
// EP1236: Pass tool use callback
|
|
7648
|
-
onToolResult,
|
|
7649
|
-
// EP1311: Pass tool result callback
|
|
7650
|
-
onComplete,
|
|
7651
|
-
onError
|
|
7652
|
-
});
|
|
7638
|
+
return { success: true };
|
|
7653
7639
|
}
|
|
7654
7640
|
console.log(`[AgentManager] EP1232: Session ${sessionId} exists with incompatible config - provider: ${existingSession.provider} vs ${provider}, module: ${existingSession.moduleId} vs ${moduleId}`);
|
|
7655
7641
|
return { success: false, error: "Session already exists with incompatible configuration" };
|
|
@@ -13609,6 +13595,8 @@ var HealthOrchestrator = class _HealthOrchestrator {
|
|
|
13609
13595
|
this.tunnelPollInterval = null;
|
|
13610
13596
|
// EP833: Track consecutive health check failures per tunnel
|
|
13611
13597
|
this.tunnelHealthFailures = /* @__PURE__ */ new Map();
|
|
13598
|
+
// Restart after 2 consecutive failures
|
|
13599
|
+
this.tunnelRestartCooldownUntil = /* @__PURE__ */ new Map();
|
|
13612
13600
|
// 3 second timeout for health checks
|
|
13613
13601
|
// EP929: Health check polling interval (restored from EP843 removal)
|
|
13614
13602
|
// Health checks are orthogonal to push-based state sync - they detect dead tunnels
|
|
@@ -13623,7 +13611,11 @@ var HealthOrchestrator = class _HealthOrchestrator {
|
|
|
13623
13611
|
this.HEALTH_CHECK_FAILURE_THRESHOLD = 2;
|
|
13624
13612
|
}
|
|
13625
13613
|
static {
|
|
13626
|
-
//
|
|
13614
|
+
// moduleUid -> unix ms
|
|
13615
|
+
this.HEALTH_RESTART_COOLDOWN_MS = 3 * 60 * 1e3;
|
|
13616
|
+
}
|
|
13617
|
+
static {
|
|
13618
|
+
// 3 minutes
|
|
13627
13619
|
this.HEALTH_CHECK_TIMEOUT_MS = 3e3;
|
|
13628
13620
|
}
|
|
13629
13621
|
static {
|
|
@@ -14043,20 +14035,55 @@ var HealthOrchestrator = class _HealthOrchestrator {
|
|
|
14043
14035
|
const isHealthy = await this.checkTunnelHealth(tunnel);
|
|
14044
14036
|
if (isHealthy) {
|
|
14045
14037
|
this.tunnelHealthFailures.delete(tunnel.moduleUid);
|
|
14038
|
+
this.tunnelRestartCooldownUntil.delete(tunnel.moduleUid);
|
|
14046
14039
|
} else {
|
|
14047
14040
|
const failures = (this.tunnelHealthFailures.get(tunnel.moduleUid) || 0) + 1;
|
|
14048
14041
|
this.tunnelHealthFailures.set(tunnel.moduleUid, failures);
|
|
14049
14042
|
console.log(`[Daemon] EP833: Health check failed for ${tunnel.moduleUid} (${failures}/${_HealthOrchestrator.HEALTH_CHECK_FAILURE_THRESHOLD})`);
|
|
14050
|
-
if (failures
|
|
14051
|
-
|
|
14052
|
-
await this.host.withTunnelLock(tunnel.moduleUid, async () => {
|
|
14053
|
-
await this.restartTunnel(tunnel.moduleUid, tunnel.port);
|
|
14054
|
-
});
|
|
14055
|
-
this.tunnelHealthFailures.delete(tunnel.moduleUid);
|
|
14043
|
+
if (failures < _HealthOrchestrator.HEALTH_CHECK_FAILURE_THRESHOLD) {
|
|
14044
|
+
continue;
|
|
14056
14045
|
}
|
|
14046
|
+
const now = Date.now();
|
|
14047
|
+
const cooldownUntil = this.tunnelRestartCooldownUntil.get(tunnel.moduleUid) || 0;
|
|
14048
|
+
if (cooldownUntil > now) {
|
|
14049
|
+
continue;
|
|
14050
|
+
}
|
|
14051
|
+
const healthProjectId = config.project_id || config.projectId;
|
|
14052
|
+
if (healthProjectId) {
|
|
14053
|
+
const activeModuleUids = await this.fetchActiveModuleUids(healthProjectId);
|
|
14054
|
+
if (activeModuleUids && !activeModuleUids.includes(tunnel.moduleUid)) {
|
|
14055
|
+
console.log(`[Daemon] EP1417: Skipping health auto-restart for ${tunnel.moduleUid}; module is no longer active`);
|
|
14056
|
+
await this.retireInactiveTunnel(tunnel.moduleUid);
|
|
14057
|
+
this.tunnelHealthFailures.delete(tunnel.moduleUid);
|
|
14058
|
+
this.tunnelRestartCooldownUntil.delete(tunnel.moduleUid);
|
|
14059
|
+
continue;
|
|
14060
|
+
}
|
|
14061
|
+
}
|
|
14062
|
+
console.log(`[Daemon] EP833: Tunnel unhealthy for ${tunnel.moduleUid}, restarting...`);
|
|
14063
|
+
await this.host.withTunnelLock(tunnel.moduleUid, async () => {
|
|
14064
|
+
await this.restartTunnel(tunnel.moduleUid, tunnel.port);
|
|
14065
|
+
});
|
|
14066
|
+
this.tunnelHealthFailures.delete(tunnel.moduleUid);
|
|
14067
|
+
this.tunnelRestartCooldownUntil.set(
|
|
14068
|
+
tunnel.moduleUid,
|
|
14069
|
+
now + _HealthOrchestrator.HEALTH_RESTART_COOLDOWN_MS
|
|
14070
|
+
);
|
|
14057
14071
|
}
|
|
14058
14072
|
}
|
|
14059
14073
|
}
|
|
14074
|
+
async retireInactiveTunnel(moduleUid) {
|
|
14075
|
+
try {
|
|
14076
|
+
const tunnelManager = getTunnelManager();
|
|
14077
|
+
await tunnelManager.stopTunnel(moduleUid);
|
|
14078
|
+
} catch (error) {
|
|
14079
|
+
console.warn(`[Daemon] EP1417: Failed to stop inactive tunnel for ${moduleUid}:`, error);
|
|
14080
|
+
}
|
|
14081
|
+
try {
|
|
14082
|
+
await stopDevServer(moduleUid);
|
|
14083
|
+
} catch (error) {
|
|
14084
|
+
console.warn(`[Daemon] EP1417: Failed to stop inactive dev server for ${moduleUid}:`, error);
|
|
14085
|
+
}
|
|
14086
|
+
}
|
|
14060
14087
|
/**
|
|
14061
14088
|
* EP833: Check if a tunnel is healthy
|
|
14062
14089
|
* EP1042: Now also verifies dev server ownership (correct worktree)
|