replicas-engine 0.1.444 → 0.1.446

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 -83
  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-v4";
527
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-17-v6";
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.444";
8603
+ var ENGINE_PACKAGE_VERSION = "0.1.446";
8596
8604
  var INITIALIZE_METHOD = "initialize";
8597
8605
  var INITIALIZED_NOTIFICATION = "initialized";
8598
8606
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -9491,18 +9499,6 @@ var CodexThreadNotFoundError = class extends Error {
9491
9499
  this.name = "CodexThreadNotFoundError";
9492
9500
  }
9493
9501
  };
9494
- var DefaultChatDeletionError = class extends Error {
9495
- constructor() {
9496
- super("Default chats cannot be deleted");
9497
- this.name = "DefaultChatDeletionError";
9498
- }
9499
- };
9500
- var ChatProcessingDeletionError = class extends Error {
9501
- constructor() {
9502
- super("Cannot delete a chat while it is processing");
9503
- this.name = "ChatProcessingDeletionError";
9504
- }
9505
- };
9506
9502
  var DuplicateDefaultChatError = class extends Error {
9507
9503
  constructor(provider) {
9508
9504
  super(`Default chat already exists for provider: ${provider}`);
@@ -12644,13 +12640,15 @@ async function uploadChatTranscript(chatId, filePath, chat) {
12644
12640
  title: chat.title,
12645
12641
  createdAt: chat.createdAt,
12646
12642
  updatedAt: chat.updatedAt,
12647
- parentChatId: chat.parentChatId
12643
+ parentChatId: chat.parentChatId,
12644
+ deletedAt: chat.deletedAt ?? null
12648
12645
  };
12649
12646
  form.append("provider", metadata.provider);
12650
12647
  form.append("title", metadata.title);
12651
12648
  form.append("created_at", metadata.createdAt);
12652
12649
  form.append("updated_at", metadata.updatedAt);
12653
12650
  if (metadata.parentChatId) form.append("parent_chat_id", metadata.parentChatId);
12651
+ form.append("deleted_at", metadata.deletedAt ?? "");
12654
12652
  }
12655
12653
  form.append(
12656
12654
  "file",
@@ -12760,7 +12758,7 @@ function isPersistedChat(value) {
12760
12758
  return false;
12761
12759
  }
12762
12760
  const candidate = value;
12763
- 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");
12764
12762
  }
12765
12763
  function normalizePersistedChat(chat) {
12766
12764
  const isLegacyCodexSdkChat = chat.provider === "codex" && (chat.codexBackend === "sdk" || chat.codexBackend === void 0 && chat.providerSessionId !== null);
@@ -12772,7 +12770,8 @@ function normalizePersistedChat(chat) {
12772
12770
  updatedAt: chat.updatedAt,
12773
12771
  providerSessionId: isLegacyCodexSdkChat ? null : chat.providerSessionId,
12774
12772
  parentChatId: chat.parentChatId ?? null,
12775
- lastMessageText: chat.lastMessageText ?? null
12773
+ lastMessageText: chat.lastMessageText ?? null,
12774
+ deletedAt: chat.deletedAt ?? null
12776
12775
  };
12777
12776
  }
12778
12777
  function parsePersistedChatsContent(content) {
@@ -12802,7 +12801,9 @@ function createUserMessageEvent(message, messageId, images) {
12802
12801
  var ChatService = class {
12803
12802
  constructor(workingDirectory) {
12804
12803
  this.workingDirectory = workingDirectory;
12805
- keepAliveService.setActivityCheck(() => [...this.chats.values()].some(isChatActive));
12804
+ keepAliveService.setActivityCheck(
12805
+ () => [...this.chats.values()].some((chat) => !chat.persisted.deletedAt && isChatActive(chat))
12806
+ );
12806
12807
  }
12807
12808
  workingDirectory;
12808
12809
  chats = /* @__PURE__ */ new Map();
@@ -12821,46 +12822,27 @@ var ChatService = class {
12821
12822
  const runtime = this.createRuntimeChat(chat);
12822
12823
  this.chats.set(chat.id, runtime);
12823
12824
  }
12824
- const hasClaudeDefault = [...this.chats.values()].some(
12825
- (c) => c.persisted.provider === "claude" && c.persisted.title === "Claude Code"
12826
- );
12827
- const hasCodexDefault = [...this.chats.values()].some(
12828
- (c) => c.persisted.provider === "codex" && c.persisted.title === "Codex"
12829
- );
12830
- const hasCursorDefault = [...this.chats.values()].some(
12831
- (c) => c.persisted.provider === "cursor" && c.persisted.title === "Cursor"
12832
- );
12833
- const hasOpencodeDefault = [...this.chats.values()].some(
12834
- (c) => c.persisted.provider === "opencode" && c.persisted.title === "Opencode"
12835
- );
12836
- if (!hasClaudeDefault) {
12837
- await this.createChat({ provider: "claude", title: "Claude Code" });
12838
- }
12839
- if (!hasCodexDefault) {
12840
- await this.createChat({ provider: "codex", title: "Codex" });
12841
- }
12842
- if (!hasCursorDefault) {
12843
- await this.createChat({ provider: "cursor", title: "Cursor" });
12844
- }
12845
- if (!hasOpencodeDefault) {
12846
- await this.createChat({ provider: "opencode", title: "Opencode" });
12847
- }
12848
- const hasRelayDefault = [...this.chats.values()].some(
12849
- (c) => c.persisted.provider === "relay" && c.persisted.title === "Relay"
12850
- );
12851
- if (!hasRelayDefault) {
12852
- 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
+ }
12853
12832
  }
12854
12833
  }
12855
12834
  listChats(includeChildren = false) {
12856
- 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 ?? ""));
12857
12839
  }
