replicas-engine 0.1.443 → 0.1.445

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 +135 -92
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -168,6 +168,9 @@ var DEFAULT_CHAT_TITLES = {
168
168
  opencode: "Opencode",
169
169
  relay: "Relay"
170
170
  };
171
+ function isDefaultChat(chat) {
172
+ return chat.title === DEFAULT_CHAT_TITLES[chat.provider];
173
+ }
171
174
  var CLAUDE_OPUS_1M_MODEL = "opus[1m]";
172
175
  var LEGACY_CLAUDE_OPUS_1M_MODEL = "opus-1m";
173
176
  var CLAUDE_FABLE_5_MODEL = "claude-fable-5";
@@ -521,7 +524,7 @@ var WORKSPACE_SIZES = ["small", "large"];
521
524
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
522
525
 
523
526
  // ../shared/src/e2b.ts
524
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-16-v3";
527
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-16-v5";
525
528
 
526
529
  // ../shared/src/runtime-env.ts
527
530
  function shellQuotePosix(value) {
@@ -2726,6 +2729,11 @@ function isVersionBelow(version, minimum) {
2726
2729
  return compareVersions(version, minimum) < 0;
2727
2730
  }
2728
2731
 
2732
+ // ../shared/src/engine/chat-tabs.ts
2733
+ function hasChatStarted(chat) {
2734
+ return chat.processing || Boolean(chat.awaitingInput) || Boolean(chat.goal) || Boolean(chat.lastMessageText) || chat.updatedAt > chat.createdAt;
2735
+ }
2736
+
2729
2737
  // ../shared/src/engine/environment.ts
2730
2738
  var DESKTOP_NOVNC_PORT = 6080;
2731
2739
 
@@ -8592,7 +8600,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
8592
8600
  var MIN_CODEX_CLI_VERSION = "0.144.0";
8593
8601
  var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
8594
8602
  var codexCliVersionEnsured = null;
8595
- var ENGINE_PACKAGE_VERSION = "0.1.443";
8603
+ var ENGINE_PACKAGE_VERSION = "0.1.445";
8596
8604
  var INITIALIZE_METHOD = "initialize";
8597
8605
  var INITIALIZED_NOTIFICATION = "initialized";
8598
8606
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -8817,9 +8825,10 @@ async function restartCodexAspHost() {
8817
8825
 
8818
8826
  // src/utils/codex-quota.ts
8819
8827
  function buildCodexRateLimitsSnapshot(fields) {
8828
+ if (fields.authMethod !== "oauth") return null;
8820
8829
  if (fields.unlimited === true) return null;
8821
8830
  let state = "ok";
8822
- if (fields.hasCredits === false) {
8831
+ if (fields.rateLimitResetType?.endsWith("_credits_depleted")) {
8823
8832
  state = "out_of_credits";
8824
8833
  } else if (fields.rateLimitResetType !== null) {
8825
8834
  state = "rate_limited";
@@ -8901,8 +8910,8 @@ function toReasoningEffort(thinkingLevel) {
8901
8910
  function extractRateLimitsSnapshot(rateLimits) {
8902
8911
  const credits = rateLimits.credits;
8903
8912
  return buildCodexRateLimitsSnapshot({
8913
+ authMethod: ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD ?? "none",
8904
8914
  unlimited: credits?.unlimited ?? null,
8905
- hasCredits: credits?.hasCredits ?? null,
8906
8915
  balance: credits?.balance ?? null,
8907
8916
  rateLimitResetType: rateLimits.rateLimitReachedType || null,
8908
8917
  planType: rateLimits.planType
@@ -9490,18 +9499,6 @@ var CodexThreadNotFoundError = class extends Error {
9490
9499
  this.name = "CodexThreadNotFoundError";
9491
9500
  }
9492
9501
  };
9493
- var DefaultChatDeletionError = class extends Error {
9494
- constructor() {
9495
- super("Default chats cannot be deleted");
9496
- this.name = "DefaultChatDeletionError";
9497
- }
9498
- };
9499
- var ChatProcessingDeletionError = class extends Error {
9500
- constructor() {
9501
- super("Cannot delete a chat while it is processing");
9502
- this.name = "ChatProcessingDeletionError";
9503
- }
9504
- };
9505
9502
  var DuplicateDefaultChatError = class extends Error {
9506
9503
  constructor(provider) {
9507
9504
  super(`Default chat already exists for provider: ${provider}`);
@@ -12643,13 +12640,15 @@ async function uploadChatTranscript(chatId, filePath, chat) {
12643
12640
  title: chat.title,
12644
12641
  createdAt: chat.createdAt,
12645
12642
  updatedAt: chat.updatedAt,
12646
- parentChatId: chat.parentChatId
12643
+ parentChatId: chat.parentChatId,
12644
+ deletedAt: chat.deletedAt ?? null
12647
12645
  };
12648
12646
  form.append("provider", metadata.provider);
12649
12647
  form.append("title", metadata.title);
12650
12648
  form.append("created_at", metadata.createdAt);
12651
12649
  form.append("updated_at", metadata.updatedAt);
12652
12650
  if (metadata.parentChatId) form.append("parent_chat_id", metadata.parentChatId);
12651
+ form.append("deleted_at", metadata.deletedAt ?? "");
12653
12652
  }
12654
12653
  form.append(
12655
12654
  "file",
@@ -12759,7 +12758,7 @@ function isPersistedChat(value) {
12759
12758
  return false;
12760
12759
  }
12761
12760
  const candidate = value;
12762
- return typeof candidate.id === "string" && (candidate.provider === "claude" || candidate.provider === "codex" || candidate.provider === "cursor" || candidate.provider === "opencode" || 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");
12761
+ return typeof candidate.id === "string" && (candidate.provider === "claude" || candidate.provider === "codex" || candidate.provider === "cursor" || candidate.provider === "opencode" || 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") && (candidate.deletedAt === void 0 || candidate.deletedAt === null || typeof candidate.deletedAt === "string");
12763
12762
  }
12764
12763
  function normalizePersistedChat(chat) {
12765
12764
  const isLegacyCodexSdkChat = chat.provider === "codex" && (chat.codexBackend === "sdk" || chat.codexBackend === void 0 && chat.providerSessionId !== null);
@@ -12771,7 +12770,8 @@ function normalizePersistedChat(chat) {
12771
12770
  updatedAt: chat.updatedAt,
12772
12771
  providerSessionId: isLegacyCodexSdkChat ? null : chat.providerSessionId,
12773
12772
  parentChatId: chat.parentChatId ?? null,
12774
- lastMessageText: chat.lastMessageText ?? null
12773
+ lastMessageText: chat.lastMessageText ?? null,
12774
+ deletedAt: chat.deletedAt ?? null
12775
12775
  };
12776
12776
  }
12777
12777
  function parsePersistedChatsContent(content) {
@@ -12801,7 +12801,9 @@ function createUserMessageEvent(message, messageId, images) {
12801
12801
  var ChatService = class {
12802
12802
  constructor(workingDirectory) {
12803
12803
  this.workingDirectory = workingDirectory;
12804
- keepAliveService.setActivityCheck(() => [...this.chats.values()].some(isChatActive));
12804
+ keepAliveService.setActivityCheck(
12805
+ () => [...this.chats.values()].some((chat) => !chat.persisted.deletedAt && isChatActive(chat))
12806
+ );
12805
12807
  }
12806
12808
  workingDirectory;
12807
12809
  chats = /* @__PURE__ */ new Map();
@@ -12820,46 +12822,27 @@ var ChatService = class {
12820
12822
  const runtime = this.createRuntimeChat(chat);
12821
12823
  this.chats.set(chat.id, runtime);
12822
12824
  }
12823
- const hasClaudeDefault = [...this.chats.values()].some(
12824
- (c) => c.persisted.provider === "claude" && c.persisted.title === "Claude Code"
12825
- );
12826
- const hasCodexDefault = [...this.chats.values()].some(
12827
- (c) => c.persisted.provider === "codex" && c.persisted.title === "Codex"
12828
- );
12829
- const hasCursorDefault = [...this.chats.values()].some(
12830
- (c) => c.persisted.provider === "cursor" && c.persisted.title === "Cursor"
12831
- );
12832
- const hasOpencodeDefault = [...this.chats.values()].some(
12833
- (c) => c.persisted.provider === "opencode" && c.persisted.title === "Opencode"
12834
- );
12835
- if (!hasClaudeDefault) {
12836
- await this.createChat({ provider: "claude", title: "Claude Code" });
12837
- }
12838
- if (!hasCodexDefault) {
12839
- await this.createChat({ provider: "codex", title: "Codex" });
12840
- }
12841
- if (!hasCursorDefault) {
12842
- await this.createChat({ provider: "cursor", title: "Cursor" });
12843
- }
12844
- if (!hasOpencodeDefault) {
12845
- await this.createChat({ provider: "opencode", title: "Opencode" });
12846
- }
12847
- const hasRelayDefault = [...this.chats.values()].some(
12848
- (c) => c.persisted.provider === "relay" && c.persisted.title === "Relay"
12849
- );
12850
- if (!hasRelayDefault) {
12851
- await this.createChat({ provider: "relay", title: "Relay" });
12825
+ for (const provider of VALID_AGENT_PROVIDERS) {
12826
+ const hasDefault = [...this.chats.values()].some(
12827
+ (c) => c.persisted.provider === provider && isDefaultChat(c.persisted)
12828
+ );
12829
+ if (!hasDefault) {
12830
+ await this.createChat({ provider, title: DEFAULT_CHAT_TITLES[provider] });
12831
+ }
12852
12832
  }
12853
12833
  }
12854
12834
  listChats(includeChildren = false) {
12855
- return Array.from(this.chats.values()).filter((chat) => includeChildren || chat.persisted.parentChatId === null).map((chat) => this.toSummary(chat)).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
12835
+ return Array.from(this.chats.values()).filter((chat) => !chat.persisted.deletedAt && (includeChildren || chat.persisted.parentChatId === null)).map((chat) => this.toSummary(chat)).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
12836
+ }
12837
+ listDeletedChats() {
12838
+ return Array.from(this.chats.values()).filter((chat) => chat.persisted.deletedAt && chat.persisted.parentChatId === null).map((chat) => this.toSummary(chat)).sort((a, b) => (b.deletedAt ?? "").localeCompare(a.deletedAt ?? ""));
12856
12839
  }
12857
12840
  listChildChats(parentChatId) {
12858
- return Array.from(this.chats.values()).filter((chat) => chat.persisted.parentChatId === parentChatId).map((chat) => this.toSummary(chat)).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
12841
+ return Array.from(this.chats.values()).filter((chat) => !chat.persisted.deletedAt && chat.persisted.parentChatId === parentChatId).map((chat) => this.toSummary(chat)).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
12859
12842
  }
12860
12843
  getChat(chatId) {
12861
12844
  const chat = this.chats.get(chatId);
12862
- return chat ? this.toSummary(chat) : null;
12845
+ return chat && !chat.persisted.deletedAt ? this.toSummary(chat) : null;
12863
12846
  }
12864
12847
  async listSlashCommands(chatId) {
12865
12848
  const chat = this.requireChat(chatId);
@@ -12879,7 +12862,7 @@ var ChatService = class {
12879
12862
  async createChat(request) {
12880
12863
  const now = (/* @__PURE__ */ new Date()).toISOString();
12881
12864
  const title = request.title?.trim() || `${request.provider} chat`;
12882
- if (title === DEFAULT_CHAT_TITLES[request.provider] && Array.from(this.chats.values()).some((chat) => chat.persisted.provider === request.provider && chat.persisted.title === DEFAULT_CHAT_TITLES[request.provider])) {
12865
+ if (isDefaultChat({ provider: request.provider, title }) && Array.from(this.chats.values()).some((chat) => !chat.persisted.deletedAt && chat.persisted.provider === request.provider && isDefaultChat(chat.persisted))) {
12883
12866
  throw new DuplicateDefaultChatError(request.provider);
12884
12867
  }
12885
12868
  const parentChatId = request.parentChatId ?? null;
@@ -13090,24 +13073,49 @@ var ChatService = class {
13090
13073
  return chat.provider.respondToToolInput(requestId, selectionId);
13091
13074
  }
13092
13075
  async deleteChat(chatId) {
13093
- const chat = this.requireChat(chatId);
13094
- if (chat.persisted.title === DEFAULT_CHAT_TITLES[chat.persisted.provider]) {
13095
- throw new DefaultChatDeletionError();
13076
+ this.requireChat(chatId);
13077
+ const toDelete = [chatId, ...this.collectDescendants(chatId)];
13078
+ const deletedAt = (/* @__PURE__ */ new Date()).toISOString();
13079
+ for (const id of toDelete) {
13080
+ const target = this.chats.get(id);
13081
+ if (!target || target.persisted.deletedAt) continue;
13082
+ if (target.provider.isProcessing()) {
13083
+ await target.provider.interrupt().catch(() => {
13084
+ });
13085
+ target.hasActiveTurn = false;
13086
+ target.activeMessageId = null;
13087
+ target.pendingMessageIds = [];
13088
+ target.acceptedUserEvents.clear();
13089
+ }
13090
+ if (hasChatStarted(this.toSummary(target))) {
13091
+ target.persisted.deletedAt = deletedAt;
13092
+ } else {
13093
+ this.chats.delete(id);
13094
+ target.provider.dispose?.();
13095
+ await this.deleteHistoryFile(target.persisted);
13096
+ }
13097
+ await this.publish({ type: "chat.deleted", payload: { chatId: id, chat: this.toSummary(target) } });
13096
13098
  }
13097
- if (chat.provider.isProcessing()) {
13098
- throw new ChatProcessingDeletionError();
13099
+ await this.persistAllChats();
13100
+ }
13101
+ async restoreChat(chatId) {
13102
+ const chat = this.chats.get(chatId);
13103
+ if (!chat?.persisted.deletedAt) {
13104
+ throw new ChatNotFoundError(chatId);
13099
13105
  }
13100
- const toDelete = this.collectDescendants(chatId);
13101
- toDelete.push(chatId);
13102
- for (const id of toDelete) {
13106
+ if (isDefaultChat(chat.persisted) && Array.from(this.chats.values()).some((other) => other !== chat && !other.persisted.deletedAt && other.persisted.provider === chat.persisted.provider && other.persisted.title === chat.persisted.title)) {
13107
+ chat.persisted.title = `${chat.persisted.title} (restored)`;
13108
+ }
13109
+ const restoredAt = (/* @__PURE__ */ new Date()).toISOString();
13110
+ for (const id of [chatId, ...this.collectDescendants(chatId)]) {
13103
13111
  const target = this.chats.get(id);
13104
- if (!target) continue;
13105
- this.chats.delete(id);
13106
- target.provider.dispose?.();
13107
- await this.deleteHistoryFile(target.persisted);
13108
- await this.publish({ type: "chat.deleted", payload: { chatId: id } });
13112
+ if (!target?.persisted.deletedAt) continue;
13113
+ target.persisted.deletedAt = null;
13114
+ target.persisted.updatedAt = restoredAt;
13115
+ await this.publish({ type: "chat.created", payload: { chat: this.toSummary(target) } });
13109
13116
  }
13110
13117
  await this.persistAllChats();
13118
+ return this.toSummary(chat);
13111
13119
  }
13112
13120
  /**
13113
13121
  * Recursively collects all descendant chat IDs of a given parent.
@@ -13152,7 +13160,7 @@ var ChatService = class {
13152
13160
  getProcessingCount() {
13153
13161
  let count = 0;
13154
13162
  for (const chat of this.chats.values()) {
13155
- if (isChatActive(chat)) {
13163
+ if (!chat.persisted.deletedAt && isChatActive(chat)) {
13156
13164
  count += 1;
13157
13165
  }
13158
13166
  }
@@ -13179,9 +13187,11 @@ var ChatService = class {
13179
13187
  persisted.providerSessionId = sessionId;
13180
13188
  persisted.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
13181
13189
  await this.persistAllChats();
13190
+ const chat = this.getRuntimeChat(persisted.id);
13191
+ if (!chat) return;
13182
13192
  await this.publish({
13183
13193
  type: "chat.updated",
13184
- payload: { chat: this.toSummary(this.requireChat(persisted.id)) }
13194
+ payload: { chat: this.toSummary(chat) }
13185
13195
  });
13186
13196
  };
13187
13197
  const onProviderTurnComplete = async () => {
@@ -13273,12 +13283,13 @@ var ChatService = class {
13273
13283
  isAuthRetrying: chat.provider.isAuthRetrying?.() ?? false,
13274
13284
  goal: chat.provider.getGoal?.() ?? null,
13275
13285
  parentChatId: chat.persisted.parentChatId,
13276
- lastMessageText: chat.persisted.lastMessageText ?? null
13286
+ lastMessageText: chat.persisted.lastMessageText ?? null,
13287
+ deletedAt: chat.persisted.deletedAt ?? null
13277
13288
  };
13278
13289
  }
13279
13290
  requireChat(chatId) {
13280
13291
  const chat = this.chats.get(chatId);
13281
- if (!chat) {
13292
+ if (!chat || chat.persisted.deletedAt) {
13282
13293
  throw new ChatNotFoundError(chatId);
13283
13294
  }
13284
13295
  return chat;
@@ -13387,7 +13398,8 @@ var ChatService = class {
13387
13398
  await this.publishAgentTurnCompleteWebhook(chat);
13388
13399
  }
13389
13400
  getRuntimeChat(chatId) {
13390
- return this.chats.get(chatId) ?? null;
13401
+ const chat = this.chats.get(chatId) ?? null;
13402
+ return chat && !chat.persisted.deletedAt ? chat : null;
13391
13403
  }
13392
13404
  async loadChats() {
13393
13405
  try {
@@ -14162,11 +14174,12 @@ import { existsSync as existsSync9 } from "fs";
14162
14174
  import { spawn as spawn5 } from "node-pty";
14163
14175
  var MAX_REPLAY_CHARS = 1024 * 1024;
14164
14176
  var MAX_TERMINAL_SESSIONS = 8;
14177
+ var MAX_PENDING_INPUT = 64;
14165
14178
  var TerminalService = class {
14166
14179
  sessions = /* @__PURE__ */ new Map();
14167
14180
  nextTitleNumber = 1;
14168
14181
  list() {
14169
- return [...this.sessions.values()].map(({ pty: _pty, replay: _replay, subscribers: _subscribers, ...session }) => session);
14182
+ return [...this.sessions.values()].map((session) => this.publicSession(session));
14170
14183
  }
14171
14184
  create(cwd, cols, rows) {
14172
14185
  if (this.sessions.size >= MAX_TERMINAL_SESSIONS) {
@@ -14195,7 +14208,10 @@ var TerminalService = class {
14195
14208
  exited: false,
14196
14209
  pty,
14197
14210
  replay: "",
14198
- subscribers: /* @__PURE__ */ new Set()
14211
+ subscribers: /* @__PURE__ */ new Set(),
14212
+ inputGeneration: -1,
14213
+ nextInputSequence: 0,
14214
+ pendingInput: /* @__PURE__ */ new Map()
14199
14215
  };
14200
14216
  this.sessions.set(id, session);
14201
14217
  pty.onData((data) => {
@@ -14213,10 +14229,25 @@ var TerminalService = class {
14213
14229
  });
14214
14230
  return createSuccessResult(this.publicSession(session));
14215
14231
  }
14216
- write(id, data) {
14232
+ write(id, data, generation, sequence) {
14217
14233
  const session = this.sessions.get(id);
14218
14234
  if (!session || session.exited) return false;
14219
- session.pty.write(data);
14235
+ if (generation < session.inputGeneration) return true;
14236
+ if (generation > session.inputGeneration) {
14237
+ session.inputGeneration = generation;
14238
+ session.nextInputSequence = 0;
14239
+ session.pendingInput.clear();
14240
+ }
14241
+ if (sequence < session.nextInputSequence) return true;
14242
+ session.pendingInput.set(sequence, data);
14243
+ if (session.pendingInput.size > MAX_PENDING_INPUT) {
14244
+ session.nextInputSequence = Math.min(...session.pendingInput.keys());
14245
+ }
14246
+ let pendingInput;
14247
+ while ((pendingInput = session.pendingInput.get(session.nextInputSequence)) !== void 0) {
14248
+ session.pty.write(pendingInput);
14249
+ session.pendingInput.delete(session.nextInputSequence++);
14250
+ }
14220
14251
  return true;
14221
14252
  }
14222
14253
  resize(id, cols, rows) {
@@ -14242,7 +14273,15 @@ var TerminalService = class {
14242
14273
  return true;
14243
14274
  }
14244
14275
  publicSession(session) {
14245
- const { pty: _pty, replay: _replay, subscribers: _subscribers, ...value } = session;
14276
+ const {
14277
+ pty: _pty,
14278
+ replay: _replay,
14279
+ subscribers: _subscribers,
14280
+ inputGeneration: _inputGeneration,
14281
+ nextInputSequence: _nextInputSequence,
14282
+ pendingInput: _pendingInput,
14283
+ ...value
14284
+ } = session;
14246
14285
  return value;
14247
14286
  }
14248
14287
  };
@@ -14268,7 +14307,9 @@ var terminalSizeSchema = z2.object({
14268
14307
  rows: z2.number().int().min(1).max(200)
14269
14308
  });
14270
14309
  var writeTerminalSessionSchema = z2.object({
14271
- data: z2.string().max(64 * 1024)
14310
+ data: z2.string().max(64 * 1024),
14311
+ generation: z2.number().int().nonnegative(),
14312
+ sequence: z2.number().int().nonnegative()
14272
14313
  });
14273
14314
  var sendMessageSchema = z2.object({
14274
14315
  message: z2.string().min(1),
@@ -14370,7 +14411,8 @@ function createV1Routes(deps) {
14370
14411
  app2.get("/chats", (c) => {
14371
14412
  const includeChildren = c.req.query("includeChildren") === "true";
14372
14413
  const response = {
14373
- chats: deps.chatService.listChats(includeChildren)
14414
+ chats: deps.chatService.listChats(includeChildren),
14415
+ deletedChats: deps.chatService.listDeletedChats()
14374
14416
  };
14375
14417
  return c.json(response);
14376
14418
  });
@@ -14414,24 +14456,25 @@ function createV1Routes(deps) {
14414
14456
  return c.json({ success: true, chatId });
14415
14457
  } catch (error) {
14416
14458
  const details = error instanceof Error ? error.message : "Unknown error";
14417
- if (error instanceof DefaultChatDeletionError) {
14418
- return c.json(jsonError("Failed to delete chat", "Default chats cannot be deleted"), 400);
14419
- }
14420
- if (error instanceof ChatProcessingDeletionError) {
14421
- return c.json(jsonError("Failed to delete chat", "Cannot delete a chat while it is processing"), 400);
14422
- }
14423
- if (error instanceof ChatNotFoundError) {
14424
- return c.json(jsonError("Failed to delete chat", details), 404);
14425
- }
14426
- if (details.includes("Default chats cannot be deleted") || details.includes("while it is processing")) {
14427
- return c.json(jsonError("Failed to delete chat", details), 400);
14428
- }
14429
- if (details.includes("Chat not found")) {
14459
+ if (error instanceof ChatNotFoundError || details.includes("Chat not found")) {
14430
14460
  return c.json(jsonError("Failed to delete chat", details), 404);
14431
14461
  }
14432
14462
  return c.json(jsonError("Failed to delete chat", details), 500);
14433
14463
  }
14434
14464
  });
14465
+ app2.post("/chats/:chatId/restore", async (c) => {
14466
+ const chatId = c.req.param("chatId");
14467
+ try {
14468
+ const chat = await deps.chatService.restoreChat(chatId);
14469
+ return c.json({ chat });
14470
+ } catch (error) {
14471
+ const details = error instanceof Error ? error.message : "Unknown error";
14472
+ if (error instanceof ChatNotFoundError) {
14473
+ return c.json(jsonError("Failed to restore chat", details), 404);
14474
+ }
14475
+ return c.json(jsonError("Failed to restore chat", details), 500);
14476
+ }
14477
+ });
14435
14478
  app2.get("/chats/:chatId/history", async (c) => {
14436
14479
  try {
14437
14480
  const history = await deps.chatService.getChatHistory(
@@ -14656,7 +14699,7 @@ function createV1Routes(deps) {
14656
14699
  });
14657
14700
  app2.post("/terminal/sessions/:id/input", async (c) => {
14658
14701
  const body = writeTerminalSessionSchema.parse(await c.req.json());
14659
- if (!terminalService.write(c.req.param("id"), body.data)) {
14702
+ if (!terminalService.write(c.req.param("id"), body.data, body.generation, body.sequence)) {
14660
14703
  return c.json(jsonError("Terminal session not found or exited"), 404);
14661
14704
  }
14662
14705
  return c.body(null, 204);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.443",
3
+ "version": "0.1.445",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",