replicas-engine 0.1.1250 → 0.1.1251

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.
@@ -8,12 +8,12 @@ import {
8
8
  listRunningCodexModels,
9
9
  restartCodexAspHost,
10
10
  restartCodexAspHostIfRunning
11
- } from "./chunk-GH5EEUT2.js";
12
- import "./chunk-6PVW5AKP.js";
13
- import "./chunk-5GHRPLRX.js";
14
- import "./chunk-3C2WTKME.js";
11
+ } from "./chunk-HRWUYYTF.js";
12
+ import "./chunk-T5YXOKTZ.js";
13
+ import "./chunk-S4QAKSXE.js";
14
+ import "./chunk-PYR5LTLY.js";
15
15
  import "./chunk-UZSNFLDQ.js";
16
- import "./chunk-7QJWP5ZL.js";
16
+ import "./chunk-MRBFRPXT.js";
17
17
  import "./chunk-VEQXQN22.js";
18
18
  export {
19
19
  CODEX_ULTRAFAST_SERVICE_TIER,
@@ -10,15 +10,15 @@ import {
10
10
  resolveDiffBase,
11
11
  runGitCommand,
12
12
  setAgentCredentialSnapshot
13
- } from "./chunk-6PVW5AKP.js";
13
+ } from "./chunk-T5YXOKTZ.js";
14
14
  import {
15
15
  AppServerProcess,
16
16
  buildCodexAgentEnv
17
- } from "./chunk-5GHRPLRX.js";
17
+ } from "./chunk-S4QAKSXE.js";
18
18
  import {
19
19
  SUBPROCESS_MAX_BUFFER,
20
20
  execFileAsync
21
- } from "./chunk-3C2WTKME.js";
21
+ } from "./chunk-PYR5LTLY.js";
22
22
  import {
23
23
  isRecord
24
24
  } from "./chunk-UZSNFLDQ.js";
@@ -55,7 +55,7 @@ import {
55
55
  resolveOpenAICompatibleModelsUrl,
56
56
  splitMothershipInstructions,
57
57
  withTimeout
58
- } from "./chunk-7QJWP5ZL.js";
58
+ } from "./chunk-MRBFRPXT.js";
59
59
 
60
60
  // src/managers/codex-token-manager.ts
61
61
  import { promises as fs } from "fs";
@@ -291,7 +291,7 @@ var CodexTokenManager = class extends BaseRefreshManager {
291
291
  await this.applyCredentialUpdate(++this.credentialGeneration, async () => {
292
292
  await this.applyCredentialsResponse(data);
293
293
  setAgentCredentialSnapshot("codex", data);
294
- const { restartCodexAspHostIfRunning: restartCodexAspHostIfRunning2 } = await import("./asp-host-UBXPKAXA.js");
294
+ const { restartCodexAspHostIfRunning: restartCodexAspHostIfRunning2 } = await import("./asp-host-ENQ4ABM4.js");
295
295
  await restartCodexAspHostIfRunning2();
296
296
  });
297
297
  await this.start(true);
@@ -313,7 +313,7 @@ var CodexTokenManager = class extends BaseRefreshManager {
313
313
  const accountChanged = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS.codex?.credentialId !== data.credentialId;
314
314
  await this.applyCredentialsResponse(data);
315
315
  if (restartOnChange && (accountChanged || CODEX_AUTH_ENV_KEYS.some((key, index) => process.env[key] !== previousEnv[index]))) {
316
- const { restartCodexAspHostIfRunning: restartCodexAspHostIfRunning2 } = await import("./asp-host-UBXPKAXA.js");
316
+ const { restartCodexAspHostIfRunning: restartCodexAspHostIfRunning2 } = await import("./asp-host-ENQ4ABM4.js");
317
317
  await restartCodexAspHostIfRunning2();
318
318
  }
319
319
  setAgentCredentialSnapshot("codex", data);
@@ -5,14 +5,14 @@ import {
5
5
  getOriginDefaultBranch,
6
6
  monolithRequest,
7
7
  runGitCommand
8
- } from "./chunk-6PVW5AKP.js";
8
+ } from "./chunk-T5YXOKTZ.js";
9
9
  import {
10
10
  extractCommandProtectionCommandText,
11
11
  findCommandProtectionGitLookups,
12
12
  findGitCommitSignals,
13
13
  findPrMergeSignals,
14
14
  parseCommandProtectionRequest
15
- } from "./chunk-7QJWP5ZL.js";
15
+ } from "./chunk-MRBFRPXT.js";
16
16
 
17
17
  // src/services/command-protection-service.ts
18
18
  import { readFile, stat } from "fs/promises";
@@ -5,7 +5,7 @@ import {
5
5
  extractCommandProtectionCommandText,
6
6
  isRecord,
7
7
  parseCodeHostPrUrl
8
- } from "./chunk-7QJWP5ZL.js";
8
+ } from "./chunk-MRBFRPXT.js";
9
9
 
10
10
  // src/services/published-pull-request-urls.ts
