replicas-engine 0.1.518 → 0.1.520

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 +103 -64
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -609,7 +609,7 @@ var WORKSPACE_SIZES = ["small", "large"];
609
609
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
610
610
 
611
611
  // ../shared/src/e2b.ts
612
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-28-v7";
612
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-29-v2";
613
613
 
614
614
  // ../shared/src/runtime-env.ts
615
615
  function shellQuotePosix(value) {
@@ -10069,7 +10069,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
10069
10069
  var MIN_CODEX_CLI_VERSION = "0.144.6";
10070
10070
  var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
10071
10071
  var codexCliVersionEnsured = null;
10072
- var ENGINE_PACKAGE_VERSION = "0.1.518";
10072
+ var ENGINE_PACKAGE_VERSION = "0.1.520";
10073
10073
  var INITIALIZE_METHOD = "initialize";
10074
10074
  var INITIALIZED_NOTIFICATION = "initialized";
10075
10075
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -12451,6 +12451,7 @@ var CursorManager = class extends CodingAgentManager {
12451
12451
  const message = await this.toCursorMessage(request, includeInstructions);
12452
12452
  const agent = await this.ensureAgent(request);
12453
12453
  const model = request.model ?? DEFAULT_CURSOR_MODEL;
12454
+ this.activeModel = model;
12454
12455
  this.recordHistoryEvent("event_msg", {
12455
12456
  type: "user_message",
12456
12457
  message: request.message
@@ -12459,11 +12460,11 @@ var CursorManager = class extends CodingAgentManager {
12459
12460
  model: { id: model },
12460
12461
  mode: request.planMode ? "plan" : "agent",
12461
12462
  onDelta: async (args) => {
12463
+ this.recordCursorContextUsage(args.update);
12462
12464
  await this.handleCursorToolCall(cursorToolInputFromDelta(args.update));
12463
12465
  }
12464
12466
  });
12465
12467
  this.activeRun = run;
12466
- this.activeModel = model;
12467
12468
  if (this.pendingCursorBlockReason) {
12468
12469
  await run.cancel();
12469
12470
  throw new Error(this.pendingCursorBlockReason);
@@ -12487,7 +12488,7 @@ var CursorManager = class extends CodingAgentManager {
12487
12488
  }
12488
12489
  if (next.done) break;
12489
12490
  const event = next.value;
12490
- this.recordCursorEvent(event);
12491
+ this.recordHistoryEvent(`cursor-${event.type}`, event, this.historyFile);
12491
12492
  if (event.type === "tool_call" && event.status === "running") {
12492
12493
  await this.handleCursorToolCall(cursorToolInputFromMessage(event));
12493
12494
  }
@@ -12508,9 +12509,11 @@ var CursorManager = class extends CodingAgentManager {
12508
12509
  await this.onSaveSessionId(agent.agentId);
12509
12510
  }
12510
12511
  if (result.status === "error") {
12512
+ const detail = await this.readRunErrorDetail(agent.agentId, result.id);
12513
+ console.error("[CursorManager] Cursor run failed:", { runId: result.id, model, detail });
12511
12514
  this.recordHistoryEvent("cursor-error", {
12512
12515
  type: "error",
12513
- message: result.result || "Cursor run failed",
12516
+ message: detail || result.result || "Cursor run failed",
12514
12517
  runId: result.id
12515
12518
  }, this.historyFile);
12516
12519
  } else {
@@ -12532,6 +12535,21 @@ var CursorManager = class extends CodingAgentManager {
12532
12535
  await this.onTurnComplete();
12533
12536
  }
12534
12537
  }
12538
+ async readRunErrorDetail(agentId, runId) {
12539
+ try {
12540
+ const { SqliteLocalAgentStore } = await import("@cursor/sdk/sqlite");
12541
+ const store = await SqliteLocalAgentStore.open({ workspaceRef: this.workingDirectory });
12542
+ try {
12543
+ const record = await store.runs.get({ agentId, runId });
12544
+ return record?.error?.trim() || null;
12545
+ } finally {
12546
+ await store.dispose();
12547
+ }
12548
+ } catch (error) {
12549
+ console.error("[CursorManager] Failed to read Cursor run error detail:", error);
12550
+ return null;
12551
+ }
12552
+ }
12535
12553
  async handleCursorToolCall(toolCall) {
12536
12554
  if (!toolCall) return;
12537
12555
  if (this.blockedToolCallIds.has(toolCall.toolUseId)) return;
@@ -12584,24 +12602,16 @@ ${request.message}` : request.message;
12584
12602
  }))
12585
12603
  };
12586
12604
  }
12587
- recordCursorEvent(event) {
12588
- this.recordHistoryEvent(`cursor-${event.type}`, event, this.historyFile);
12589
- const usage = this.buildCursorContextUsagePayload(event);
12590
- if (!usage) return;
12591
- this.historyFile.append(this.emitContextUsage(usage));
12592
- }
12593
- buildCursorContextUsagePayload(event) {
12594
- if (!event || typeof event !== "object" || !("type" in event) || event.type !== "turn-ended") {
12595
- return null;
12596
- }
12597
- const usage = "usage" in event && event.usage && typeof event.usage === "object" ? event.usage : null;
12598
- if (!usage) return null;
12599
- const inputTokens = finiteNumber("inputTokens" in usage ? usage.inputTokens : null);
12600
- const cacheReadTokens = finiteNumber("cacheReadTokens" in usage ? usage.cacheReadTokens : null);
12601
- const cacheWriteTokens = finiteNumber("cacheWriteTokens" in usage ? usage.cacheWriteTokens : null);
12602
- const outputTokens = finiteNumber("outputTokens" in usage ? usage.outputTokens : null);
12605
+ // `turn-ended` is only ever an `onDelta` interaction update — it is not part of
12606
+ // the `SDKMessage` union the run stream yields, so usage has to be read here.
12607
+ recordCursorContextUsage(update) {
12608
+ if (update.type !== "turn-ended" || !update.usage) return;
12609
+ const inputTokens = finiteNumber(update.usage.inputTokens);
12610
+ const cacheReadTokens = finiteNumber(update.usage.cacheReadTokens);
12611
+ const cacheWriteTokens = finiteNumber(update.usage.cacheWriteTokens);
12612
+ const outputTokens = finiteNumber(update.usage.outputTokens);
12603
12613
  const rawTotalTokens = inputTokens + cacheReadTokens + cacheWriteTokens + outputTokens;
12604
- if (rawTotalTokens <= 0) return null;
12614
+ if (rawTotalTokens <= 0) return;
12605
12615
  const maxTokens = CURSOR_COMPOSER_CONTEXT_WINDOW;
12606
12616
  const { totalTokens, totalProcessedTokens } = clampTokensToWindow(rawTotalTokens, maxTokens);
12607
12617
  const categories = [
@@ -12630,7 +12640,7 @@ ${request.message}` : request.message;
12630
12640
  color: CURSOR_CATEGORY_COLORS.output
12631
12641
  }
12632
12642
  ].filter((category) => category.tokens > 0);
12633
- return {
12643
+ const payload = {
12634
12644
  provider: "cursor",
12635
12645
  source: "provider_usage",
12636
12646
  model: this.activeModel,
@@ -12649,6 +12659,7 @@ ${request.message}` : request.message;
12649
12659
  },
12650
12660
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
12651
12661
  };
12662
+ this.historyFile.append(this.emitContextUsage(payload));
12652
12663
  }
12653
12664
  };
12654
12665
 
@@ -14396,7 +14407,10 @@ async function reconcileCanvasItems(filenames) {
14396
14407
  }
14397
14408
 
14398
14409
  // src/services/upload-chat-transcripts.ts
14399
- import { readdir as readdir7, readFile as readFile13 } from "fs/promises";
14410
+ import { createReadStream } from "fs";
14411
+ import { readdir as readdir7, readFile as readFile13, stat as stat4 } from "fs/promises";
14412
+ import { request as httpRequest } from "http";
14413
+ import { request as httpsRequest } from "https";
14400
14414
  import { basename as basename2, join as join23 } from "path";
14401
14415
 
14402
14416
  // src/services/chat/chat-senders.ts
@@ -14423,6 +14437,34 @@ var HISTORY_DIRS = [
14423
14437
  join23(ENGINE_DIR2, "relay-histories"),
14424
14438
  join23(ENGINE_DIR2, "codex-histories")
14425
14439
  ];
14440
+ async function putTranscript(uploadUrl, filePath, size) {
14441
+ await new Promise((resolve4, reject) => {
14442
+ const url = new URL(uploadUrl);
14443
+ const request = (url.protocol === "https:" ? httpsRequest : httpRequest)(url, {
14444
+ method: "PUT",
14445
+ headers: {
14446
+ "content-length": String(size),
14447
+ "content-type": "application/x-ndjson"
14448
+ }
14449
+ }, (response) => {
14450
+ response.setEncoding("utf8");
14451
+ let body = "";
14452
+ response.on("data", (chunk) => {
14453
+ body += chunk;
14454
+ });
14455
+ response.on("end", () => {
14456
+ const status = response.statusCode ?? 0;
14457
+ if (status >= 200 && status < 300) resolve4();
14458
+ else reject(new Error(`upload failed: ${status} ${body}`));
14459
+ });
14460
+ response.on("error", reject);
14461
+ });
14462
+ request.on("error", reject);
14463
+ const file = createReadStream(filePath, { start: 0, end: size - 1 });
14464
+ file.on("error", (error) => request.destroy(error));
14465
+ file.pipe(request);
14466
+ });
14467
+ }
14426
14468
  async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
14427
14469
  let flushed = 0;
14428
14470
  let failed = 0;
@@ -14451,44 +14493,41 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
14451
14493
  return { flushed, failed };
14452
14494
  }
14453
14495
  async function uploadChatTranscript(chatId, filePath, chat) {
14454
- const bytes = await readFile13(filePath);
14455
- if (bytes.byteLength === 0) return;
14456
- let senders;
14496
+ const { size } = await stat4(filePath);
14497
+ if (size === 0) return;
14498
+ const metadata = chat ? {
14499
+ provider: chat.provider,
14500
+ title: chat.title,
14501
+ createdAt: chat.createdAt,
14502
+ updatedAt: chat.updatedAt,
14503
+ parentChatId: chat.parentChatId,
14504
+ deletedAt: chat.deletedAt ?? null
14505
+ } : {};
14457
14506
  try {
14458
- senders = parseChatMessageSendersJsonl(await readFile13(chatMessageSendersFilePath(chatId), "utf-8"));
14507
+ metadata.senders = parseChatMessageSendersJsonl(
14508
+ await readFile13(chatMessageSendersFilePath(chatId), "utf-8")
14509
+ );
14459
14510
  } catch (error) {
14460
14511
  if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) throw error;
14461
14512
  }
14462
- const form = new FormData();
14463
- form.append("chat_id", chatId);
14464
- if (chat) {
14465
- const metadata = {
14466
- provider: chat.provider,
14467
- title: chat.title,
14468
- createdAt: chat.createdAt,
14469
- updatedAt: chat.updatedAt,
14470
- parentChatId: chat.parentChatId,
14471
- deletedAt: chat.deletedAt ?? null
14472
- };
14473
- form.append("provider", metadata.provider);
14474
- form.append("title", metadata.title);
14475
- form.append("created_at", metadata.createdAt);
14476
- form.append("updated_at", metadata.updatedAt);
14477
- if (metadata.parentChatId) form.append("parent_chat_id", metadata.parentChatId);
14478
- form.append("deleted_at", metadata.deletedAt ?? "");
14513
+ const uploadRequest = { chatId, size, metadata };
14514
+ const prepareResponse = await monolithRequest("/v1/engine/chat-transcripts/upload-url", {
14515
+ body: uploadRequest
14516
+ });
14517
+ if (!prepareResponse.ok) {
14518
+ throw new Error(`prepare failed: ${prepareResponse.status} ${await prepareResponse.text()}`);
14479
14519
  }
14480
- if (senders !== void 0) {
14481
- form.append("senders", JSON.stringify(senders));
14520
+ const prepareBody = await prepareResponse.json();
14521
+ if (!isRecord(prepareBody) || typeof prepareBody.uploadUrl !== "string" && prepareBody.uploadUrl !== null) {
14522
+ throw new Error("prepare failed: invalid response");
14482
14523
  }
14483
- form.append(
14484
- "file",
14485
- new Blob([new Uint8Array(bytes)], { type: "application/x-ndjson" }),
14486
- "transcript.jsonl"
14487
- );
14488
- const response = await monolithRequest("/v1/engine/chat-transcripts", { body: form });
14489
- if (!response.ok) {
14490
- const errorText = await response.text();
14491
- throw new Error(`upload failed: ${response.status} ${errorText}`);
14524
+ if (prepareBody.uploadUrl === null) return;
14525
+ await putTranscript(prepareBody.uploadUrl, filePath, size);
14526
+ const finalizeResponse = await monolithRequest("/v1/engine/chat-transcripts/finalize", {
14527
+ body: uploadRequest
14528
+ });
14529
+ if (!finalizeResponse.ok) {
14530
+ throw new Error(`finalize failed: ${finalizeResponse.status} ${await finalizeResponse.text()}`);
14492
14531
  }
14493
14532
  }
14494
14533
 
@@ -14526,8 +14565,8 @@ async function flushRepoState() {
14526
14565
  }
14527
14566
 
14528
14567
  // src/services/upload-engine-logs.ts
14529
- import { createReadStream } from "fs";
14530
- import { readdir as readdir8, stat as stat4 } from "fs/promises";
14568
+ import { createReadStream as createReadStream2 } from "fs";
14569
+ import { readdir as readdir8, stat as stat5 } from "fs/promises";
14531
14570
  import { join as join24 } from "path";
14532
14571
  var MAX_ENGINE_LOG_FLUSH_SESSIONS = 10;
14533
14572
  var MAX_ENGINE_LOG_FLUSH_BYTES = 5 * 1024 * 1024;
@@ -14558,7 +14597,7 @@ async function flushAllEngineLogs() {
14558
14597
  try {
14559
14598
  const sessionId = filename.slice(0, -".log".length);
14560
14599
  const filePath = join24(LOG_DIR, filename);
14561
- const fileStat = await runBeforeDeadline(() => stat4(filePath), deadline);
14600
+ const fileStat = await runBeforeDeadline(() => stat5(filePath), deadline);
14562
14601
  if (!fileStat.isFile()) {
14563
14602
  skipped++;
14564
14603
  return null;
@@ -14590,7 +14629,7 @@ async function flushAllEngineLogs() {
14590
14629
  const content = await runBeforeDeadline(async (signal) => {
14591
14630
  if (candidate.length === 0) return Buffer.alloc(0);
14592
14631
  const chunks = [];
14593
- for await (const chunk of createReadStream(candidate.filePath, {
14632
+ for await (const chunk of createReadStream2(candidate.filePath, {
14594
14633
  start: candidate.offset,
14595
14634
  end: candidate.offset + candidate.length - 1,
14596
14635
  signal
@@ -15531,7 +15570,7 @@ var ChatService = class {
15531
15570
 
15532
15571
  // src/services/repo-file-service.ts
15533
15572
  import { execFile as execFile2 } from "child_process";
15534
- import { readFile as readFile15, realpath, stat as stat5 } from "fs/promises";
15573
+ import { readFile as readFile15, realpath, stat as stat6 } from "fs/promises";
15535
15574
  import { join as join26, resolve as resolve2, extname as extname2 } from "path";
15536
15575
  var CACHE_TTL_MS = 3e4;
15537
15576
  var SEARCH_TIMEOUT_MS = 15e3;
@@ -15696,7 +15735,7 @@ var RepoFileService = class {
15696
15735
  const repoRoot = await realpath(repo.path);
15697
15736
  const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
15698
15737
  if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
15699
- const fileStat = await stat5(fullPath);
15738
+ const fileStat = await stat6(fullPath);
15700
15739
  if (!fileStat.isFile()) return null;
15701
15740
  const sizeBytes = fileStat.size;
15702
15741
  if (isBinaryExtension(filePath)) {
@@ -15799,7 +15838,7 @@ var RepoFileService = class {
15799
15838
  // src/v1-routes.ts
15800
15839
  import { Hono } from "hono";
15801
15840
  import { z as z7 } from "zod";
15802
- import { readdir as readdir10, stat as stat6, readFile as readFile18 } from "fs/promises";
15841
+ import { readdir as readdir10, stat as stat7, readFile as readFile18 } from "fs/promises";
15803
15842
  import { join as join29, resolve as resolve3 } from "path";
15804
15843
 
15805
15844
  // src/services/warm-hooks-service.ts
@@ -17189,7 +17228,7 @@ data: ${JSON.stringify("Terminal session not found")}
17189
17228
  const sessions = await Promise.all(
17190
17229
  logFiles.map(async (filename) => {
17191
17230
  const filePath = join29(LOG_DIR, filename);
17192
- const fileStat = await stat6(filePath);
17231
+ const fileStat = await stat7(filePath);
17193
17232
  const sessionId = filename.replace(/\.log$/, "");
17194
17233
  return {
17195
17234
  sessionId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.518",
3
+ "version": "0.1.520",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",