replicas-engine 0.1.328 → 0.1.329

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 +197 -54
  2. package/package.json +2 -1
package/dist/src/index.js CHANGED
@@ -287,7 +287,7 @@ var WORKSPACE_SIZES = ["small", "large"];
287
287
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
288
288
 
289
289
  // ../shared/src/e2b.ts
290
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-19-v2";
290
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-19-v3";
291
291
 
292
292
  // ../shared/src/runtime-env.ts
293
293
  function parsePosixEnvFile(content) {
@@ -2123,11 +2123,13 @@ var DESKTOP_NOVNC_PORT = 6080;
2123
2123
  var DEFAULT_CHAT_TITLES = {
2124
2124
  claude: "Claude Code",
2125
2125
  codex: "Codex",
2126
+ cursor: "Cursor",
2126
2127
  relay: "Relay"
2127
2128
  };
2128
2129
  var CLAUDE_OPUS_1M_MODEL = "opus[1m]";
2129
2130
  var LEGACY_CLAUDE_OPUS_1M_MODEL = "opus-1m";
2130
2131
  var DEFAULT_CODEX_MODEL = "gpt-5.5";
2132
+ var DEFAULT_CURSOR_MODEL = "composer-2";
2131
2133
  function normalizeClaudeModel(model) {
2132
2134
  if (model === LEGACY_CLAUDE_OPUS_1M_MODEL) {
2133
2135
  return CLAUDE_OPUS_1M_MODEL;
@@ -2137,6 +2139,7 @@ function normalizeClaudeModel(model) {
2137
2139
  var AGENT_MODELS = {
2138
2140
  claude: [CLAUDE_OPUS_1M_MODEL, "sonnet", "haiku"],
2139
2141
  codex: [DEFAULT_CODEX_MODEL, "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex", "gpt-5.2"],
2142
+ cursor: [DEFAULT_CURSOR_MODEL, "composer-2.5"],
2140
2143
  relay: [CLAUDE_OPUS_1M_MODEL, "sonnet"]
2141
2144
  };
2142
2145
  var MODEL_LABELS = {
@@ -2146,6 +2149,8 @@ var MODEL_LABELS = {
2146
2149
  [LEGACY_CLAUDE_OPUS_1M_MODEL]: "Opus 4.8 (1M)",
2147
2150
  haiku: "Haiku 4.5",
2148
2151
  [DEFAULT_CODEX_MODEL]: "GPT-5.5",
2152
+ [DEFAULT_CURSOR_MODEL]: "Composer 2",
2153
+ "composer-2.5": "Composer 2.5",
2149
2154
  "gpt-5.4": "GPT-5.4",
2150
2155
  "gpt-5.4-mini": "GPT-5.4 Mini",
2151
2156
  "gpt-5.3-codex": "GPT-5.3 Codex",
@@ -2825,6 +2830,7 @@ function loadEngineEnv() {
2825
2830
  SLACK_THREAD_TS: readEnv("SLACK_THREAD_TS"),
2826
2831
  ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
2827
2832
  OPENAI_API_KEY: readEnv("OPENAI_API_KEY"),
2833
+ CURSOR_API_KEY: readEnv("CURSOR_API_KEY"),
2828
2834
  CLAUDE_CODE_USE_BEDROCK: readEnv("CLAUDE_CODE_USE_BEDROCK"),
2829
2835
  AWS_ACCESS_KEY_ID: readEnv("AWS_ACCESS_KEY_ID"),
2830
2836
  AWS_SECRET_ACCESS_KEY: readEnv("AWS_SECRET_ACCESS_KEY"),
@@ -4198,6 +4204,9 @@ function detectCodexAuthMethod() {
4198
4204
  }
4199
4205
  return "none";
4200
4206
  }
4207
+ function detectCursorAuthMethod() {
4208
+ return ENGINE_ENV.CURSOR_API_KEY ? "api_key" : "none";
4209
+ }
4201
4210
  async function detectGitIdentityConfigured() {
4202
4211
  try {
4203
4212
  const { stdout } = await execFileAsync("git", ["config", "--global", "user.name"]);
@@ -4237,6 +4246,7 @@ function createDefaultDetails() {
4237
4246
  googleAccessConfigured: false,
4238
4247
  claudeAuthMethod: "none",
4239
4248
  codexAuthMethod: "none",
4249
+ cursorAuthMethod: "none",
4240
4250
  lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
4241
4251
  };
4242
4252
  }
@@ -4267,6 +4277,7 @@ var EnvironmentDetailsService = class {
4267
4277
  details.engineVersion = E2B_TEMPLATE_NAME;
4268
4278
  details.claudeAuthMethod = detectClaudeAuthMethod();
4269
4279
  details.codexAuthMethod = detectCodexAuthMethod();
4280
+ details.cursorAuthMethod = detectCursorAuthMethod();
4270
4281
  details.gitIdentityConfigured = gitIdentityConfigured;
4271
4282
  const ghConfigured = existsSync3(GH_HOSTS_PATH);
4272
4283
  details.githubAccessConfigured = ghConfigured;
@@ -5015,9 +5026,9 @@ async function registerDesktopPreview() {
5015
5026
 
5016
5027
  // src/services/chat/chat-service.ts
5017
5028
  import { existsSync as existsSync7 } from "fs";
5018
- import { appendFile as appendFile4, copyFile, mkdir as mkdir11, readFile as readFile13, rename as rename2, rm } from "fs/promises";
5029
+ import { appendFile as appendFile5, copyFile, mkdir as mkdir12, readFile as readFile13, rename as rename2, rm } from "fs/promises";
5019
5030
  import { homedir as homedir14 } from "os";
5020
- import { join as join17 } from "path";
5031
+ import { join as join18 } from "path";
5021
5032
  import { randomUUID as randomUUID5 } from "crypto";
5022
5033
 
5023
5034
  // src/managers/claude-manager.ts
@@ -7291,7 +7302,7 @@ var AspClient = class {
7291
7302
  // src/managers/codex-asp/app-server-process.ts
7292
7303
  var DEFAULT_CODEX_BINARY = "codex";
7293
7304
  var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
7294
- var ENGINE_PACKAGE_VERSION = "0.1.328";
7305
+ var ENGINE_PACKAGE_VERSION = "0.1.329";
7295
7306
  var INITIALIZE_METHOD = "initialize";
7296
7307
  var INITIALIZED_NOTIFICATION = "initialized";
7297
7308
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -9089,6 +9100,120 @@ var CodexAspManager = class extends CodingAgentManager {
9089
9100
  }
9090
9101
  };
9091
9102
 
9103
+ // src/managers/cursor-manager.ts
9104
+ import { appendFile as appendFile4, mkdir as mkdir11 } from "fs/promises";
9105
+ import { dirname as dirname4, join as join15 } from "path";
9106
+ import { Agent as CursorAgent } from "@cursor/sdk";
9107
+ var CursorManager = class extends CodingAgentManager {
9108
+ agent = null;
9109
+ activeRun = null;
9110
+ historyFile;
9111
+ constructor(options) {
9112
+ super(options);
9113
+ this.historyFile = options.historyFilePath ?? join15(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
9114
+ this.initializeManager(this.processMessageInternal.bind(this));
9115
+ }
9116
+ async initialize() {
9117
+ await mkdir11(dirname4(this.historyFile), { recursive: true });
9118
+ }
9119
+ async interruptActiveTurn() {
9120
+ await this.activeRun?.cancel();
9121
+ }
9122
+ async getHistory() {
9123
+ return {
9124
+ thread_id: this.agent?.agentId ?? this.initialSessionId,
9125
+ events: await readJSONL(this.historyFile),
9126
+ goal: null
9127
+ };
9128
+ }
9129
+ async ensureAgent(request) {
9130
+ if (this.agent) return this.agent;
9131
+ const apiKey = ENGINE_ENV.CURSOR_API_KEY;
9132
+ if (!apiKey) {
9133
+ throw new Error("Cursor API key is not configured for this workspace.");
9134
+ }
9135
+ const model = { id: request.model ?? DEFAULT_CURSOR_MODEL };
9136
+ this.agent = this.initialSessionId ? await CursorAgent.resume(this.initialSessionId, {
9137
+ apiKey,
9138
+ model,
9139
+ local: { cwd: this.workingDirectory }
9140
+ }) : await CursorAgent.create({
9141
+ apiKey,
9142
+ model,
9143
+ local: { cwd: this.workingDirectory }
9144
+ });
9145
+ await this.onSaveSessionId(this.agent.agentId);
9146
+ return this.agent;
9147
+ }
9148
+ async processMessageInternal(request) {
9149
+ try {
9150
+ const agent = await this.ensureAgent(request);
9151
+ const message = await this.toCursorMessage(request);
9152
+ this.recordHistoryEvent("event_msg", {
9153
+ type: "user_message",
9154
+ message: request.message
9155
+ });
9156
+ const run = await agent.send(message, {
9157
+ model: { id: request.model ?? DEFAULT_CURSOR_MODEL },
9158
+ mode: request.planMode ? "plan" : "agent"
9159
+ });
9160
+ this.activeRun = run;
9161
+ for await (const event of run.stream()) {
9162
+ this.recordCursorEvent(event);
9163
+ }
9164
+ const result = await run.wait();
9165
+ if (result.status === "error") {
9166
+ this.recordHistoryEvent("cursor-error", {
9167
+ type: "error",
9168
+ message: result.result || "Cursor run failed",
9169
+ runId: result.id
9170
+ });
9171
+ }
9172
+ } catch (error) {
9173
+ this.recordHistoryEvent("cursor-error", {
9174
+ type: "error",
9175
+ message: error instanceof Error ? error.message : String(error)
9176
+ });
9177
+ } finally {
9178
+ this.activeRun = null;
9179
+ await this.onTurnComplete();
9180
+ }
9181
+ }
9182
+ async toCursorMessage(request) {
9183
+ if (!request.images || request.images.length === 0) {
9184
+ return request.message;
9185
+ }
9186
+ const images = await normalizeImages(request.images);
9187
+ return {
9188
+ text: request.message,
9189
+ images: images.map((image) => ({
9190
+ data: image.source.data,
9191
+ mimeType: image.source.media_type
9192
+ }))
9193
+ };
9194
+ }
9195
+ recordCursorEvent(event) {
9196
+ this.recordHistoryEvent(`cursor-${event.type}`, event);
9197
+ }
9198
+ recordHistoryEvent(type, payload) {
9199
+ const eventPayload = {};
9200
+ if (payload && typeof payload === "object") {
9201
+ Object.assign(eventPayload, payload);
9202
+ } else {
9203
+ eventPayload.value = payload;
9204
+ }
9205
+ const event = {
9206
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9207
+ type,
9208
+ payload: eventPayload
9209
+ };
9210
+ this.onEvent(event);
9211
+ appendFile4(this.historyFile, `${JSON.stringify(event)}
9212
+ `, "utf-8").catch(() => {
9213
+ });
9214
+ }
9215
+ };
9216
+
9092
9217
  // src/managers/relay-tools.ts
9093
9218
  import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
9094
9219
  import { z } from "zod";
@@ -9670,10 +9795,10 @@ var keepAliveService = new KeepAliveService();
9670
9795
  // src/services/canvas-service.ts
9671
9796
  import { readdir as readdir4, readFile as readFile11, stat as stat3 } from "fs/promises";
9672
9797
  import { homedir as homedir12 } from "os";
9673
- import { join as join15 } from "path";
9798
+ import { join as join16 } from "path";
9674
9799
  var CANVAS_DIRECTORIES = [
9675
- join15(homedir12(), ".claude", "plans"),
9676
- join15(homedir12(), ".replicas", "canvas")
9800
+ join16(homedir12(), ".claude", "plans"),
9801
+ join16(homedir12(), ".replicas", "canvas")
9677
9802
  ];
9678
9803
  var CanvasService = class {
9679
9804
  async listItems() {
@@ -9692,7 +9817,7 @@ var CanvasService = class {
9692
9817
  const { kind } = classifyCanvasFilename(entry.name);
9693
9818
  let sizeBytes = 0;
9694
9819
  try {
9695
- const s = await stat3(join15(directory, entry.name));
9820
+ const s = await stat3(join16(directory, entry.name));
9696
9821
  sizeBytes = s.size;
9697
9822
  } catch {
9698
9823
  continue;
@@ -9707,7 +9832,7 @@ var CanvasService = class {
9707
9832
  if (!safe) return null;
9708
9833
  const { kind, mimeType } = classifyCanvasFilename(safe);
9709
9834
  for (const directory of CANVAS_DIRECTORIES) {
9710
- const filePath = join15(directory, safe);
9835
+ const filePath = join16(directory, safe);
9711
9836
  let sizeBytes = 0;
9712
9837
  let updatedAt = "";
9713
9838
  try {
@@ -9844,13 +9969,13 @@ async function reconcileCanvasItems(filenames) {
9844
9969
 
9845
9970
  // src/services/upload-chat-transcripts.ts
9846
9971
  import { readdir as readdir5, readFile as readFile12 } from "fs/promises";
9847
- import { basename, join as join16 } from "path";
9972
+ import { basename, join as join17 } from "path";
9848
9973
  import { homedir as homedir13 } from "os";
9849
- var ENGINE_DIR2 = join16(homedir13(), ".replicas", "engine");
9974
+ var ENGINE_DIR2 = join17(homedir13(), ".replicas", "engine");
9850
9975
  var HISTORY_DIRS = [
9851
- join16(ENGINE_DIR2, "claude-histories"),
9852
- join16(ENGINE_DIR2, "relay-histories"),
9853
- join16(ENGINE_DIR2, "codex-histories")
9976
+ join17(ENGINE_DIR2, "claude-histories"),
9977
+ join17(ENGINE_DIR2, "relay-histories"),
9978
+ join17(ENGINE_DIR2, "codex-histories")
9854
9979
  ];
9855
9980
  async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
9856
9981
  let flushed = 0;
@@ -9867,7 +9992,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
9867
9992
  if (!entry.endsWith(".jsonl")) continue;
9868
9993
  const chatId = basename(entry, ".jsonl");
9869
9994
  tasks.push(
9870
- uploadChatTranscript(chatId, join16(dir, entry), chatsById.get(chatId)).then(() => {
9995
+ uploadChatTranscript(chatId, join17(dir, entry), chatsById.get(chatId)).then(() => {
9871
9996
  flushed++;
9872
9997
  }).catch((err) => {
9873
9998
  failed++;
@@ -9937,18 +10062,20 @@ var DuplicateDefaultChatError = class extends Error {
9937
10062
  };
9938
10063
 
9939
10064
  // src/services/chat/chat-service.ts
9940
- var ENGINE_DIR3 = join17(homedir14(), ".replicas", "engine");
9941
- var CHATS_FILE = join17(ENGINE_DIR3, "chats.json");
9942
- var CLAUDE_HISTORY_DIR = join17(ENGINE_DIR3, "claude-histories");
9943
- var RELAY_HISTORY_DIR = join17(ENGINE_DIR3, "relay-histories");
9944
- var CODEX_HISTORY_DIR = join17(ENGINE_DIR3, "codex-histories");
10065
+ var ENGINE_DIR3 = join18(homedir14(), ".replicas", "engine");
10066
+ var CHATS_FILE = join18(ENGINE_DIR3, "chats.json");
10067
+ var CLAUDE_HISTORY_DIR = join18(ENGINE_DIR3, "claude-histories");
10068
+ var RELAY_HISTORY_DIR = join18(ENGINE_DIR3, "relay-histories");
10069
+ var CODEX_HISTORY_DIR = join18(ENGINE_DIR3, "codex-histories");
10070
+ var CURSOR_HISTORY_DIR = join18(ENGINE_DIR3, "cursor-histories");
9945
10071
  var HISTORY_DIR_BY_PROVIDER = {
9946
10072
  claude: CLAUDE_HISTORY_DIR,
9947
10073
  relay: RELAY_HISTORY_DIR,
9948
- codex: CODEX_HISTORY_DIR
10074
+ codex: CODEX_HISTORY_DIR,
10075
+ cursor: CURSOR_HISTORY_DIR
9949
10076
  };
9950
- var CHAT_SENDERS_DIR = join17(ENGINE_DIR3, "chat-senders");
9951
- var CODEX_AUTH_PATH2 = join17(homedir14(), ".codex", "auth.json");
10077
+ var CHAT_SENDERS_DIR = join18(ENGINE_DIR3, "chat-senders");
10078
+ var CODEX_AUTH_PATH2 = join18(homedir14(), ".codex", "auth.json");
9952
10079
  var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
9953
10080
  function isChatMessageSender(value) {
9954
10081
  if (!isRecord4(value)) return false;
@@ -9998,7 +10125,7 @@ function isPersistedChat(value) {
9998
10125
  return false;
9999
10126
  }
10000
10127
  const candidate = value;
10001
- return typeof candidate.id === "string" && (candidate.provider === "claude" || candidate.provider === "codex" || candidate.provider === "relay") && typeof candidate.title === "string" && typeof candidate.createdAt === "string" && typeof candidate.updatedAt === "string" && (candidate.providerSessionId === null || typeof candidate.providerSessionId === "string") && (candidate.parentChatId === void 0 || candidate.parentChatId === null || typeof candidate.parentChatId === "string");
10128
+ return typeof candidate.id === "string" && (candidate.provider === "claude" || candidate.provider === "codex" || candidate.provider === "cursor" || candidate.provider === "relay") && typeof candidate.title === "string" && typeof candidate.createdAt === "string" && typeof candidate.updatedAt === "string" && (candidate.providerSessionId === null || typeof candidate.providerSessionId === "string") && (candidate.parentChatId === void 0 || candidate.parentChatId === null || typeof candidate.parentChatId === "string");
10002
10129
  }
10003
10130
  function normalizePersistedChat(chat) {
10004
10131
  const isLegacyCodexSdkChat = chat.provider === "codex" && (chat.codexBackend === "sdk" || chat.codexBackend === void 0 && chat.providerSessionId !== null);
@@ -10046,11 +10173,12 @@ var ChatService = class {
10046
10173
  persistInFlight = false;
10047
10174
  persistQueued = false;
10048
10175
  async initialize() {
10049
- await mkdir11(ENGINE_DIR3, { recursive: true });
10050
- await mkdir11(CLAUDE_HISTORY_DIR, { recursive: true });
10051
- await mkdir11(RELAY_HISTORY_DIR, { recursive: true });
10052
- await mkdir11(CODEX_HISTORY_DIR, { recursive: true });
10053
- await mkdir11(CHAT_SENDERS_DIR, { recursive: true });
10176
+ await mkdir12(ENGINE_DIR3, { recursive: true });
10177
+ await mkdir12(CLAUDE_HISTORY_DIR, { recursive: true });
10178
+ await mkdir12(RELAY_HISTORY_DIR, { recursive: true });
10179
+ await mkdir12(CODEX_HISTORY_DIR, { recursive: true });
10180
+ await mkdir12(CURSOR_HISTORY_DIR, { recursive: true });
10181
+ await mkdir12(CHAT_SENDERS_DIR, { recursive: true });
10054
10182
  const persisted = await this.loadChats();
10055
10183
  for (const chat of persisted) {
10056
10184
  const runtime = this.createRuntimeChat(chat);
@@ -10062,12 +10190,18 @@ var ChatService = class {
10062
10190
  const hasCodexDefault = [...this.chats.values()].some(
10063
10191
  (c) => c.persisted.provider === "codex" && c.persisted.title === "Codex"
10064
10192
  );
10193
+ const hasCursorDefault = [...this.chats.values()].some(
10194
+ (c) => c.persisted.provider === "cursor" && c.persisted.title === "Cursor"
10195
+ );
10065
10196
  if (!hasClaudeDefault) {
10066
10197
  await this.createChat({ provider: "claude", title: "Claude Code" });
10067
10198
  }
10068
10199
  if (!hasCodexDefault) {
10069
10200
  await this.createChat({ provider: "codex", title: "Codex" });
10070
10201
  }
10202
+ if (!hasCursorDefault) {
10203
+ await this.createChat({ provider: "cursor", title: "Cursor" });
10204
+ }
10071
10205
  const hasRelayDefault = [...this.chats.values()].some(
10072
10206
  (c) => c.persisted.provider === "relay" && c.persisted.title === "Relay"
10073
10207
  );
@@ -10149,11 +10283,11 @@ var ChatService = class {
10149
10283
  };
10150
10284
  }
10151
10285
  senderFilePath(chatId) {
10152
- return join17(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
10286
+ return join18(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
10153
10287
  }
10154
10288
  async appendSender(chatId, sender) {
10155
10289
  try {
10156
- await appendFile4(this.senderFilePath(chatId), JSON.stringify(sender) + "\n", "utf-8");
10290
+ await appendFile5(this.senderFilePath(chatId), JSON.stringify(sender) + "\n", "utf-8");
10157
10291
  } catch (error) {
10158
10292
  console.error("[ChatService] Failed to append sender record:", error);
10159
10293
  }
@@ -10305,7 +10439,7 @@ var ChatService = class {
10305
10439
  return descendants;
10306
10440
  }
10307
10441
  async deleteHistoryFile(persisted) {
10308
- await rm(join17(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
10442
+ await rm(join18(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
10309
10443
  await rm(this.senderFilePath(persisted.id), { force: true });
10310
10444
  }
10311
10445
  async getChatHistory(chatId) {
@@ -10376,7 +10510,7 @@ var ChatService = class {
10376
10510
  if (persisted.provider === "claude") {
10377
10511
  provider = new ClaudeManager({
10378
10512
  workingDirectory: this.workingDirectory,
10379
- historyFilePath: join17(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
10513
+ historyFilePath: join18(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
10380
10514
  initialSessionId: persisted.providerSessionId,
10381
10515
  onSaveSessionId: saveSession,
10382
10516
  onTurnComplete: onProviderTurnComplete,
@@ -10385,7 +10519,7 @@ var ChatService = class {
10385
10519
  } else if (persisted.provider === "relay") {
10386
10520
  provider = new RelayManager({
10387
10521
  workingDirectory: this.workingDirectory,
10388
- historyFilePath: join17(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
10522
+ historyFilePath: join18(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
10389
10523
  initialSessionId: persisted.providerSessionId,
10390
10524
  onSaveSessionId: saveSession,
10391
10525
  onTurnComplete: onProviderTurnComplete,
@@ -10393,10 +10527,19 @@ var ChatService = class {
10393
10527
  chatId: persisted.id,
10394
10528
  codexAvailable: isCodexAvailable()
10395
10529
  });
10530
+ } else if (persisted.provider === "cursor") {
10531
+ provider = new CursorManager({
10532
+ workingDirectory: this.workingDirectory,
10533
+ historyFilePath: join18(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
10534
+ initialSessionId: persisted.providerSessionId,
10535
+ onSaveSessionId: saveSession,
10536
+ onTurnComplete: onProviderTurnComplete,
10537
+ onEvent: onProviderEvent
10538
+ });
10396
10539
  } else {
10397
10540
  provider = new CodexAspManager({
10398
10541
  workingDirectory: this.workingDirectory,
10399
- historyFilePath: join17(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
10542
+ historyFilePath: join18(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
10400
10543
  initialSessionId: persisted.providerSessionId,
10401
10544
  onSaveSessionId: saveSession,
10402
10545
  onTurnComplete: onProviderTurnComplete,
@@ -10535,7 +10678,7 @@ var ChatService = class {
10535
10678
  });
10536
10679
  uploadChatTranscript(
10537
10680
  chatId,
10538
- join17(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
10681
+ join18(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
10539
10682
  this.toSummary(chat)
10540
10683
  ).catch((err) => {
10541
10684
  console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
@@ -10651,7 +10794,7 @@ var ChatService = class {
10651
10794
  // src/services/repo-file-service.ts
10652
10795
  import { execFile as execFile2 } from "child_process";
10653
10796
  import { readFile as readFile14, realpath, stat as stat4 } from "fs/promises";
10654
- import { join as join18, resolve as resolve2, extname } from "path";
10797
+ import { join as join19, resolve as resolve2, extname } from "path";
10655
10798
  var CACHE_TTL_MS = 3e4;
10656
10799
  var SEARCH_TIMEOUT_MS = 15e3;
10657
10800
  var MAX_CONTENT_BYTES = 256 * 1024;
@@ -10811,7 +10954,7 @@ var RepoFileService = class {
10811
10954
  const repo = repos.find((r) => r.name === repoName);
10812
10955
  if (!repo) return null;
10813
10956
  try {
10814
- const fullPath = await realpath(resolve2(join18(repo.path, filePath)));
10957
+ const fullPath = await realpath(resolve2(join19(repo.path, filePath)));
10815
10958
  const repoRoot = await realpath(repo.path);
10816
10959
  const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
10817
10960
  if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
@@ -10919,20 +11062,20 @@ var RepoFileService = class {
10919
11062
  import { Hono } from "hono";
10920
11063
  import { z as z2 } from "zod";
10921
11064
  import { readdir as readdir7, stat as stat5, readFile as readFile17 } from "fs/promises";
10922
- import { join as join21, resolve as resolve3 } from "path";
11065
+ import { join as join22, resolve as resolve3 } from "path";
10923
11066
 
10924
11067
  // src/services/warm-hooks-service.ts
10925
11068
  import { spawn as spawn4 } from "child_process";
10926
11069
  import { readFile as readFile16 } from "fs/promises";
10927
11070
  import { existsSync as existsSync8 } from "fs";
10928
- import { join as join20 } from "path";
11071
+ import { join as join21 } from "path";
10929
11072
 
10930
11073
  // src/services/warm-hook-logs-service.ts
10931
- import { mkdir as mkdir12, readFile as readFile15, writeFile as writeFile6, readdir as readdir6, appendFile as appendFile5, unlink as unlink3 } from "fs/promises";
11074
+ import { mkdir as mkdir13, readFile as readFile15, writeFile as writeFile6, readdir as readdir6, appendFile as appendFile6, unlink as unlink3 } from "fs/promises";
10932
11075
  import { homedir as homedir15 } from "os";
10933
- import { join as join19 } from "path";
10934
- var LOGS_DIR2 = join19(homedir15(), ".replicas", "warm-hook-logs");
10935
- var CURRENT_RUN_LOG = join19(LOGS_DIR2, "current-run.log");
11076
+ import { join as join20 } from "path";
11077
+ var LOGS_DIR2 = join20(homedir15(), ".replicas", "warm-hook-logs");
11078
+ var CURRENT_RUN_LOG = join20(LOGS_DIR2, "current-run.log");
10936
11079
  var GLOBAL_FILENAME = "global.json";
10937
11080
  function withPreview2(stored) {
10938
11081
  const preview = buildHookOutputPreview(stored.output);
@@ -10940,7 +11083,7 @@ function withPreview2(stored) {
10940
11083
  }
10941
11084
  var WarmHookLogsService = class {
10942
11085
  async ensureDir() {
10943
- await mkdir12(LOGS_DIR2, { recursive: true });
11086
+ await mkdir13(LOGS_DIR2, { recursive: true });
10944
11087
  }
10945
11088
  async saveGlobalHookLog(entry) {
10946
11089
  await this.ensureDir();
@@ -10949,7 +11092,7 @@ var WarmHookLogsService = class {
10949
11092
  hookName: "organization",
10950
11093
  ...entry
10951
11094
  };
10952
- await writeFile6(join19(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
11095
+ await writeFile6(join20(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
10953
11096
  `, "utf-8");
10954
11097
  }
10955
11098
  async saveEnvironmentHookLog(entry) {
@@ -10959,7 +11102,7 @@ var WarmHookLogsService = class {
10959
11102
  hookName: "environment",
10960
11103
  ...entry
10961
11104
  };
10962
- await writeFile6(join19(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
11105
+ await writeFile6(join20(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
10963
11106
  `, "utf-8");
10964
11107
  }
10965
11108
  async saveRepoHookLog(repoName, entry) {
@@ -10969,7 +11112,7 @@ var WarmHookLogsService = class {
10969
11112
  hookName: repoName,
10970
11113
  ...entry
10971
11114
  };
10972
- await writeFile6(join19(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
11115
+ await writeFile6(join20(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
10973
11116
  `, "utf-8");
10974
11117
  }
10975
11118
  async getAllLogs() {
@@ -10988,7 +11131,7 @@ var WarmHookLogsService = class {
10988
11131
  continue;
10989
11132
  }
10990
11133
  try {
10991
- const raw = await readFile15(join19(LOGS_DIR2, file), "utf-8");
11134
+ const raw = await readFile15(join20(LOGS_DIR2, file), "utf-8");
10992
11135
  const stored = JSON.parse(raw);
10993
11136
  logs.push(withPreview2(stored));
10994
11137
  } catch {
@@ -11013,7 +11156,7 @@ var WarmHookLogsService = class {
11013
11156
  }
11014
11157
  async appendCurrentRunLog(chunk) {
11015
11158
  if (!chunk) return;
11016
- await appendFile5(CURRENT_RUN_LOG, chunk, "utf-8");
11159
+ await appendFile6(CURRENT_RUN_LOG, chunk, "utf-8");
11017
11160
  }
11018
11161
  async getCurrentRunLog() {
11019
11162
  try {
@@ -11026,7 +11169,7 @@ var WarmHookLogsService = class {
11026
11169
  async getFullOutput(hookType, hookName) {
11027
11170
  const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
11028
11171
  try {
11029
- const raw = await readFile15(join19(LOGS_DIR2, filename), "utf-8");
11172
+ const raw = await readFile15(join20(LOGS_DIR2, filename), "utf-8");
11030
11173
  const stored = JSON.parse(raw);
11031
11174
  if (stored.hookType !== hookType || stored.hookName !== hookName) {
11032
11175
  return null;
@@ -11045,7 +11188,7 @@ var warmHookLogsService = new WarmHookLogsService();
11045
11188
  // src/services/warm-hooks-service.ts
11046
11189
  async function readRepoWarmHook(repoPath) {
11047
11190
  for (const filename of REPLICAS_CONFIG_FILENAMES) {
11048
- const configPath = join20(repoPath, filename);
11191
+ const configPath = join21(repoPath, filename);
11049
11192
  if (!existsSync8(configPath)) {
11050
11193
  continue;
11051
11194
  }
@@ -11310,7 +11453,7 @@ var setWorkspaceNameSchema = z2.object({
11310
11453
  name: z2.string().min(1).max(48)
11311
11454
  });
11312
11455
  var createChatSchema = z2.object({
11313
- provider: z2.enum(["claude", "codex", "relay"]),
11456
+ provider: z2.enum(["claude", "codex", "cursor", "relay"]),
11314
11457
  title: z2.string().min(1).optional(),
11315
11458
  parentChatId: z2.string().uuid().optional()
11316
11459
  });
@@ -12000,7 +12143,7 @@ function createV1Routes(deps) {
12000
12143
  const logFiles = files.filter((f) => f.endsWith(".log"));
12001
12144
  const sessions = await Promise.all(
12002
12145
  logFiles.map(async (filename) => {
12003
- const filePath = join21(LOG_DIR, filename);
12146
+ const filePath = join22(LOG_DIR, filename);
12004
12147
  const fileStat = await stat5(filePath);
12005
12148
  const sessionId = filename.replace(/\.log$/, "");
12006
12149
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.328",
3
+ "version": "0.1.329",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -31,6 +31,7 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@anthropic-ai/claude-agent-sdk": "0.3.168",
34
+ "@cursor/sdk": "1.0.19",
34
35
  "@hono/node-server": "^1.19.5",
35
36
  "hono": "^4.10.3",
36
37
  "smol-toml": "^1.6.0",