11
11
  function publishedPullRequestUrls(result) {
@@ -3,7 +3,7 @@ import { createRequire as __createRequire } from 'node:module';
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  AspClient
6
- } from "./chunk-5GHRPLRX.js";
6
+ } from "./chunk-S4QAKSXE.js";
7
7
  import {
8
8
  ASTER_BASE_URL,
9
9
  ASTER_PROVIDER,
@@ -13,7 +13,7 @@ import {
13
13
  isRecord,
14
14
  readOllamaAuthEnv,
15
15
  readOpenAICompatibleAuthEnv
16
- } from "./chunk-7QJWP5ZL.js";
16
+ } from "./chunk-MRBFRPXT.js";
17
17
 
18
18
  // src/managers/codex-asp/notification-dispatch.ts
19
19
  var TURN_STARTED_METHOD = "turn/started";
@@ -1414,6 +1414,7 @@ var ACCEPTED_USER_MESSAGE_SOURCE = "replicas-chat-turn-accepted";
1414
1414
  var QUEUED_MESSAGE_REMOVED_EVENT_TYPE = "replicas-queued-message-removed";
1415
1415
  var REMOVED_MESSAGE_IDS_PAYLOAD_KEY = "removedMessageIds";
1416
1416
  var USER_MESSAGE_ID_PAYLOAD_KEY = "replicasMessageId";
1417
+ var REPLACED_MESSAGE_ID_PAYLOAD_KEY = "replicasReplacedMessageId";
1417
1418
  var CODEX_ASP_ITEM_ID_PAYLOAD_KEY = "codexAspItemId";
1418
1419
  var CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE = "codex-asp-transcript-updated";
1419
1420
  var CODEX_ITEM_EVENT_TYPE = "codex-item";
@@ -1609,7 +1610,8 @@ var sendChatMessageRequestSchema = z4.object({
1609
1610
  senderDisplayName: z4.string().optional(),
1610
1611
  senderAvatarUrl: z4.string().optional(),
1611
1612
  errorNotificationTarget: integrationErrorNotificationTargetSchema.optional(),
1612
- errorNotificationTargets: z4.array(integrationErrorNotificationTargetSchema).optional()
1613
+ errorNotificationTargets: z4.array(integrationErrorNotificationTargetSchema).optional(),
1614
+ replacesMessageId: z4.string().min(1).max(256).optional()
1613
1615
  }).passthrough();
1614
1616
  function isChatMessageSender(value) {
1615
1617
  return isRecord(value) && (value.messageId === void 0 || typeof value.messageId === "string") && typeof value.senderUserId === "string" && typeof value.senderEmail === "string" && typeof value.recordedAt === "string";
@@ -1631,7 +1633,7 @@ function imageContentToUserMessageImages(images) {
1631
1633
  }
1632
1634
  return userImages.length > 0 ? userImages : void 0;
1633
1635
  }
1634
- function createAcceptedUserMessageEvent(message2, messageId, timestamp, images) {
1636
+ function createAcceptedUserMessageEvent(message2, messageId, timestamp, images, replacesMessageId) {
1635
1637
  const eventImages = imageContentToUserMessageImages(images);
1636
1638
  return {
1637
1639
  timestamp,
@@ -1641,6 +1643,7 @@ function createAcceptedUserMessageEvent(message2, messageId, timestamp, images)
1641
1643
  message: message2,
1642
1644
  source: ACCEPTED_USER_MESSAGE_SOURCE,
1643
1645
  [USER_MESSAGE_ID_PAYLOAD_KEY]: messageId,
1646
+ ...replacesMessageId ? { [REPLACED_MESSAGE_ID_PAYLOAD_KEY]: replacesMessageId } : {},
1644
1647
  ...eventImages ? { images: eventImages } : {}
1645
1648
  }
1646
1649
  };
@@ -6230,6 +6233,10 @@ function takeRecordedPrompt(prompts, echo, turnIndex) {
6230
6233
  }
6231
6234
  return closestIndex === -1 ? void 0 : prompts.splice(closestIndex, 1)[0].message;
6232
6235
  }