12858
12840
  listChildChats(parentChatId) {
12859
- 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));
12860
12842
  }
12861
12843
  getChat(chatId) {
12862
12844
  const chat = this.chats.get(chatId);
12863
- return chat ? this.toSummary(chat) : null;
12845
+ return chat && !chat.persisted.deletedAt ? this.toSummary(chat) : null;
12864
12846
  }
12865
12847
  async listSlashCommands(chatId) {
12866
12848
  const chat = this.requireChat(chatId);
@@ -12880,7 +12862,7 @@ var ChatService = class {
12880
12862
  async createChat(request) {
12881
12863
  const now = (/* @__PURE__ */ new Date()).toISOString();
12882
12864
  const title = request.title?.trim() || `${request.provider} chat`;
12883
- 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))) {
12884
12866
  throw new DuplicateDefaultChatError(request.provider);
12885
12867
  }
12886
12868
  const parentChatId = request.parentChatId ?? null;
@@ -13091,24 +13073,49 @@ var ChatService = class {
13091
13073
  return chat.provider.respondToToolInput(requestId, selectionId);
13092
13074
  }
13093
13075
  async deleteChat(chatId) {
13094
- const chat = this.requireChat(chatId);
13095
- if (chat.persisted.title === DEFAULT_CHAT_TITLES[chat.persisted.provider]) {
13096
- 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) } });
13097
13098
  }
13098
- if (chat.provider.isProcessing()) {
13099
- 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);
13100
13105
  }
13101
- const toDelete = this.collectDescendants(chatId);
13102
- toDelete.push(chatId);
13103
- 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)]) {
13104
13111
  const target = this.chats.get(id);
13105
- if (!target) continue;
13106
- this.chats.delete(id);
13107
- target.provider.dispose?.();
13108
- await this.deleteHistoryFile(target.persisted);
13109
- 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) } });
13110
13116
  }
13111
13117
  await this.persistAllChats();
13118
+ return this.toSummary(chat);
13112
13119
  }
