episoda 0.2.130 → 0.2.132

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.
@@ -2823,7 +2823,7 @@ var require_package = __commonJS({
2823
2823
  "package.json"(exports2, module2) {
2824
2824
  module2.exports = {
2825
2825
  name: "episoda",
2826
- version: "0.2.129",
2826
+ version: "0.2.131",
2827
2827
  description: "CLI tool for Episoda local development workflow orchestration",
2828
2828
  main: "dist/index.js",
2829
2829
  types: "dist/index.d.ts",
@@ -8359,6 +8359,35 @@ function generateCodexConfig(credentials, projectPath) {
8359
8359
  }
8360
8360
  return files;
8361
8361
  }
8362
+ function escapeTomlString(value) {
8363
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
8364
+ }
8365
+ function generateCodexMcpConfigToml(servers, projectPath) {
8366
+ const lines = [];
8367
+ if (projectPath) {
8368
+ const escapedPath = escapeTomlString(projectPath);
8369
+ lines.push(`[projects."${escapedPath}"]`);
8370
+ lines.push('trust_level = "trusted"');
8371
+ lines.push("");
8372
+ }
8373
+ for (const server of servers) {
8374
+ lines.push(`[mcp_servers.${server.name}]`);
8375
+ lines.push(`command = "${escapeTomlString(server.command)}"`);
8376
+ if (server.args && server.args.length > 0) {
8377
+ const argsStr = server.args.map((arg) => `"${escapeTomlString(arg)}"`).join(", ");
8378
+ lines.push(`args = [${argsStr}]`);
8379
+ }
8380
+ if (server.env && Object.keys(server.env).length > 0) {
8381
+ lines.push("");
8382
+ lines.push(`[mcp_servers.${server.name}.env]`);
8383
+ for (const [key, value] of Object.entries(server.env)) {
8384
+ lines.push(`${key} = "${escapeTomlString(value)}"`);
8385
+ }
8386
+ }
8387
+ lines.push("");
8388
+ }
8389
+ return lines.join("\n");
8390
+ }
8362
8391
 
8363
8392
  // src/agent/agent-manager.ts
8364
8393
  var import_child_process12 = require("child_process");
@@ -8840,13 +8869,13 @@ var AgentManager = class {
8840
8869
  *
8841
8870
  * Returns MCP server configurations based on:
8842
8871
  * - mcpMode: 'full' includes dev-server, 'standard' does not
8843
- * - DEV_ENVIRONMENT_ID: Required for git-server and dev-server
8872
+ * - moduleUid: Required for git-server and dev-server (DEV_ENVIRONMENT_ID legacy fallback)
8844
8873
  * - githubToken: Required for GitHub MCP
8845
8874
  *
8846
8875
  * MCP servers provide:
8847
8876
  * - workflow-server: Task/module/knowledge operations
8848
- * - git-server: Git operations via API (requires DEV_ENVIRONMENT_ID)
8849
- * - dev-server: File/exec operations via API (requires DEV_ENVIRONMENT_ID, only in 'full' mode)
8877
+ * - git-server: Git operations via API (requires moduleUid)
8878
+ * - dev-server: File/exec operations via API (requires moduleUid, only in 'full' mode)
8850
8879
  * - github: GitHub operations (PRs, issues, etc.) via @modelcontextprotocol/server-github
8851
8880
  */
8852
8881
  getMcpServersForSession(session) {
@@ -8858,7 +8887,7 @@ var AgentManager = class {
8858
8887
  const workflowServerPath = path20.join(mcpDir, "workflow-server.ts");
8859
8888
  const gitServerPath = path20.join(mcpDir, "git-server.ts");
8860
8889
  const devServerPath = path20.join(mcpDir, "dev-server.ts");
8861
- const hasDevEnvId = !!process.env.DEV_ENVIRONMENT_ID || !!process.env.EPISODA_CONTAINER_ID;
8890
+ const hasDevTarget = !!session.moduleUid || !!process.env.DEV_ENVIRONMENT_ID || !!process.env.EPISODA_CONTAINER_ID;
8862
8891
  if (fs19.existsSync(workflowServerPath)) {
8863
8892
  servers.push({
8864
8893
  name: "workflow",
@@ -8867,15 +8896,15 @@ var AgentManager = class {
8867
8896
  } else {
8868
8897
  console.warn(`[AgentManager] EP1233: workflow-server.ts not found at ${workflowServerPath}`);
8869
8898
  }
8870
- if (hasDevEnvId && fs19.existsSync(gitServerPath)) {
8899
+ if (hasDevTarget && fs19.existsSync(gitServerPath)) {
8871
8900
  servers.push({
8872
8901
  name: "git",
8873
8902
  command: `tsx ${gitServerPath}`
8874
8903
  });
8875
- } else if (!hasDevEnvId) {
8876
- console.log("[AgentManager] EP1233: git-server not registered (DEV_ENVIRONMENT_ID not set)");
8904
+ } else if (!hasDevTarget) {
8905
+ console.log("[AgentManager] EP1233: git-server not registered (module UID or env ID missing)");
8877
8906
  }
8878
- if (session.mcpMode === "full" && hasDevEnvId && fs19.existsSync(devServerPath)) {
8907
+ if (session.mcpMode === "full" && hasDevTarget && fs19.existsSync(devServerPath)) {
8879
8908
  servers.push({
8880
8909
  name: "dev",
8881
8910
  command: `tsx ${devServerPath}`
@@ -8961,7 +8990,7 @@ var AgentManager = class {
8961
8990
  * EP1173: Added autonomousMode parameter for permission-free execution
8962
8991
  */
8963
8992
  async startSession(options) {
8964
- const { sessionId, moduleId, moduleUid, projectPath, provider = "claude", autonomousMode = true, canWrite = true, readOnlyReason, mcpMode = "standard", message, credentials, systemPrompt, onChunk, onToolUse, onComplete, onError } = options;
8993
+ const { sessionId, moduleId, moduleUid, projectId, projectPath, provider = "claude", autonomousMode = true, canWrite = true, readOnlyReason, mcpMode = "standard", message, credentials, systemPrompt, onChunk, onToolUse, onComplete, onError } = options;
8965
8994
  const existingSession = this.sessions.get(sessionId);
8966
8995
  if (existingSession) {
8967
8996
  if (existingSession.provider === provider && existingSession.moduleId === moduleId) {
@@ -9013,6 +9042,7 @@ var AgentManager = class {
9013
9042
  sessionId,
9014
9043
  moduleId,
9015
9044
  moduleUid,
9045
+ projectId,
9016
9046
  projectPath,
9017
9047
  provider,
9018
9048
  // EP1133: Store provider in session
@@ -9212,6 +9242,7 @@ If changes are needed, explain what needs to be done.`;
9212
9242
  EPISODA_API_URL: process.env.EPISODA_API_URL || "https://episoda.dev",
9213
9243
  EPISODA_SESSION_TOKEN: sessionToken,
9214
9244
  MODULE_UID: session.moduleUid,
9245
+ EPISODA_PROJECT_ID: session.projectId,
9215
9246
  DEV_ENVIRONMENT_ID: devEnvId
9216
9247
  };
9217
9248
  const githubMcpEnv = {
@@ -9280,18 +9311,83 @@ If changes are needed, explain what needs to be done.`;
9280
9311
  idToken: session.credentials.idToken,
9281
9312
  accountId: session.credentials.accountId,
9282
9313
  expiresAt: session.credentials.expiresAt
9283
- }, session.projectPath);
9314
+ });
9284
9315
  const authJsonPath = path20.join(sessionCodexDir, "auth.json");
9285
9316
  fs19.writeFileSync(authJsonPath, codexConfig["auth.json"], { mode: 384 });
9286
9317
  console.log(`[AgentManager] EP1260: Wrote Codex auth.json to ${authJsonPath}`);
9287
- if (codexConfig["config.toml"]) {
9288
- const configTomlPath = path20.join(sessionCodexDir, "config.toml");
9289
- fs19.writeFileSync(configTomlPath, codexConfig["config.toml"], { mode: 420 });
9290
- console.log(`[AgentManager] EP1260: Wrote Codex config.toml to ${configTomlPath}`);
9291
- }
9292
9318
  } else if (useApiKey) {
9293
9319
  console.log("[AgentManager] EP1133: Using Codex with API key (OPENAI_API_KEY)");
9294
9320
  }
9321
+ const mcpServersToRegister = this.getMcpServersForSession(session);
9322
+ if (mcpServersToRegister.length > 0) {
9323
+ const sessionToken = process.env.EPISODA_ACCESS_TOKEN || process.env.EPISODA_SESSION_TOKEN || "";
9324
+ const devEnvId = process.env.EPISODA_CONTAINER_ID || process.env.EPISODA_MACHINE_ID || "";
9325
+ const essentialEnvKeys = [
9326
+ "PATH",
9327
+ "HOME",
9328
+ "USER",
9329
+ "SHELL",
9330
+ "NODE_PATH",
9331
+ "NODE_OPTIONS",
9332
+ "NPM_CONFIG_PREFIX",
9333
+ "LANG",
9334
+ "LC_ALL",
9335
+ "LC_CTYPE",
9336
+ "TERM",
9337
+ "COLORTERM",
9338
+ "XDG_CONFIG_HOME",
9339
+ "XDG_DATA_HOME",
9340
+ "XDG_CACHE_HOME",
9341
+ "TMPDIR",
9342
+ "TMP",
9343
+ "TEMP"
9344
+ ];
9345
+ const baseEnv = {};
9346
+ for (const key of essentialEnvKeys) {
9347
+ const value = process.env[key];
9348
+ if (value !== void 0) {
9349
+ baseEnv[key] = value;
9350
+ }
9351
+ }
9352
+ const codexMcpServers = mcpServersToRegister.map((server) => {
9353
+ const parts = server.command.split(" ");
9354
+ const command = parts[0];
9355
+ const args2 = parts.slice(1);
9356
+ let env;
9357
+ if (server.name === "github") {
9358
+ env = {
9359
+ ...baseEnv,
9360
+ GITHUB_PERSONAL_ACCESS_TOKEN: session.credentials.githubToken || ""
9361
+ };
9362
+ } else {
9363
+ env = {
9364
+ ...baseEnv,
9365
+ EPISODA_API_URL: process.env.EPISODA_API_URL || "https://episoda.dev",
9366
+ EPISODA_SESSION_TOKEN: sessionToken,
9367
+ MODULE_UID: session.moduleUid || "",
9368
+ EPISODA_PROJECT_ID: session.projectId || "",
9369
+ DEV_ENVIRONMENT_ID: devEnvId
9370
+ };
9371
+ }
9372
+ return {
9373
+ name: server.name,
9374
+ command,
9375
+ args: args2.length > 0 ? args2 : void 0,
9376
+ env
9377
+ };
9378
+ });
9379
+ const configTomlContent = generateCodexMcpConfigToml(codexMcpServers, session.projectPath);
9380
+ const configTomlPath = path20.join(sessionCodexDir, "config.toml");
9381
+ fs19.writeFileSync(configTomlPath, configTomlContent, { mode: 384 });
9382
+ console.log(`[AgentManager] EP1278: Wrote Codex config.toml with ${codexMcpServers.length} MCP server(s): ${codexMcpServers.map((s) => s.name).join(", ")}`);
9383
+ } else {
9384
+ const configTomlContent = generateCodexMcpConfigToml([], session.projectPath);
9385
+ if (configTomlContent.trim()) {
9386
+ const configTomlPath = path20.join(sessionCodexDir, "config.toml");
9387
+ fs19.writeFileSync(configTomlPath, configTomlContent, { mode: 420 });
9388
+ console.log(`[AgentManager] EP1260: Wrote Codex config.toml (project trust only)`);
9389
+ }
9390
+ }
9295
9391
  });
9296
9392
  } else {
9297
9393
  await this.withConfigLock(async () => {
@@ -9349,7 +9445,8 @@ If changes are needed, explain what needs to be done.`;
9349
9445
  FORCE_COLOR: "0",
9350
9446
  // EP1233: MCP server environment variables
9351
9447
  // MCP servers inherit these from the Claude Code process
9352
- MODULE_UID: session.moduleUid
9448
+ MODULE_UID: session.moduleUid,
9449
+ EPISODA_PROJECT_ID: session.projectId
9353
9450
  };
9354
9451
  if (provider === "codex") {
9355
9452
  envVars.CODEX_HOME = sessionCodexDir;
@@ -11477,6 +11574,7 @@ var Daemon = class _Daemon {
11477
11574
  sessionId: cmd.sessionId,
11478
11575
  moduleId: cmd.moduleId,
11479
11576
  moduleUid: cmd.moduleUid,
11577
+ projectId: cmd.projectId,
11480
11578
  projectPath: agentWorkingDir,
11481
11579
  provider: cmd.provider || "claude",
11482
11580
  // EP1133: Multi-provider support