6236
+ var promptTurnIds = /* @__PURE__ */ new WeakMap();
6237
+ function codexPromptTurnId(message2) {
6238
+ return promptTurnIds.get(message2);
6239
+ }
6233
6240
  function parseCodexEvents(events) {
6234
6241
  const messages = [];
6235
6242
  const turns = collectCodexTurns(events);
@@ -6453,6 +6460,7 @@ function parseCodexEvents(events) {
6453
6460
  const turn = turns.get(turnId);
6454
6461
  if (!turn) continue;
6455
6462
  const kept = [];
6463
+ let opened = false;
6456
6464
  for (const message2 of messagesForCodexTurn(turn)) {
6457
6465
  if (retriedTurnIds.has(turnId)) {
6458
6466
  if (message2.type === "error") continue;
@@ -6467,12 +6475,11 @@ function parseCodexEvents(events) {
6467
6475
  }
6468
6476
  const prompts = recordedPrompts.get(stripReplicasInstructionBlock(message2.content));
6469
6477
  const recorded = prompts && takeRecordedPrompt(prompts, message2, index);
6470
- if (!recorded) {
6471
- kept.push(message2);
6472
- continue;
6473
- }
6474
- claimedPrompts.add(recorded);
6475
- kept.push({ ...recorded, images: recorded.images ?? message2.images });
6478
+ if (recorded) claimedPrompts.add(recorded);
6479
+ const prompt = recorded ? { ...recorded, images: recorded.images ?? message2.images } : message2;
6480
+ if (!opened) promptTurnIds.set(prompt, turnId);
6481
+ opened = true;
6482
+ kept.push(prompt);
6476
6483
  }
6477
6484
  messages.splice(index, 0, ...kept);
6478
6485
  }
@@ -7792,7 +7799,9 @@ function parseClaudeEvents(events, parentToolUseId) {
7792
7799
  // ../shared/src/display-message/parsers/index.ts
7793
7800
  var INTERRUPTION_DEDUP_WINDOW_MS = 15e3;
7794
7801
  function parseAgentEvents(events, agentType) {
7795
- events = excludeQueuedAcceptedEvents(events, []);
7802
+ return withoutReplacedMessages(excludeQueuedAcceptedEvents(events, []), (segment) => parseProviderEvents(segment, agentType));
7803
+ }
7804
+ function parseProviderEvents(events, agentType, parentToolUseId) {
7796
7805
  if (agentType === "codex") {
7797
7806
  return parseCodexEvents(events);
7798
7807
  }
@@ -7808,21 +7817,37 @@ function parseAgentEvents(events, agentType) {
7808
7817
  if (agentType === "pi") {
7809
7818
  return parsePiEvents(events);
7810
7819
  }
7811
- return parseClaudeEvents(events);
7820
+ return parseClaudeEvents(events, parentToolUseId);
7812
7821
  }
7813
7822
  function parseDisplayMessages(events, agentType, options = {}) {
7814
- events = excludeQueuedAcceptedEvents(events, []);
7815
- const parsedEvents = agentType === "claude" ? parseClaudeEvents(events, options.parentToolUseId) : parseAgentEvents(events, agentType);
7816
- const reconciledEvents = [];
7817
- for (const message2 of parsedEvents) {
7818
- if (message2.type === "user") upsertDisplayMessage(reconciledEvents, message2);
7819
- else reconciledEvents.push(message2);
7820
- }
7821
- if (options.filter === false) return reconciledEvents;
7822
- return applyEngineNotices(
7823
- applyInterruptions(filterDisplayMessages(reconciledEvents, agentType), events),
7824
- events
7825
- );
7823
+ return withoutReplacedMessages(excludeQueuedAcceptedEvents(events, []), (segment) => {
7824
+ const parsedEvents = parseProviderEvents(segment, agentType, options.parentToolUseId);
7825
+ const reconciledEvents = [];
7826
+ for (const message2 of parsedEvents) {
7827
+ if (message2.type === "user") upsertDisplayMessage(reconciledEvents, message2);
7828
+ else reconciledEvents.push(message2);
7829
+ }
7830
+ if (options.filter === false) return reconciledEvents;
7831
+ return applyEngineNotices(
7832
+ applyInterruptions(filterDisplayMessages(reconciledEvents, agentType), segment),
7833
+ segment
7834
+ );
7835
+ });
7836
+ }
7837
+ function withoutReplacedMessages(events, parse) {
7838
+ let kept = [];
7839
+ let start = 0;
7840
+ const handled = /* @__PURE__ */ new Set();
7841
+ events.forEach((event, index) => {
7842
+ const replaced = getReplacedMessageId(event);
7843
+ if (replaced === null || handled.has(replaced)) return;
7844
+ handled.add(replaced);
7845
+ if (index === 0) return;
7846
+ kept.push(...parse(events.slice(start, index)));
7847
+ kept = kept.slice(0, Math.max(0, kept.findIndex(({ id }) => id === replaced)));
7848
+ start = index;
7849
+ });
7850
+ return start === 0 ? parse(events) : [...kept, ...parse(events.slice(start))];
7826
7851
  }
7827
7852
  function applyInterruptions(messages, events) {
7828
7853
  const result = [...messages];
@@ -7996,6 +8021,10 @@ function getUserMessageId(event) {
7996
8021
  const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
7997
8022
  return typeof messageId === "string" ? messageId : null;
7998
8023
  }
8024
+ function getReplacedMessageId(event) {
8025
+ const messageId = event.payload[REPLACED_MESSAGE_ID_PAYLOAD_KEY];
8026
+ return typeof messageId === "string" ? messageId : null;
8027
+ }
7999
8028
  function getRemovedMessageIds(event) {
8000
8029
  if (event.type !== QUEUED_MESSAGE_REMOVED_EVENT_TYPE) return [];
8001
8030
  const messageIds = event.payload[REMOVED_MESSAGE_IDS_PAYLOAD_KEY];
@@ -8398,8 +8427,11 @@ function redactSecrets(value) {
8398
8427
  function parseChatTranscript(content, provider2, senders) {
8399
8428
  return attachSendersToMessages(parseDisplayMessages(parseCodexHistoryEvents(content), provider2), senders);
8400
8429
  }
8401
- function canonicalizeChatTranscriptBlocks(content, provider2, senders) {
8402
- return parseChatTranscript(content, provider2, senders).flatMap((message2) => {
8430
+ function canonicalizeChatTranscriptBlocks(content, provider2, senders, beforeMessageId) {
8431
+ const messages = parseChatTranscript(content, provider2, senders);
8432
+ const end = beforeMessageId === void 0 ? messages.length : messages.findIndex(({ id }) => id === beforeMessageId);
8433
+ if (end === -1) throw new Error("That message is no longer in the chat history");
8434
+ return messages.slice(0, end).flatMap((message2) => {
8403
8435
  let block = null;
8404
8436
  if (message2.type === "user") {
8405
8437
  block = `## User${message2.senderEmail ? ` (${message2.senderEmail})` : ""}
@@ -10367,6 +10399,7 @@ export {
10367
10399
  QUEUED_MESSAGE_REMOVED_EVENT_TYPE,
10368
10400
  REMOVED_MESSAGE_IDS_PAYLOAD_KEY,
10369
10401
  USER_MESSAGE_ID_PAYLOAD_KEY,
10402
+ REPLACED_MESSAGE_ID_PAYLOAD_KEY,
10370
10403
  CODEX_ASP_ITEM_ID_PAYLOAD_KEY,
10371
10404
  CODEX_ITEM_EVENT_TYPE,
10372
10405
  CODEX_ITEM_PARTIAL_EVENT_TYPE,
@@ -10447,6 +10480,7 @@ export {
10447
10480
  learnedSkillsManifestSchema,
10448
10481
  learnedSkillFormatInstruction,
10449
10482
  areUserMessagesWithinMatchWindow,
10483
+ codexPromptTurnId,
10450
10484
  extractErrorText,
10451
10485
  isTransientErrorText,
10452
10486
  extractToolResultText,
@@ -3,7 +3,7 @@ import { createRequire as __createRequire } from 'node:module';
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  HOOK_EXEC_MAX_BUFFER_BYTES
6
- } from "./chunk-7QJWP5ZL.js";
6
+ } from "./chunk-MRBFRPXT.js";
7
7
 
8
8
  // src/utils/exec.ts
9
9
  import { exec, execFile } from "child_process";
@@ -3,10 +3,10 @@ import { createRequire as __createRequire } from 'node:module';
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  execFileAsync
6
- } from "./chunk-3C2WTKME.js";
6
+ } from "./chunk-PYR5LTLY.js";
7
7
  import {
8
8
  isVersionBelow
9
- } from "./chunk-7QJWP5ZL.js";
9
+ } from "./chunk-MRBFRPXT.js";
10
10
 
11
11
  // src/utils/codex-agent-env.ts
12
12
  function buildCodexAgentEnv(source = process.env) {
@@ -240,7 +240,7 @@ function getCodexModelProvider(method) {
240
240
  if (method === "foundry") return "azure";
241
241
  return method === "ollama" || method === "openai-compatible" ? "replicas_openai_compatible" : "openai";
242
242
  }
243
- var ENGINE_PACKAGE_VERSION = "0.1.1249";
243
+ var ENGINE_PACKAGE_VERSION = "0.1.1251";
244
244
  var INITIALIZE_METHOD = "initialize";
245
245
  var INITIALIZED_NOTIFICATION = "initialized";
246
246
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -4,7 +4,7 @@ const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  SUBPROCESS_MAX_BUFFER,
6
6
  execFileAsync
7
- } from "./chunk-3C2WTKME.js";
7
+ } from "./chunk-PYR5LTLY.js";
8
8
  import {
9
9
  isRecord as isRecord2
10
10
  } from "./chunk-UZSNFLDQ.js";
@@ -19,7 +19,7 @@ import {
19
19
  isValidAgentProvider,
20
20
  parsePosixEnvFile,
21
21
  readReplicasRuntimeEnv
22
- } from "./chunk-7QJWP5ZL.js";
22
+ } from "./chunk-MRBFRPXT.js";
23
23
 
24
24
  // src/runtime-env-loader.ts
25
25
  import { readFileSync } from "fs";
@@ -3,13 +3,13 @@ import { createRequire as __createRequire } from 'node:module';
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  evaluateCommandProtection
6
- } from "./chunk-4AIHQBEA.js";
7
- import "./chunk-6PVW5AKP.js";
8
- import "./chunk-3C2WTKME.js";
6
+ } from "./chunk-IGGMUT3I.js";
7
+ import "./chunk-T5YXOKTZ.js";
8
+ import "./chunk-PYR5LTLY.js";
9
9
  import {
10
10
  isRecord
11
11
  } from "./chunk-UZSNFLDQ.js";
12
- import "./chunk-7QJWP5ZL.js";
12
+ import "./chunk-MRBFRPXT.js";
13
13
  import "./chunk-VEQXQN22.js";
14
14
 
15
15
  // src/command-protection-hook.ts
@@ -13,12 +13,12 @@ import {
13
13
  recoverCompletedTurn,
14
14
  spawnMuseMsp,
15
15
  startMuseSession
16
- } from "./chunk-5ANTWWVQ.js";
16
+ } from "./chunk-KXHXAE4A.js";
17
17
  import {
18
18
  AppServerProcess,
19
19
  buildCodexAgentEnv
20
- } from "./chunk-5GHRPLRX.js";
21
- import "./chunk-3C2WTKME.js";
20
+ } from "./chunk-S4QAKSXE.js";
21
+ import "./chunk-PYR5LTLY.js";
22
22
  import {
23
23
  AGENT,
24
24
  OPENCODE_GO_PROVIDER,
@@ -28,7 +28,7 @@ import {
28
28
  headlessAgentUsagePath,
29
29
  isRecord,
30
30
  withTimeout
31
- } from "./chunk-7QJWP5ZL.js";
31
+ } from "./chunk-MRBFRPXT.js";
32
32
  import "./chunk-VEQXQN22.js";
33
33
 
34
34
  // src/headless-agent.ts
package/dist/src/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  evaluateCommandProtection,
28
28
  extractToolCommand,
29
29
  reportCommandProtectionBlock
30
- } from "./chunk-4AIHQBEA.js";
30
+ } from "./chunk-IGGMUT3I.js";
31
31
  import {
32
32
  ACCOUNT_RATE_LIMITS_UPDATED_METHOD,
33
33
  AGENT_MESSAGE_DELTA_METHOD,
@@ -64,10 +64,10 @@ import {
64
64
  spawnMuseMsp,
65
65
  startMuseSession,
66
66
  uuidV7
67
- } from "./chunk-5ANTWWVQ.js";
67
+ } from "./chunk-KXHXAE4A.js";
68
68
  import {
69
69
  publishedPullRequestUrls
70
- } from "./chunk-FQZ6YTN2.js";
70
+ } from "./chunk-JF3UUTX5.js";
71
71
  import {
72
72
  ACCOUNT_RATE_LIMITS_READ_METHOD,
73
73
  AsyncLock,
@@ -140,7 +140,7 @@ import {
140
140
  timestampFromSeconds,
141
141
  upsertCredentialFileLines,
142
142
  writeSecureCredentialFile
143
- } from "./chunk-GH5EEUT2.js";
143
+ } from "./chunk-HRWUYYTF.js";
144
144
  import {
145
145
  ENGINE_ENV,
146
146
  monolithRequest,
@@ -149,15 +149,15 @@ import {
149
149
  reloadEngineEnv,
150
150
  resolveDiffBase,
151
151
  setAgentCredentialSnapshot
152
- } from "./chunk-6PVW5AKP.js";
152
+ } from "./chunk-T5YXOKTZ.js";
153
153
  import {
154
154
  getCodexModelProvider
155
- } from "./chunk-5GHRPLRX.js";
155
+ } from "./chunk-S4QAKSXE.js";
156
156
  import {
157
157
  SUBPROCESS_MAX_BUFFER,
158
158
  execAsync,
159
159
  execFileAsync
160
- } from "./chunk-3C2WTKME.js";
160
+ } from "./chunk-PYR5LTLY.js";
161
161
  import {
162
162
  isRecord as isRecord2
163
163
  } from "./chunk-UZSNFLDQ.js";
@@ -236,6 +236,7 @@ import {
236
236
  OPENCODE_GO_PROVIDER,
237
237
  QUEUED_MESSAGE_REMOVED_EVENT_TYPE,
238
238
  REMOVED_MESSAGE_IDS_PAYLOAD_KEY,
239
+ REPLACED_MESSAGE_ID_PAYLOAD_KEY,
239
240
  REPLICAS_CONFIG_FILENAMES,
240
241
  REPLICAS_INSTRUCTIONS_TAG,
241
242
  REPLICAS_RUNTIME_ENV_ALIASES,
@@ -269,6 +270,7 @@ import {
269
270
  codexHistoryFormatEvent,
270
271
  codexItemEvent,
271
272
  codexItemFromEvent,
273
+ codexPromptTurnId,
272
274
  codexTranscriptToEvents,
273
275
  codexTurnEvent,
274
276
  codexTurnFromEvent,
@@ -396,7 +398,7 @@ import {
396
398
  workspaceTokenRequestSchema,
397
399
  workspaceTokenResponseSchema,
398
400
  wrapInTag
399
- } from "./chunk-7QJWP5ZL.js";
401
+ } from "./chunk-MRBFRPXT.js";
400
402
  import {
401
403
  cloneMcpConfig,
402
404
  ensureCompatibilityImports,
@@ -9650,6 +9652,7 @@ var EnvironmentDetailsService = class {
9650
9652
  details.supportsChatForking = true;
9651
9653
  details.supportsChatForkMessage = true;
9652
9654
  details.supportsDeferredChatForking = true;
9655
+ details.supportsMessageEditing = true;
9653
9656
  details.supportsSideChats = true;
9654
9657
  details.supportsMultipleSideChats = true;
9655
9658
  details.supportsCredentialSwitching = true;
@@ -11623,7 +11626,8 @@ var CodingAgentManager = class {
11623
11626
  type: "user_message",
11624
11627
  message: request.message,
11625
11628
  ...extraPayload,
11626
- ...request.messageId ? { [USER_MESSAGE_ID_PAYLOAD_KEY]: request.messageId } : {}
11629
+ ...request.messageId ? { [USER_MESSAGE_ID_PAYLOAD_KEY]: request.messageId } : {},
11630
+ ...request.replacesMessageId ? { [REPLACED_MESSAGE_ID_PAYLOAD_KEY]: request.replacesMessageId } : {}
11627
11631
  };
11628
11632
  }
11629
11633
  initializeManager(processMessage) {
@@ -12462,12 +12466,15 @@ var CodexHistoryFile = class {
12462
12466
  * match, so history size does not bound memory.
12463
12467
  */
12464
12468
  async findLastEventOfType(type) {
12469
+ return this.findLastEvent(type, (event) => event.type === type);
12470
+ }
12471
+ async findLastEvent(needle, matches) {
12465
12472
  let found = null;
12466
12473
  try {
12467
12474
  for await (const line of createInterface({ input: createReadStream(this.filePath), crlfDelay: Infinity })) {
12468
- if (!line.includes(type)) continue;
12475
+ if (!line.includes(needle)) continue;
12469
12476
  const event = parseAgentEventJsonlLine(line);
12470
- if (event?.type === type) found = event;
12477
+ if (event && matches(event)) found = event;
12471
12478
  }
12472
12479
  } catch (error) {
12473
12480
  if (!isMissingFile(error)) throw error;
@@ -13393,7 +13400,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
13393
13400
  this.pendingInterrupt = false;
13394
13401
  const userMessage = await this.buildUserMessage(request);
13395
13402
  if (!options.skipUserMessageRecord) {
13396
- await this.recordEvent(userMessage, request.messageId);
13403
+ await this.recordEvent(userMessage, request.messageId, request.replacesMessageId);
13397
13404
  }
13398
13405
  const goalCommand = getGoalCommand(message, request.goalMode);
13399
13406
  const goalObjective = goalCommand?.type === "set" ? goalCommand.objective : goalCommand?.type === "resume" ? this.currentGoal?.objective : void 0;
@@ -13886,14 +13893,15 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
13886
13893
  await this.abortAllPendingToolInputs();
13887
13894
  await this.tearDownSession();
13888
13895
  }
13889
- async forkPoint() {
13896
+ async forkPoint(beforeMessageId) {
13890
13897
  await this.initialized;
13891
13898
  const sessionId = this.sessionId;
13892
13899
  if (!sessionId) return null;
13893
13900
  const messages = await getSessionMessages(sessionId, { dir: this.workingDirectory });
13901
+ const editedPrompt = beforeMessageId && await this.historyFile.findLastEvent(beforeMessageId, (event) => event.type === "claude-user" && event.payload[USER_MESSAGE_ID_PAYLOAD_KEY] === beforeMessageId);
13894
13902
  const turnUuids = this.pendingTurn?.userMessageUuids;
13895
13903
  const turnStart = turnUuids ? messages.findIndex((entry) => turnUuids.has(entry.uuid)) : -1;
13896
- const end = turnStart >= 0 ? turnStart : this.isProcessing() ? Math.max(0, messages.findLastIndex((entry) => entry.type === "user" && isPromptMessage(entry.message))) : messages.length;
13904
+ const end = beforeMessageId ? messages.findIndex((entry) => editedPrompt && entry.uuid === editedPrompt.payload.uuid) : turnStart >= 0 ? turnStart : this.isProcessing() ? Math.max(0, messages.findLastIndex((entry) => entry.type === "user" && isPromptMessage(entry.message))) : messages.length;
13897
13905
  const throughTurn = messages[end - 1]?.uuid;
13898
13906
  return throughTurn ? { sessionId, throughTurn } : null;
13899
13907
  }
@@ -14206,7 +14214,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
14206
14214
  this.recordGoalChange(null);
14207
14215
  }
14208
14216
  }
14209
- async recordEvent(event, replicasMessageId) {
14217
+ async recordEvent(event, replicasMessageId, replacesMessageId) {
14210
14218
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
14211
14219
  const restampAmbient = event.type === "system" && "task_id" in event && this.ambientTaskIds.has(event.task_id);
14212
14220
  const payload = { ...event };
@@ -14217,7 +14225,8 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
14217
14225
  payload: {
14218
14226
  ...payload,
14219
14227
  ...restampAmbient ? { ambient: true } : {},
14220
- ...replicasMessageId ? { [USER_MESSAGE_ID_PAYLOAD_KEY]: replicasMessageId } : {}
14228
+ ...replicasMessageId ? { [USER_MESSAGE_ID_PAYLOAD_KEY]: replicasMessageId } : {},
14229
+ ...replacesMessageId ? { [REPLACED_MESSAGE_ID_PAYLOAD_KEY]: replacesMessageId } : {}
14221
14230
  }
14222
14231
  };
14223
14232
  this.historyFile.append(jsonEvent);
@@ -14293,6 +14302,12 @@ var ChatMessagePersistenceError = class extends Error {
14293
14302
  this.cause = cause;
14294
14303
  }
14295
14304
  };
14305
+ var ChatBusyError = class extends Error {
14306
+ constructor(message) {
14307
+ super(message);
14308
+ this.name = "ChatBusyError";
14309
+ }
14310
+ };
14296
14311
  var ChatProviderUnavailableError = class extends Error {
14297
14312
  constructor(provider) {
14298
14313
  super(`${provider} is not configured in this workspace`);
@@ -14524,7 +14539,7 @@ var CodexAspManager = class extends CodingAgentManager {
14524
14539
  }
14525
14540
  return true;
14526
14541
  }
14527
- async forkPoint() {
14542
+ async forkPoint(beforeMessageId) {
14528
14543
  await this.initialized;
14529
14544
  const sessionId = this.currentThreadId;
14530
14545
  if (!sessionId) return null;
@@ -14532,7 +14547,10 @@ var CodexAspManager = class extends CodingAgentManager {
14532
14547
  THREAD_READ_METHOD,
14533
14548
  { threadId: sessionId, includeTurns: true }
14534
14549
  );
14535
- const throughTurn = thread.turns.findLast((turn) => turn.status !== "inProgress")?.id;
14550
+ const edited = beforeMessageId ? parseAgentEvents(await this.historyFile?.loadAll() ?? [], "codex").findLast(({ id }) => id === beforeMessageId) : void 0;
14551
+ const editedTurnId = edited && codexPromptTurnId(edited);
14552
+ const turns = beforeMessageId ? thread.turns.slice(0, Math.max(0, thread.turns.findIndex((turn) => turn.id === editedTurnId))) : thread.turns;
14553
+ const throughTurn = turns.findLast((turn) => turn.status !== "inProgress")?.id;
14536
14554
  return throughTurn ? { sessionId, throughTurn } : null;
14537
14555
  }
14538
14556
  /** The fork happens on the next turn: Codex keeps a loaded thread's settings, so it must be created with this chat's own. */
@@ -59708,7 +59726,8 @@ function unseenConversationExcerpt(seenHashes, blocks) {
59708
59726
  async function buildForkHandoff(input) {
59709
59727
  const rawHistoryPath = join27(HISTORY_DIR_BY_PROVIDER[input.sourceProvider], `${input.sourceChatId}.jsonl`);
59710
59728
  const { content, truncated: sourceTruncated } = await readHistoryTail(rawHistoryPath, MAX_SANITIZED_SOURCE_BYTES);
59711
- let blocks = canonicalizeChatTranscriptBlocks(content, input.sourceProvider, input.senders);
59729
+ let blocks = canonicalizeChatTranscriptBlocks(content, input.sourceProvider, input.senders, input.beforeMessageId);
59730
+ const fullHistory = input.turnLimit === void 0 && input.beforeMessageId === void 0;
59712
59731
  if (input.turnLimit !== void 0) {
59713
59732
  let turns = 0;
59714
59733
  const start = blocks.findLastIndex((block) => block.startsWith("## User") && ++turns === input.turnLimit);
@@ -59716,8 +59735,8 @@ async function buildForkHandoff(input) {
59716
59735
  }
59717
59736
  const forkDir = join27(FORKS_DIR, input.targetChatId);
59718
59737
  await mkdir16(forkDir, { recursive: true });
59719
- const transcriptPath = join27(forkDir, "source-transcript.md");
59720
- const header = sourceTruncated ? `_This file was generated from only the most recent ${MAX_SANITIZED_SOURCE_BYTES / 1024 / 1024} MB of the source chat.${input.turnLimit === void 0 ? ` The complete raw event log is at ${rawHistoryPath}; grep it for anything earlier.` : ""}_
59738
+ const transcriptPath = join27(forkDir, input.transcriptName ?? "source-transcript.md");
59739
+ const header = sourceTruncated ? `_This file was generated from only the most recent ${MAX_SANITIZED_SOURCE_BYTES / 1024 / 1024} MB of the source chat.${fullHistory ? ` The complete raw event log is at ${rawHistoryPath}; grep it for anything earlier.` : ""}_
59721
59740
 
59722
59741
  ` : "";
59723
59742
  await writeFile8(transcriptPath, `${header}${blocks.join("\n\n")}
@@ -59730,7 +59749,7 @@ async function buildForkHandoff(input) {
59730
59749
  blocks,
59731
59750
  resumeRequest: unansweredRequest(blocks),
59732
59751
  transcriptPath,
59733
- rawHistoryPath: input.turnLimit === void 0 ? rawHistoryPath : void 0
59752
+ rawHistoryPath: fullHistory ? rawHistoryPath : void 0
59734
59753
  };
59735
59754
  }
59736
59755
  async function readPullRequestDecisions(notesPath) {
@@ -59750,7 +59769,8 @@ function createTurnMetadata(message, messageId, recordedAt) {
59750
59769
  message.message,
59751
59770
  messageId,
59752
59771
  recordedAt,
59753
- message.images
59772
+ message.images,
59773
+ message.replacesMessageId
59754
59774
  );
59755
59775
  const sender = message.senderUserId && message.senderEmail ? {
59756
59776
  messageId,
@@ -60131,7 +60151,9 @@ var ChatService = class {
60131
60151
  this.requireChat(chatId);
60132
60152
  seenBeforeSend = this.forkSourceSeenBlocks.get(chatId);
60133
60153
  const fork = chat.persisted.fork;
60134
- if (fork && (chat.persisted.pendingForkHandoff || fork.trigger === "side")) {
60154
+ if (request.replacesMessageId) {
60155
+ request = { ...request, message: await this.rewindBefore(chat, request.replacesMessageId, request.message) };
60156
+ } else if (fork && (chat.persisted.pendingForkHandoff || fork.trigger === "side")) {
60135
60157
  request = {
60136
60158
  ...request,
60137
60159
  message: await this.createForkHandoffMessage(chatId, { source: fork.source, trigger: fork.trigger, message: request.message })
@@ -60643,6 +60665,46 @@ ${note}`;
60643
60665
  const unseen = options.followsSource ? unseenConversationExcerpt(seen, handoff.blocks) : unseenTurnsExcerpt(seen, handoff.blocks);
60644
60666
  return unseen ? formatChatForkUpdateMessage(options.source, options.trigger, unseen, options.message ?? "") : options.message ?? "";
60645
60667
  }
60668
+ async rewindBefore(chat, messageId, message) {
60669
+ if (chat.provider.isProcessing() || chat.provider.getQueue().length > 0 || chat.provider.hasActiveBackgroundTasks?.()) {
60670
+ throw new ChatBusyError("Stop the agent before editing a message.");
60671
+ }
60672
+ const files = "Files and git state may still include changes from turns that came after the original message.";
60673
+ const point = await chat.provider.forkPoint?.(messageId).catch((error) => {
60674
+ console.warn("[ChatService] Could not find the edited message in the agent session; restarting it:", { chatId: chat.persisted.id, error });
60675
+ return null;
60676
+ });
60677
+ if (point && chat.provider.forkFrom) {
60678
+ chat.persisted.pendingProviderFork = point;
60679
+ await this.persistAllChats();
60680
+ await chat.provider.forkFrom(point);
60681
+ return `${message}
60682
+
60683
+ ${wrapInTag(`The user edited one of their earlier messages: the conversation above ends where that message was, and this is its edited version. ${files}`, REPLICAS_INSTRUCTIONS_TAG)}`;
60684
+ }
60685
+ await chat.provider.getHistory({ limit: 1 });
60686
+ const handoff = await buildForkHandoff({
60687
+ sourceChatId: chat.persisted.id,
60688
+ sourceProvider: chat.persisted.provider,
60689
+ targetChatId: chat.persisted.id,
60690
+ senders: await this.readSenders(chat.persisted.id),
60691
+ beforeMessageId: messageId,
60692
+ transcriptName: "transcript-before-edit.md"
60693
+ });
60694
+ await chat.provider.dispose?.();
60695
+ chat.persisted.providerSessionId = null;
60696
+ delete chat.persisted.pendingProviderFork;
60697
+ await this.persistAllChats();
60698
+ chat.provider = this.createRuntimeChat(chat.persisted).provider;
60699
+ const note = handoff.blocks.length === 0 ? `The user edited their first message, so your session restarted and this is its edited version. ${files}` : `The user edited one of their earlier messages, so your session restarted. The conversation before that message is below (also saved at \`${handoff.transcriptPath}\`), and this is its edited version. ${files}
60700
+
60701
+ ${handoff.excerptTruncated ? `${CHAT_FORK_EXCERPT_OMITTED_NOTICE}
60702
+
60703
+ ` : ""}${handoff.excerpt}`;
60704
+ return `${message}
60705
+
60706
+ ${wrapInTag(note, REPLICAS_INSTRUCTIONS_TAG)}`;
60707
+ }
60646
60708
  async forkProviderSession(source, target, point) {
60647
60709
  if (source.persisted.provider !== target.persisted.provider || !source.provider.forkPoint || !target.provider.forkFrom) return false;
60648
60710
  const { forkedThroughTurn, pendingProviderFork } = target.persisted;
@@ -62828,6 +62890,9 @@ function createV1Routes(deps) {
62828
62890
  if (error instanceof ChatMessagePersistenceError) {
62829
62891
  return c.json(jsonError("Failed to save user message", details), 500);
62830
62892
  }
62893
+ if (error instanceof ChatBusyError) {
62894
+ return c.json(jsonError(ENGINE_SEND_MESSAGE_FAILED_ERROR, details), 409);
62895
+ }
62831
62896
  return c.json(jsonError(ENGINE_SEND_MESSAGE_FAILED_ERROR, details), 400);
62832
62897
  }
62833
62898
  });
@@ -3,13 +3,13 @@ import { createRequire as __createRequire } from 'node:module';
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  publishedPullRequestUrls
6
- } from "./chunk-FQZ6YTN2.js";
6
+ } from "./chunk-JF3UUTX5.js";
7
7
  import {
8
8
  isRecord
9
9
  } from "./chunk-UZSNFLDQ.js";
10
10
  import {
11
11
  shouldRefreshPullRequests
12
- } from "./chunk-7QJWP5ZL.js";
12
+ } from "./chunk-MRBFRPXT.js";
13
13
  import "./chunk-VEQXQN22.js";
14
14
 
15
15
  // src/services/post-tool-pr-notifier.ts
@@ -11,7 +11,7 @@ import {
11
11
  spawnSubagentRequestSchema,
12
12
  subagentResponseSchema,
13
13
  waitSubagentRequestSchema
14
- } from "./chunk-7QJWP5ZL.js";
14
+ } from "./chunk-MRBFRPXT.js";
15
15
  import "./chunk-VEQXQN22.js";
16
16
 
17
17
  // src/subagent-mcp.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.1250",
3
+ "version": "0.1.1251",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",