13113
13120
  /**
13114
13121
  * Recursively collects all descendant chat IDs of a given parent.
@@ -13153,7 +13160,7 @@ var ChatService = class {
13153
13160
  getProcessingCount() {
13154
13161
  let count = 0;
13155
13162
  for (const chat of this.chats.values()) {
13156
- if (isChatActive(chat)) {
13163
+ if (!chat.persisted.deletedAt && isChatActive(chat)) {
13157
13164
  count += 1;
13158
13165
  }
13159
13166
  }
@@ -13180,9 +13187,11 @@ var ChatService = class {
13180
13187
  persisted.providerSessionId = sessionId;
13181
13188
  persisted.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
13182
13189
  await this.persistAllChats();
13190
+ const chat = this.getRuntimeChat(persisted.id);
13191
+ if (!chat) return;
13183
13192
  await this.publish({
13184
13193
  type: "chat.updated",
13185
- payload: { chat: this.toSummary(this.requireChat(persisted.id)) }
13194
+ payload: { chat: this.toSummary(chat) }
13186
13195
  });
13187
13196
  };
13188
13197
  const onProviderTurnComplete = async () => {
@@ -13274,12 +13283,13 @@ var ChatService = class {
13274
13283
  isAuthRetrying: chat.provider.isAuthRetrying?.() ?? false,
13275
13284
  goal: chat.provider.getGoal?.() ?? null,
13276
13285
  parentChatId: chat.persisted.parentChatId,
13277
- lastMessageText: chat.persisted.lastMessageText ?? null
13286
+ lastMessageText: chat.persisted.lastMessageText ?? null,
13287
+ deletedAt: chat.persisted.deletedAt ?? null
13278
13288
  };
13279
13289
  }
13280
13290
  requireChat(chatId) {
13281
13291
  const chat = this.chats.get(chatId);
13282
- if (!chat) {
13292
+ if (!chat || chat.persisted.deletedAt) {
13283
13293
  throw new ChatNotFoundError(chatId);
13284
13294
  }
13285
13295
  return chat;
@@ -13388,7 +13398,8 @@ var ChatService = class {
13388
13398
  await this.publishAgentTurnCompleteWebhook(chat);
13389
13399
  }
13390
13400
  getRuntimeChat(chatId) {
13391
- return this.chats.get(chatId) ?? null;
13401
+ const chat = this.chats.get(chatId) ?? null;
13402
+ return chat && !chat.persisted.deletedAt ? chat : null;
13392
13403
  }
13393
13404
  async loadChats() {
13394
13405
  try {
@@ -14400,7 +14411,8 @@ function createV1Routes(deps) {
14400
14411
  app2.get("/chats", (c) => {
14401
14412
  const includeChildren = c.req.query("includeChildren") === "true";
14402
14413
  const response = {
14403
- chats: deps.chatService.listChats(includeChildren)
14414
+ chats: deps.chatService.listChats(includeChildren),
14415
+ deletedChats: deps.chatService.listDeletedChats()
14404
14416
  };
14405
14417
  return c.json(response);
14406
14418
  });
@@ -14444,24 +14456,25 @@ function createV1Routes(deps) {
14444
14456
  return c.json({ success: true, chatId });
14445
14457
  } catch (error) {
14446
14458
  const details = error instanceof Error ? error.message : "Unknown error";
14447
- if (error instanceof DefaultChatDeletionError) {
14448
- return c.json(jsonError("Failed to delete chat", "Default chats cannot be deleted"), 400);
14449
- }
14450
- if (error instanceof ChatProcessingDeletionError) {
14451
- return c.json(jsonError("Failed to delete chat", "Cannot delete a chat while it is processing"), 400);
14452
- }
14453
- if (error instanceof ChatNotFoundError) {
14454
- return c.json(jsonError("Failed to delete chat", details), 404);
14455
- }
14456
- if (details.includes("Default chats cannot be deleted") || details.includes("while it is processing")) {
14457
- return c.json(jsonError("Failed to delete chat", details), 400);
14458
- }
14459
- if (details.includes("Chat not found")) {
14459
+ if (error instanceof ChatNotFoundError || details.includes("Chat not found")) {
14460
14460
  return c.json(jsonError("Failed to delete chat", details), 404);
14461
14461
  }
14462
14462
  return c.json(jsonError("Failed to delete chat", details), 500);
14463
14463
  }
14464
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
+ });
14465
14478
  app2.get("/chats/:chatId/history", async (c) => {
14466
14479
  try {
14467
14480
  const history = await deps.chatService.getChatHistory(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.444",
3
+ "version": "0.1.446",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",