episoda 0.2.122 → 0.2.123

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.
@@ -2815,7 +2815,7 @@ var require_package = __commonJS({
2815
2815
  "package.json"(exports2, module2) {
2816
2816
  module2.exports = {
2817
2817
  name: "episoda",
2818
- version: "0.2.121",
2818
+ version: "0.2.122",
2819
2819
  description: "CLI tool for Episoda local development workflow orchestration",
2820
2820
  main: "dist/index.js",
2821
2821
  types: "dist/index.d.ts",
@@ -9014,12 +9014,12 @@ If changes are needed, explain what needs to be done.`;
9014
9014
  }
9015
9015
  const useOAuth = !!session.credentials.oauthToken;
9016
9016
  const useApiKey = !useOAuth && !!session.credentials.apiKey;
9017
+ const sessionCodexDir = path20.join(os6.homedir(), ".codex", "sessions", sessionId);
9018
+ const sessionClaudeDir = path20.join(os6.homedir(), ".claude", "sessions", sessionId);
9017
9019
  if (provider === "codex") {
9018
9020
  await this.withConfigLock(async () => {
9019
- const codexDir = path20.join(os6.homedir(), ".codex");
9020
- if (!fs19.existsSync(codexDir)) {
9021
- fs19.mkdirSync(codexDir, { recursive: true });
9022
- }
9021
+ fs19.mkdirSync(sessionCodexDir, { recursive: true });
9022
+ console.log(`[AgentManager] EP1260: Created session-specific Codex dir: ${sessionCodexDir}`);
9023
9023
  if (useOAuth) {
9024
9024
  const codexConfig = generateCodexConfig({
9025
9025
  accessToken: session.credentials.oauthToken,
@@ -9028,23 +9028,13 @@ If changes are needed, explain what needs to be done.`;
9028
9028
  accountId: session.credentials.accountId,
9029
9029
  expiresAt: session.credentials.expiresAt
9030
9030
  }, session.projectPath);
9031
- const authJsonPath = path20.join(codexDir, "auth.json");
9031
+ const authJsonPath = path20.join(sessionCodexDir, "auth.json");
9032
9032
  fs19.writeFileSync(authJsonPath, codexConfig["auth.json"], { mode: 384 });
9033
- console.log("[AgentManager] EP1133: Wrote Codex auth.json to ~/.codex/auth.json");
9033
+ console.log(`[AgentManager] EP1260: Wrote Codex auth.json to ${authJsonPath}`);
9034
9034
  if (codexConfig["config.toml"]) {
9035
- const configTomlPath = path20.join(codexDir, "config.toml");
9036
- let existingConfig = "";
9037
- try {
9038
- existingConfig = fs19.readFileSync(configTomlPath, "utf-8");
9039
- } catch {
9040
- }
9041
- const escapedPathForRegex = session.projectPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9042
- const projectKeyPattern = new RegExp(`\\[projects\\."${escapedPathForRegex}"\\]`);
9043
- const projectAlreadyTrusted = projectKeyPattern.test(existingConfig);
9044
- if (!projectAlreadyTrusted) {
9045
- fs19.writeFileSync(configTomlPath, existingConfig + "\n" + codexConfig["config.toml"], { mode: 420 });
9046
- console.log("[AgentManager] EP1133: Updated Codex config.toml with project trust");
9047
- }
9035
+ const configTomlPath = path20.join(sessionCodexDir, "config.toml");
9036
+ fs19.writeFileSync(configTomlPath, codexConfig["config.toml"], { mode: 420 });
9037
+ console.log(`[AgentManager] EP1260: Wrote Codex config.toml to ${configTomlPath}`);
9048
9038
  }
9049
9039
  } else if (useApiKey) {
9050
9040
  console.log("[AgentManager] EP1133: Using Codex with API key (OPENAI_API_KEY)");
@@ -9052,16 +9042,11 @@ If changes are needed, explain what needs to be done.`;
9052
9042
  });
9053
9043
  } else {
9054
9044
  await this.withConfigLock(async () => {
9055
- const claudeDir = path20.join(os6.homedir(), ".claude");
9056
- const credentialsPath = path20.join(claudeDir, ".credentials.json");
9057
- const statsigDir = path20.join(claudeDir, "statsig");
9058
- if (!fs19.existsSync(claudeDir)) {
9059
- fs19.mkdirSync(claudeDir, { recursive: true });
9060
- }
9061
- if (!fs19.existsSync(statsigDir)) {
9062
- fs19.mkdirSync(statsigDir, { recursive: true });
9063
- }
9045
+ const statsigDir = path20.join(sessionClaudeDir, "statsig");
9046
+ fs19.mkdirSync(statsigDir, { recursive: true });
9047
+ console.log(`[AgentManager] EP1260: Created session-specific Claude dir: ${sessionClaudeDir}`);
9064
9048
  if (useOAuth) {
9049
+ const credentialsPath = path20.join(sessionClaudeDir, ".credentials.json");
9065
9050
  const oauthCredentials = {
9066
9051
  accessToken: session.credentials.oauthToken
9067
9052
  };
@@ -9078,7 +9063,7 @@ If changes are needed, explain what needs to be done.`;
9078
9063
  claudeAiOauth: oauthCredentials
9079
9064
  }, null, 2);
