replicas-engine 0.1.336 → 0.1.338

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.
Files changed (2) hide show
  1. package/dist/src/index.js +81 -36
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -15,6 +15,10 @@ function isRecord(value) {
15
15
  }
16
16
 
17
17
  // ../shared/src/agent.ts
18
+ var VALID_AGENT_PROVIDERS = ["claude", "codex", "cursor", "relay"];
19
+ var VALID_CODING_AGENT_PROVIDERS = VALID_AGENT_PROVIDERS.filter(
20
+ (provider) => provider !== "relay"
21
+ );
18
22
  var CODEX_REASONING_EFFORT_BY_THINKING_LEVEL = {
19
23
  low: "low",
20
24
  medium: "medium",
@@ -291,7 +295,7 @@ var WORKSPACE_SIZES = ["small", "large"];
291
295
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
292
296
 
293
297
  // ../shared/src/e2b.ts
294
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-22-v2";
298
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-22-v4";
295
299
 
296
300
  // ../shared/src/runtime-env.ts
297
301
  function parsePosixEnvFile(content) {
@@ -3648,10 +3652,11 @@ var GitService = class {
3648
3652
  const states = [];
3649
3653
  for (const repo of repos) {
3650
3654
  try {
3651
- const [persistedState, currentBranchRaw, gitDiff] = await Promise.all([
3655
+ const [persistedState, currentBranchRaw, gitDiff, provider] = await Promise.all([
3652
3656
  loadRepoState(repo.name),
3653
3657
  getCurrentBranch(repo.path),
3654
- this.getGitDiffStats(repo.path, repo.defaultBranch)
3658
+ this.getGitDiffStats(repo.path, repo.defaultBranch),
3659
+ this.resolveCodeHostProvider(repo.path)
3655
3660
  ]);
3656
3661
  const currentBranch = currentBranchRaw ?? repo.defaultBranch;
3657
3662
  const fullDiff = includeDiffs && gitDiff ? await this.getFullGitDiff(repo.path, repo.defaultBranch) : void 0;
@@ -3663,7 +3668,8 @@ var GitService = class {
3663
3668
  prUrls: persistedState?.prUrls ?? [],
3664
3669
  // fullDiff may be empty if the diff subprocess fails.
3665
3670
  gitDiff: includeDiffs && gitDiff ? { ...gitDiff, fullDiff: fullDiff ?? "" } : gitDiff,
3666
- startHooksCompleted: persistedState?.startHooksCompleted ?? false
3671
+ startHooksCompleted: persistedState?.startHooksCompleted ?? false,
3672
+ provider
3667
3673
  });
3668
3674
  } catch {
3669
3675
  }
@@ -4026,6 +4032,10 @@ var GitService = class {
4026
4032
  return { status: "error" };
4027
4033
  }
4028
4034
  }
4035
+ async resolveCodeHostProvider(repoPath) {
4036
+ const origin = await this.getOriginInfo(repoPath);
4037
+ return origin.provider === "unknown" ? void 0 : origin.provider;
4038
+ }
4029
4039
  async getOriginInfo(repoPath) {
4030
4040
  const cached = this.originInfoCache.get(repoPath);
4031
4041
  if (cached !== void 0) {
@@ -4169,7 +4179,8 @@ var GitService = class {
4169
4179
  currentBranch,
4170
4180
  prUrls,
4171
4181
  gitDiff: await this.getGitDiffStats(repo.path, repo.defaultBranch),
4172
- startHooksCompleted
4182
+ startHooksCompleted,
4183
+ provider: await this.resolveCodeHostProvider(repo.path)
4173
4184
  };
4174
4185
  await saveRepoState(repo.name, state, state);
4175
4186
  return state;
@@ -7497,7 +7508,7 @@ var AspClient = class {
7497
7508
  // src/managers/codex-asp/app-server-process.ts
7498
7509
  var DEFAULT_CODEX_BINARY = "codex";
7499
7510
  var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
7500
- var ENGINE_PACKAGE_VERSION = "0.1.336";
7511
+ var ENGINE_PACKAGE_VERSION = "0.1.338";
7501
7512
  var INITIALIZE_METHOD = "initialize";
7502
7513
  var INITIALIZED_NOTIFICATION = "initialized";
7503
7514
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -9385,8 +9396,29 @@ var CursorManager = class extends CodingAgentManager {
9385
9396
  // src/managers/relay-tools.ts
9386
9397
  import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
9387
9398
  import { z } from "zod";
9399
+
9400
+ // src/managers/relay-providers.ts
9401
+ function getAvailableRelayProviders(availability) {
9402
+ const codexAvailable = availability.codexAvailable ?? false;
9403
+ const cursorAvailable = availability.cursorAvailable ?? false;
9404
+ const providers = ["claude"];
9405
+ if (codexAvailable) providers.push("codex");
9406
+ if (cursorAvailable) providers.push("cursor");
9407
+ providers.push("relay");
9408
+ return providers;
9409
+ }
9410
+ function getAvailableCodeProviders(availability) {
9411
+ return getAvailableRelayProviders(availability).filter((provider) => provider === "codex" || provider === "cursor");
9412
+ }
9413
+
9414
+ // src/managers/relay-tools.ts
9388
9415
  var POLL_INTERVAL_MS = 2e3;
9389
9416
  var DEFAULT_SUBAGENT_TIMEOUT_MS = 6e5;
9417
+ function extractTextBlocks(content, textBlockType, separator = "\n") {
9418
+ if (!Array.isArray(content)) return null;
9419
+ const texts = content.map((block) => block && typeof block === "object" && "type" in block && block.type === textBlockType && "text" in block && typeof block.text === "string" ? block.text : "").filter(Boolean);
9420
+ return texts.length > 0 ? texts.join(separator) : null;
9421
+ }
9390
9422
  async function engineFetch(path5, options) {
9391
9423
  const baseUrl = `http://localhost:${ENGINE_ENV.REPLICAS_ENGINE_PORT}`;
9392
9424
  return fetch(`${baseUrl}${path5}`, {
@@ -9439,21 +9471,12 @@ async function getChatFinalResponse(chatId) {
9439
9471
  }
9440
9472
  if (event.type === "claude-assistant") {
9441
9473
  const message = payload.message;
9442
- if (message?.content) {
9443
- const textBlocks = message.content.filter((block) => block.type === "text" && block.text).map((block) => block.text);
9444
- if (textBlocks.length > 0) {
9445
- return textBlocks.join("\n");
9446
- }
9447
- }
9474
+ const text = extractTextBlocks(message?.content, "text");
9475
+ if (text) return text;
9448
9476
  }
9449
9477
  if (event.type === "response_item" && payload.type === "message" && payload.role === "assistant") {
9450
- const content = payload.content;
9451
- if (Array.isArray(content)) {
9452
- const texts = content.filter((block) => block.type === "output_text" && block.text).map((block) => block.text);
9453
- if (texts.length > 0) {
9454
- return texts.join("\n");
9455
- }
9456
- }
9478
+ const text = extractTextBlocks(payload.content, "output_text");
9479
+ if (text) return text;
9457
9480
  }
9458
9481
  if (event.type === "event_msg" && payload.type === "agent_reasoning") {
9459
9482
  const text = payload.text;
@@ -9461,13 +9484,22 @@ async function getChatFinalResponse(chatId) {
9461
9484
  return text;
9462
9485
  }
9463
9486
  }
9487
+ if (event.type === "cursor-assistant") {
9488
+ const message = payload.message;
9489
+ const text = extractTextBlocks(message?.content, "text", "");
9490
+ if (text) return text;
9491
+ }
9464
9492
  }
9465
9493
  return "[No response from subagent]";
9466
9494
  }
9467
- function buildSpawnAgentTool(parentChatId, codexAvailable = false) {
9468
- const providerEnum = codexAvailable ? z.enum(["claude", "codex", "relay"]) : z.enum(["claude", "relay"]);
9469
- const providerDesc = codexAvailable ? "Which agent to use. Prefer codex for code writing, claude for exploration/analysis, relay for complex multi-step orchestration." : "Which agent to use. Use claude for code writing, exploration, and analysis. Use relay for complex multi-step orchestration.";
9470
- const useCases = codexAvailable ? `- Complex code writing tasks (use provider 'codex' with a capable model)
9495
+ function buildSpawnAgentTool(parentChatId, availability = {}) {
9496
+ const codexAvailable = availability.codexAvailable ?? false;
9497
+ const cursorAvailable = availability.cursorAvailable ?? false;
9498
+ const availableProviders = getAvailableRelayProviders(availability);
9499
+ const providerEnum = z.enum(availableProviders);
9500
+ const codeProviders = getAvailableCodeProviders(availability);
9501
+ const providerDesc = codeProviders.length > 0 ? `Which agent to use. Prefer ${codeProviders.join(" or ")} for code writing, claude for exploration/analysis, relay for complex multi-step orchestration.` : "Which agent to use. Use claude for code writing, exploration, and analysis. Use relay for complex multi-step orchestration.";
9502
+ const useCases = codeProviders.length > 0 ? `- Complex code writing tasks (use provider '${codeProviders.join("' or '")}' with a capable model)
9471
9503
  - Codebase exploration that would consume many tokens (use provider 'claude')` : `- Complex code writing tasks (use provider 'claude')
9472
9504
  - Codebase exploration that would consume many tokens (use provider 'claude')`;
9473
9505
  return tool(
@@ -9484,9 +9516,13 @@ You will also receive the chatId so you can send follow-up messages or clean up
9484
9516
  {
9485
9517
  provider: providerEnum.describe(providerDesc),
9486
9518
  prompt: z.string().describe("The full prompt/instructions for the subagent. Be detailed - it has no context from your conversation."),
9487
- model: z.string().optional().describe(codexAvailable ? `Model override. Claude: ${AGENT_MODELS.claude.join(", ")} (opus[1m] is the default, 1M context, use for very large codebases or huge context tasks). Codex: gpt-5.5, gpt-5.4, gpt-5.3-codex, etc.` : `Model override. Claude: ${AGENT_MODELS.claude.join(", ")} (opus[1m] is the default, 1M context, use for very large codebases or huge context tasks).`),
9519
+ model: z.string().optional().describe([
9520
+ `Model override. Claude: ${AGENT_MODELS.claude.join(", ")} (opus[1m] is the default, 1M context, use for very large codebases or huge context tasks).`,
9521
+ codexAvailable ? "Codex: gpt-5.5, gpt-5.4, gpt-5.3-codex, etc." : null,
9522
+ cursorAvailable ? `Cursor: ${AGENT_MODELS.cursor.join(", ")}.` : null
9523
+ ].filter(Boolean).join(" ")),
9488
9524
  thinking_level: z.enum(["low", "medium", "high", "max"]).optional().describe(
9489
- "Controls how much thinking/reasoning the subagent applies. low = light thinking, medium = moderate, high = deep reasoning, max = maximum effort. Defaults: Claude = high, Codex = medium."
9525
+ "Controls how much thinking/reasoning the subagent applies. low = light thinking, medium = moderate, high = deep reasoning, max = maximum effort. Defaults: Claude = high, Codex = medium, Cursor = medium."
9490
9526
  ),
9491
9527
  title: z.string().optional().describe("Optional title for the subagent chat (for identification)."),
9492
9528
  timeout_minutes: z.number().positive().optional().describe("Timeout in minutes for the subagent to complete (default: 10). Set higher for large tasks to avoid losing work.")
@@ -9554,7 +9590,7 @@ The tool blocks until the subagent completes and returns its response.`,
9554
9590
  message: z.string().describe("The follow-up message to send."),
9555
9591
  model: z.string().optional().describe("Optional model override for this message."),
9556
9592
  thinking_level: z.enum(["low", "medium", "high", "max"]).optional().describe(
9557
- "Controls how much thinking/reasoning the subagent applies. low = light thinking, medium = moderate, high = deep reasoning, max = maximum effort. Defaults: Claude = high, Codex = medium."
9593
+ "Controls how much thinking/reasoning the subagent applies. low = light thinking, medium = moderate, high = deep reasoning, max = maximum effort. Defaults: Claude = high, Codex = medium, Cursor = medium."
9558
9594
  ),
9559
9595
  timeout_minutes: z.number().positive().optional().describe("Timeout in minutes for the subagent to complete (default: 10). Set higher for large tasks to avoid losing work.")
9560
9596
  },
@@ -9612,11 +9648,11 @@ var deleteAgentTool = tool(
9612
9648
  }
9613
9649
  }
9614
9650
  );
9615
- function createRelayMcpServer(parentChatId, codexAvailable = false) {
9651
+ function createRelayMcpServer(parentChatId, availability = {}) {
9616
9652
  return createSdkMcpServer({
9617
9653
  name: "relay-subagent-tools",
9618
9654
  version: "1.0.0",
9619
- tools: [buildSpawnAgentTool(parentChatId, codexAvailable), messageAgentTool, deleteAgentTool]
9655
+ tools: [buildSpawnAgentTool(parentChatId, availability), messageAgentTool, deleteAgentTool]
9620
9656
  });
9621
9657
  }
9622
9658
 
@@ -9718,11 +9754,15 @@ function getUsingToolsSection() {
9718
9754
  ];
9719
9755
  return [`# Using your tools`, ...prependBullets(items)].join("\n");
9720
9756
  }
9721
- function getDelegationSection(codexAvailable) {
9722
- const providerList = codexAvailable ? "claude, codex, or relay" : "claude or relay";
9757
+ function getDelegationSection(codexAvailable, cursorAvailable) {
9758
+ const providerList = getAvailableRelayProviders({ codexAvailable, cursorAvailable }).join(", ");
9723
9759
  const spawnDesc = `Create a new subagent with a specific provider (${providerList}), send it a prompt, and wait for its response. Returns the chatId and the agent's final response. You can set a custom timeout via the timeout_minutes parameter (default: 10 minutes).`;
9724
9760
  const claudeModelList = AGENT_MODELS.claude.join(", ");
9725
- const agentSelectionLines = codexAvailable ? `Use provider 'codex' for heavy code writing, implementation, and large refactors. Suggested models: gpt-5.5 (default), gpt-5.4, gpt-5.3-codex.
9761
+ const extraAgentLines = [
9762
+ codexAvailable ? `Use provider 'codex' for heavy code writing, implementation, and large refactors. Suggested models: gpt-5.5 (default), gpt-5.4, gpt-5.3-codex.` : null,
9763
+ cursorAvailable ? `Use provider 'cursor' for fast iteration on code changes. Suggested models: ${AGENT_MODELS.cursor.join(", ")}.` : null
9764
+ ].filter(Boolean);
9765
+ const agentSelectionLines = extraAgentLines.length > 0 ? `${extraAgentLines.join("\n\n")}
9726
9766
 
9727
9767
  Use provider 'claude' for codebase exploration, code review, planning, complex debugging, and tasks requiring nuanced architectural understanding. Suggested models: ${claudeModelList} (opus[1m] is the default, 1M context window, use for very large codebases; sonnet is faster).` : `Use provider 'claude' for all tasks including code writing, codebase exploration, code review, planning, complex debugging, and tasks requiring nuanced architectural understanding. Suggested models: ${claudeModelList} (opus[1m] is the default, 1M context window, use for very large codebases; sonnet is faster).`;
9728
9768
  return `# Delegation
@@ -9842,14 +9882,14 @@ function getEnvironmentSection() {
9842
9882
  ].join("\n");
9843
9883
  }
9844
9884
  function buildRelaySystemPrompt(options) {
9845
- const { customInstructions, codexAvailable } = options ?? {};
9885
+ const { customInstructions, codexAvailable, cursorAvailable } = options ?? {};
9846
9886
  const sections = [
9847
9887
  getIntroSection(),
9848
9888
  getSystemSection(),
9849
9889
  getDoingTasksSection(),
9850
9890
  getActionsSection(),
9851
9891
  getUsingToolsSection(),
9852
- getDelegationSection(codexAvailable ?? false),
9892
+ getDelegationSection(codexAvailable ?? false, cursorAvailable ?? false),
9853
9893
  getToneAndStyleSection(),
9854
9894
  getOutputEfficiencySection(),
9855
9895
  getEnvironmentSection(),
@@ -9880,12 +9920,13 @@ var RelayManager = class {
9880
9920
  inner;
9881
9921
  constructor(options) {
9882
9922
  const codexAvailable = options.codexAvailable ?? false;
9923
+ const cursorAvailable = options.cursorAvailable ?? false;
9883
9924
  this.inner = new ClaudeManager({
9884
9925
  ...options,
9885
- systemPromptOverride: (customInstructions) => buildRelaySystemPrompt({ customInstructions, codexAvailable }),
9926
+ systemPromptOverride: (customInstructions) => buildRelaySystemPrompt({ customInstructions, codexAvailable, cursorAvailable }),
9886
9927
  tools: RELAY_TOOLS,
9887
9928
  mcpServers: {
9888
- "relay-subagent-tools": createRelayMcpServer(options.chatId, codexAvailable)
9929
+ "relay-subagent-tools": createRelayMcpServer(options.chatId, { codexAvailable, cursorAvailable })
9889
9930
  },
9890
9931
  envOverrides: {
9891
9932
  CLAUDE_CODE_STREAM_CLOSE_TIMEOUT: "900000"
@@ -10252,6 +10293,9 @@ function isChatMessageSender(value) {
10252
10293
  function isCodexAvailable() {
10253
10294
  return existsSync7(CODEX_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENAI_API_KEY);
10254
10295
  }
10296
+ function isCursorAvailable() {
10297
+ return Boolean(ENGINE_ENV.CURSOR_API_KEY);
10298
+ }
10255
10299
  function isSameAcceptedUserEvent(event, acceptedEvent) {
10256
10300
  if (areSameUserMessageEvents(event, acceptedEvent)) return true;
10257
10301
  const eventMessage = getUserMessage(event);
@@ -10693,7 +10737,8 @@ var ChatService = class {
10693
10737
  onTurnComplete: onProviderTurnComplete,
10694
10738
  onEvent: onProviderEvent,
10695
10739
  chatId: persisted.id,
10696
- codexAvailable: isCodexAvailable()
10740
+ codexAvailable: isCodexAvailable(),
10741
+ cursorAvailable: isCursorAvailable()
10697
10742
  });
10698
10743
  } else if (persisted.provider === "cursor") {
10699
10744
  provider = new CursorManager({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.336",
3
+ "version": "0.1.338",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",