replicas-engine 0.1.289 → 0.1.291

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 +96 -34
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -286,7 +286,7 @@ var WORKSPACE_SIZES = ["small", "large"];
286
286
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
287
287
 
288
288
  // ../shared/src/e2b.ts
289
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-09-v3";
289
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-09-v5";
290
290
 
291
291
  // ../shared/src/runtime-env.ts
292
292
  function parsePosixEnvFile(content) {
@@ -4747,7 +4747,7 @@ async function registerDesktopPreview() {
4747
4747
 
4748
4748
  // src/services/chat/chat-service.ts
4749
4749
  import { existsSync as existsSync7 } from "fs";
4750
- import { appendFile as appendFile3, copyFile, mkdir as mkdir11, readFile as readFile8, rename as rename2, rm } from "fs/promises";
4750
+ import { appendFile as appendFile4, copyFile, mkdir as mkdir11, readFile as readFile9, rename as rename2, rm } from "fs/promises";
4751
4751
  import { homedir as homedir12 } from "os";
4752
4752
  import { join as join14 } from "path";
4753
4753
  import { randomUUID as randomUUID5 } from "crypto";
@@ -6594,7 +6594,7 @@ var AspClient = class {
6594
6594
  // src/managers/codex-asp/app-server-process.ts
6595
6595
  var DEFAULT_CODEX_BINARY = "codex";
6596
6596
  var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
6597
- var ENGINE_PACKAGE_VERSION = "0.1.289";
6597
+ var ENGINE_PACKAGE_VERSION = "0.1.291";
6598
6598
  var INITIALIZE_METHOD = "initialize";
6599
6599
  var INITIALIZED_NOTIFICATION = "initialized";
6600
6600
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -7396,11 +7396,56 @@ var TranscriptUpdateCoalescer = class {
7396
7396
  }
7397
7397
  };
7398
7398
 
7399
+ // src/managers/codex-asp/codex-history-file.ts
7400
+ import { appendFile as appendFile3, readFile as readFile8 } from "fs/promises";
7401
+ function parseCodexHistoryJsonl(content) {
7402
+ const events = [];
7403
+ let transcript = null;
7404
+ for (const event of parseAgentEventJsonl(content)) {
7405
+ if (event.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE) {
7406
+ events.push(event);
7407
+ continue;
7408
+ }
7409
+ const delta = event.payload.transcriptDelta;
7410
+ if (isCodexAspTranscriptDelta(delta)) {
7411
+ transcript = applyCodexAspTranscriptDelta(transcript, delta);
7412
+ } else if (isCodexAspTranscript(event.payload.transcript)) {
7413
+ transcript = event.payload.transcript;
7414
+ }
7415
+ }
7416
+ return { events, transcript };
7417
+ }
7418
+ var CodexHistoryFile = class {
7419
+ constructor(filePath) {
7420
+ this.filePath = filePath;
7421
+ }
7422
+ filePath;
7423
+ writeChain = Promise.resolve();
7424
+ /** Best-effort ordered append; failures must not disrupt the turn. */
7425
+ append(event) {
7426
+ this.writeChain = this.writeChain.then(() => appendFile3(this.filePath, JSON.stringify(event) + "\n", "utf-8")).catch((error) => {
7427
+ console.error("[CodexHistoryFile] Failed to append event:", error);
7428
+ });
7429
+ }
7430
+ async load() {
7431
+ try {
7432
+ const content = await readFile8(this.filePath, "utf-8");
7433
+ return parseCodexHistoryJsonl(content);
7434
+ } catch (error) {
7435
+ if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) {
7436
+ console.error("[CodexHistoryFile] Failed to load history file:", error);
7437
+ }
7438
+ return { events: [], transcript: null };
7439
+ }
7440
+ }
7441
+ };
7442
+
7399
7443
  // src/managers/codex-asp/codex-asp-manager.ts
7400
7444
  var CodexAspManager = class extends CodingAgentManager {
7401
7445
  currentThreadId = null;
7402
7446
  activeTurnId = null;
7403
7447
  threadAttached = false;
7448
+ historyFile;
7404
7449
  historyEvents = [];
7405
7450
  codexAspTranscript = null;
7406
7451
  lastEmittedTranscripts = /* @__PURE__ */ new Map();
@@ -7412,12 +7457,18 @@ var CodexAspManager = class extends CodingAgentManager {
7412
7457
  });
7413
7458
  constructor(options) {
7414
7459
  super(options);
7460
+ this.historyFile = options.historyFilePath ? new CodexHistoryFile(options.historyFilePath) : null;
7415
7461
  this.initializeManager(this.processMessageInternal.bind(this));
7416
7462
  }
7417
7463
  async initialize() {
7418
- if (this.initialSessionId) {
7419
- this.currentThreadId = this.initialSessionId;
7464
+ const replayed = await this.historyFile?.load();
7465
+ if (replayed) {
7466
+ this.historyEvents.push(...replayed.events);
7467
+ if (replayed.transcript) {
7468
+ this.mergeTranscriptSnapshot(replayed.transcript);
7469
+ }
7420
7470
  }
7471
+ this.currentThreadId = this.initialSessionId ?? replayed?.transcript?.threadId ?? null;
7421
7472
  }
7422
7473
  async interruptActiveTurn() {
7423
7474
  if (!this.currentThreadId || !this.activeTurnId) {
@@ -8131,9 +8182,13 @@ var CodexAspManager = class extends CodingAgentManager {
8131
8182
  type,
8132
8183
  payload
8133
8184
  };
8134
- this.historyEvents.push(event);
8185
+ this.trackHistoryEvent(event);
8135
8186
  return event;
8136
8187
  }
8188
+ trackHistoryEvent(event) {
8189
+ this.historyEvents.push(event);
8190
+ this.historyFile?.append(event);
8191
+ }
8137
8192
  emitTranscriptUpdated(threadId, options = {}) {
8138
8193
  this.transcriptUpdateCoalescer.schedule(threadId, options);
8139
8194
  }
@@ -8226,11 +8281,13 @@ var CodexAspManager = class extends CodingAgentManager {
8226
8281
  this.lastEmittedTranscripts.delete(emittedThreadId);
8227
8282
  }
8228
8283
  }
8229
- this.onEvent({
8284
+ const event = {
8230
8285
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
8231
8286
  type: CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE,
8232
8287
  payload: updatePayload
8233
- });
8288
+ };
8289
+ this.historyFile?.append(event);
8290
+ this.onEvent(event);
8234
8291
  }
8235
8292
  handleRateLimits(rateLimits) {
8236
8293
  const snapshot = extractRateLimitsSnapshot(rateLimits);
@@ -8251,7 +8308,7 @@ var CodexAspManager = class extends CodingAgentManager {
8251
8308
  emitQuotaStatus(snapshot, force = false) {
8252
8309
  const event = this.quotaStatus.apply(snapshot, force);
8253
8310
  if (!event) return;
8254
- this.historyEvents.push(event);
8311
+ this.trackHistoryEvent(event);
8255
8312
  this.onEvent(event);
8256
8313
  }
8257
8314
  emitCodexTokenUsage(tokenUsage, model) {
@@ -8271,7 +8328,7 @@ var CodexAspManager = class extends CodingAgentManager {
8271
8328
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
8272
8329
  });
8273
8330
  const event = this.emitContextUsage(payload);
8274
- this.historyEvents.push(event);
8331
+ this.trackHistoryEvent(event);
8275
8332
  }
8276
8333
  };
8277
8334
 
@@ -8881,6 +8938,12 @@ var ENGINE_DIR2 = join14(homedir12(), ".replicas", "engine");
8881
8938
  var CHATS_FILE = join14(ENGINE_DIR2, "chats.json");
8882
8939
  var CLAUDE_HISTORY_DIR = join14(ENGINE_DIR2, "claude-histories");
8883
8940
  var RELAY_HISTORY_DIR = join14(ENGINE_DIR2, "relay-histories");
8941
+ var CODEX_HISTORY_DIR = join14(ENGINE_DIR2, "codex-histories");
8942
+ var HISTORY_DIR_BY_PROVIDER = {
8943
+ claude: CLAUDE_HISTORY_DIR,
8944
+ relay: RELAY_HISTORY_DIR,
8945
+ codex: CODEX_HISTORY_DIR
8946
+ };
8884
8947
  var CHAT_SENDERS_DIR = join14(ENGINE_DIR2, "chat-senders");
8885
8948
  var CODEX_AUTH_PATH2 = join14(homedir12(), ".codex", "auth.json");
8886
8949
  var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
@@ -8981,6 +9044,7 @@ var ChatService = class {
8981
9044
  await mkdir11(ENGINE_DIR2, { recursive: true });
8982
9045
  await mkdir11(CLAUDE_HISTORY_DIR, { recursive: true });
8983
9046
  await mkdir11(RELAY_HISTORY_DIR, { recursive: true });
9047
+ await mkdir11(CODEX_HISTORY_DIR, { recursive: true });
8984
9048
  await mkdir11(CHAT_SENDERS_DIR, { recursive: true });
8985
9049
  const persisted = await this.loadChats();
8986
9050
  for (const chat of persisted) {
@@ -9083,14 +9147,14 @@ var ChatService = class {
9083
9147
  }
9084
9148
  async appendSender(chatId, sender) {
9085
9149
  try {
9086
- await appendFile3(this.senderFilePath(chatId), JSON.stringify(sender) + "\n", "utf-8");
9150
+ await appendFile4(this.senderFilePath(chatId), JSON.stringify(sender) + "\n", "utf-8");
9087
9151
  } catch (error) {
9088
9152
  console.error("[ChatService] Failed to append sender record:", error);
9089
9153
  }
9090
9154
  }
9091
9155
  async readSenders(chatId) {
9092
9156
  try {
9093
- const content = await readFile8(this.senderFilePath(chatId), "utf-8");
9157
+ const content = await readFile9(this.senderFilePath(chatId), "utf-8");
9094
9158
  const lines = content.split("\n").filter((line) => line.trim().length > 0);
9095
9159
  const senders = [];
9096
9160
  for (const line of lines) {
@@ -9227,10 +9291,7 @@ var ChatService = class {
9227
9291
  return descendants;
9228
9292
  }
9229
9293
  async deleteHistoryFile(persisted) {
9230
- if (persisted.provider === "claude" || persisted.provider === "relay") {
9231
- const dir = persisted.provider === "claude" ? CLAUDE_HISTORY_DIR : RELAY_HISTORY_DIR;
9232
- await rm(join14(dir, `${persisted.id}.jsonl`), { force: true });
9233
- }
9294
+ await rm(join14(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
9234
9295
  await rm(this.senderFilePath(persisted.id), { force: true });
9235
9296
  }
9236
9297
  async getChatHistory(chatId) {
@@ -9306,6 +9367,7 @@ var ChatService = class {
9306
9367
  } else {
9307
9368
  provider = new CodexAspManager({
9308
9369
  workingDirectory: this.workingDirectory,
9370
+ historyFilePath: join14(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
9309
9371
  initialSessionId: persisted.providerSessionId,
9310
9372
  onSaveSessionId: saveSession,
9311
9373
  onTurnComplete: onProviderTurnComplete,
@@ -9446,7 +9508,7 @@ var ChatService = class {
9446
9508
  }
9447
9509
  async loadChats() {
9448
9510
  try {
9449
- const content = await readFile8(CHATS_FILE, "utf-8");
9511
+ const content = await readFile9(CHATS_FILE, "utf-8");
9450
9512
  return parsePersistedChatsContent(content);
9451
9513
  } catch (error) {
9452
9514
  if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
@@ -9461,7 +9523,7 @@ var ChatService = class {
9461
9523
  console.error("[ChatService] Failed to quarantine corrupt chats file:", renameError);
9462
9524
  }
9463
9525
  try {
9464
- const backupContent = await readFile8(CHATS_BACKUP_FILE, "utf-8");
9526
+ const backupContent = await readFile9(CHATS_BACKUP_FILE, "utf-8");
9465
9527
  return parsePersistedChatsContent(backupContent);
9466
9528
  } catch (backupError) {
9467
9529
  if (backupError && typeof backupError === "object" && "code" in backupError && backupError.code === "ENOENT") {
@@ -9546,7 +9608,7 @@ var ChatService = class {
9546
9608
 
9547
9609
  // src/services/repo-file-service.ts
9548
9610
  import { execFile as execFile2 } from "child_process";
9549
- import { readFile as readFile9, realpath, stat as stat2 } from "fs/promises";
9611
+ import { readFile as readFile10, realpath, stat as stat2 } from "fs/promises";
9550
9612
  import { join as join15, resolve, extname } from "path";
9551
9613
  var CACHE_TTL_MS = 3e4;
9552
9614
  var SEARCH_TIMEOUT_MS = 15e3;
@@ -9736,7 +9798,7 @@ var RepoFileService = class {
9736
9798
  tooLarge: true
9737
9799
  };
9738
9800
  }
9739
- const content = await readFile9(fullPath, "utf-8");
9801
+ const content = await readFile10(fullPath, "utf-8");
9740
9802
  return {
9741
9803
  repoName,
9742
9804
  path: filePath,
@@ -9814,11 +9876,11 @@ var RepoFileService = class {
9814
9876
  // src/v1-routes.ts
9815
9877
  import { Hono } from "hono";
9816
9878
  import { z as z2 } from "zod";
9817
- import { readdir as readdir6, stat as stat4, readFile as readFile14 } from "fs/promises";
9879
+ import { readdir as readdir6, stat as stat4, readFile as readFile15 } from "fs/promises";
9818
9880
  import { join as join20, resolve as resolve2 } from "path";
9819
9881
 
9820
9882
  // src/services/upload-chat-transcripts.ts
9821
- import { readdir as readdir3, readFile as readFile10 } from "fs/promises";
9883
+ import { readdir as readdir3, readFile as readFile11 } from "fs/promises";
9822
9884
  import { basename, join as join16 } from "path";
9823
9885
  import { homedir as homedir13 } from "os";
9824
9886
  var ENGINE_DIR3 = join16(homedir13(), ".replicas", "engine");
@@ -9854,7 +9916,7 @@ async function flushAllChatTranscripts() {
9854
9916
  return { flushed, failed };
9855
9917
  }
9856
9918
  async function uploadOne(chatId, filePath) {
9857
- const bytes = await readFile10(filePath);
9919
+ const bytes = await readFile11(filePath);
9858
9920
  if (bytes.byteLength === 0) return;
9859
9921
  const form = new FormData();
9860
9922
  form.append("chat_id", chatId);
@@ -9871,7 +9933,7 @@ async function uploadOne(chatId, filePath) {
9871
9933
  }
9872
9934
 
9873
9935
  // src/services/canvas-service.ts
9874
- import { readdir as readdir4, readFile as readFile11, stat as stat3 } from "fs/promises";
9936
+ import { readdir as readdir4, readFile as readFile12, stat as stat3 } from "fs/promises";
9875
9937
  import { homedir as homedir14 } from "os";
9876
9938
  import { basename as basename2, join as join17 } from "path";
9877
9939
  var CANVAS_DIRECTORIES = [
@@ -9936,10 +9998,10 @@ var CanvasService = class {
9936
9998
  }
9937
9999
  try {
9938
10000
  if (isTextKind(kind)) {
9939
- const content = await readFile11(filePath, "utf-8");
10001
+ const content = await readFile12(filePath, "utf-8");
9940
10002
  return { filename: safe, kind, sizeBytes, mimeType, content };
9941
10003
  }
9942
- const buf = await readFile11(filePath);
10004
+ const buf = await readFile12(filePath);
9943
10005
  return { filename: safe, kind, sizeBytes, mimeType, base64: buf.toString("base64") };
9944
10006
  } catch {
9945
10007
  continue;
@@ -9952,12 +10014,12 @@ var canvasService = new CanvasService();
9952
10014
 
9953
10015
  // src/services/warm-hooks-service.ts
9954
10016
  import { spawn as spawn4 } from "child_process";
9955
- import { readFile as readFile13 } from "fs/promises";
10017
+ import { readFile as readFile14 } from "fs/promises";
9956
10018
  import { existsSync as existsSync8 } from "fs";
9957
10019
  import { join as join19 } from "path";
9958
10020
 
9959
10021
  // src/services/warm-hook-logs-service.ts
9960
- import { mkdir as mkdir12, readFile as readFile12, writeFile as writeFile6, readdir as readdir5, appendFile as appendFile4, unlink as unlink3 } from "fs/promises";
10022
+ import { mkdir as mkdir12, readFile as readFile13, writeFile as writeFile6, readdir as readdir5, appendFile as appendFile5, unlink as unlink3 } from "fs/promises";
9961
10023
  import { homedir as homedir15 } from "os";
9962
10024
  import { join as join18 } from "path";
9963
10025
  var LOGS_DIR2 = join18(homedir15(), ".replicas", "warm-hook-logs");
@@ -10017,7 +10079,7 @@ var WarmHookLogsService = class {
10017
10079
  continue;
10018
10080
  }
10019
10081
  try {
10020
- const raw = await readFile12(join18(LOGS_DIR2, file), "utf-8");
10082
+ const raw = await readFile13(join18(LOGS_DIR2, file), "utf-8");
10021
10083
  const stored = JSON.parse(raw);
10022
10084
  logs.push(withPreview2(stored));
10023
10085
  } catch {
@@ -10042,11 +10104,11 @@ var WarmHookLogsService = class {
10042
10104
  }
10043
10105
  async appendCurrentRunLog(chunk) {
10044
10106
  if (!chunk) return;
10045
- await appendFile4(CURRENT_RUN_LOG, chunk, "utf-8");
10107
+ await appendFile5(CURRENT_RUN_LOG, chunk, "utf-8");
10046
10108
  }
10047
10109
  async getCurrentRunLog() {
10048
10110
  try {
10049
- return await readFile12(CURRENT_RUN_LOG, "utf-8");
10111
+ return await readFile13(CURRENT_RUN_LOG, "utf-8");
10050
10112
  } catch (err) {
10051
10113
  if (err.code === "ENOENT") return null;
10052
10114
  throw err;
@@ -10055,7 +10117,7 @@ var WarmHookLogsService = class {
10055
10117
  async getFullOutput(hookType, hookName) {
10056
10118
  const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
10057
10119
  try {
10058
- const raw = await readFile12(join18(LOGS_DIR2, filename), "utf-8");
10120
+ const raw = await readFile13(join18(LOGS_DIR2, filename), "utf-8");
10059
10121
  const stored = JSON.parse(raw);
10060
10122
  if (stored.hookType !== hookType || stored.hookName !== hookName) {
10061
10123
  return null;
@@ -10079,7 +10141,7 @@ async function readRepoWarmHook(repoPath) {
10079
10141
  continue;
10080
10142
  }
10081
10143
  try {
10082
- const raw = await readFile13(configPath, "utf-8");
10144
+ const raw = await readFile14(configPath, "utf-8");
10083
10145
  const config = parseReplicasConfigString(raw, filename);
10084
10146
  if (!config.warmHook) {
10085
10147
  return null;
@@ -11042,7 +11104,7 @@ function createV1Routes(deps) {
11042
11104
  const limit = Math.min(parseInt(c.req.query("limit") || "500", 10), 5e3);
11043
11105
  let content;
11044
11106
  try {
11045
- content = await readFile14(filePath, "utf-8");
11107
+ content = await readFile15(filePath, "utf-8");
11046
11108
  } catch {
11047
11109
  return c.json(jsonError("Log session not found"), 404);
11048
11110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.289",
3
+ "version": "0.1.291",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",