9080
9065
  fs19.writeFileSync(credentialsPath, credentialsContent, { mode: 384 });
9081
- console.log("[AgentManager] Wrote OAuth credentials to ~/.claude/.credentials.json");
9066
+ console.log(`[AgentManager] EP1260: Wrote OAuth credentials to ${credentialsPath}`);
9082
9067
  try {
9083
9068
  const claudeConfig = generateClaudeConfig({
9084
9069
  githubToken: session.credentials.githubToken
@@ -9089,13 +9074,13 @@ If changes are needed, explain what needs to be done.`;
9089
9074
  if (!hasEvaluations || !hasStableId) {
9090
9075
  throw new Error(`Invalid statsig config: missing required files`);
9091
9076
  }
9092
- const settingsPath = path20.join(claudeDir, "settings.json");
9077
+ const settingsPath = path20.join(sessionClaudeDir, "settings.json");
9093
9078
  fs19.writeFileSync(settingsPath, claudeConfig["settings.json"], { mode: 384 });
9094
9079
  for (const [filename, content] of Object.entries(claudeConfig.statsig)) {
9095
9080
  const filePath = path20.join(statsigDir, filename);
9096
9081
  fs19.writeFileSync(filePath, content, { mode: 420 });
9097
9082
  }
9098
- console.log("[AgentManager] Wrote Claude config files");
9083
+ console.log("[AgentManager] EP1260: Wrote Claude config files to session directory");
9099
9084
  } catch (configError) {
9100
9085
  console.warn("[AgentManager] Failed to write Claude config files:", configError instanceof Error ? configError.message : configError);
9101
9086
  }
@@ -9113,6 +9098,13 @@ If changes are needed, explain what needs to be done.`;
9113
9098
  // MCP servers inherit these from the Claude Code process
9114
9099
  MODULE_UID: session.moduleUid
9115
9100
  };
9101
+ if (provider === "codex") {
9102
+ envVars.CODEX_HOME = sessionCodexDir;
9103
+ console.log(`[AgentManager] EP1260: Set CODEX_HOME=${sessionCodexDir}`);
9104
+ } else {
9105
+ envVars.CLAUDE_CONFIG_DIR = sessionClaudeDir;
9106
+ console.log(`[AgentManager] EP1260: Set CLAUDE_CONFIG_DIR=${sessionClaudeDir}`);
9107
+ }
9116
9108
  if (!envVars.DEV_ENVIRONMENT_ID) {
9117
9109
  envVars.DEV_ENVIRONMENT_ID = process.env.EPISODA_CONTAINER_ID || process.env.EPISODA_MACHINE_ID || "";
9118
9110
  if (envVars.DEV_ENVIRONMENT_ID) {
@@ -9361,6 +9353,25 @@ If changes are needed, explain what needs to be done.`;
9361
9353
  this.removePidFile(sessionId);
9362
9354
  console.log(`[AgentManager] Session ${sessionId} stopped`);
9363
9355
  }
9356
+ /**
9357
+ * EP1260: Clean up session-specific credential directories
9358
+ * Call this when a session is truly ended (not just paused/stopped)
9359
+ * e.g., module state transition, explicit session close, etc.
9360
+ */
9361
+ cleanupSessionCredentials(sessionId, provider) {
9362
+ const providers = provider ? [provider] : ["claude", "codex"];
9363
+ for (const p of providers) {
9364
+ const sessionDir = p === "codex" ? path20.join(os6.homedir(), ".codex", "sessions", sessionId) : path20.join(os6.homedir(), ".claude", "sessions", sessionId);
9365
+ try {
9366
+ if (fs19.existsSync(sessionDir)) {
9367
+ fs19.rmSync(sessionDir, { recursive: true, force: true });
9368
+ console.log(`[AgentManager] EP1260: Cleaned up ${p} session credentials: ${sessionDir}`);
9369
+ }
9370
+ } catch (error) {
9371
+ console.warn(`[AgentManager] EP1260: Failed to clean up ${p} session credentials:`, error);
9372
+ }
9373
+ }
9374
+ }
9364
9375
  /**
9365
9376
  * Stop all active sessions
9366
9377
  */