@makerbi/remodex 2.3.2 → 2.5.6

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.
@@ -13,6 +13,10 @@ const {
13
13
  } = require("./rollout-watch");
14
14
  const { resolveCodexGeneratedImagesRoot } = require("./codex-home");
15
15
  const { buildApplyPatchFileChangeItem } = require("./apply-patch-changes");
16
+ const {
17
+ expandExecWrapperToolCall,
18
+ isOrchestrationWaitCall,
19
+ } = require("./codex-tool-wrapper");
16
20
  const {
17
21
  TERMINAL_TASK_EVENT_TYPES,
18
22
  terminalEventClosesTrackedTurn,
@@ -56,6 +60,8 @@ function createRolloutLiveMirrorController({
56
60
  now = () => Date.now(),
57
61
  setIntervalFn = setInterval,
58
62
  clearIntervalFn = clearInterval,
63
+ setImmediateFn = setImmediate,
64
+ clearImmediateFn = clearImmediate,
59
65
  pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,
60
66
  lookupTimeoutMs = DEFAULT_LOOKUP_TIMEOUT_MS,
61
67
  idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS,
@@ -110,6 +116,8 @@ function createRolloutLiveMirrorController({
110
116
  now,
111
117
  setIntervalFn,
112
118
  clearIntervalFn,
119
+ setImmediateFn,
120
+ clearImmediateFn,
113
121
  pollIntervalMs,
114
122
  lookupTimeoutMs,
115
123
  idleTimeoutMs,
@@ -132,9 +140,17 @@ function createRolloutLiveMirrorController({
132
140
  mirrorsByThreadId.clear();
133
141
  }
134
142
 
143
+ // The real turn id this mirror is actively tailing, or null. Lets the bridge
144
+ // answer the phone's turn-state probe from mirror truth when the bounded
145
+ // canonical page reads a busy run as closed.
146
+ function getActiveTurnId(threadId) {
147
+ return mirrorsByThreadId.get(threadId)?.getActiveTurnId() || null;
148
+ }
149
+
135
150
  return {
136
151
  observeInbound,
137
152
  stopAll,
153
+ getActiveTurnId,
138
154
  };
139
155
  }
140
156
 
@@ -149,6 +165,8 @@ function createThreadRolloutLiveMirror({
149
165
  now,
150
166
  setIntervalFn,
151
167
  clearIntervalFn,
168
+ setImmediateFn,
169
+ clearImmediateFn,
152
170
  pollIntervalMs,
153
171
  lookupTimeoutMs,
154
172
  idleTimeoutMs,
@@ -158,6 +176,7 @@ function createThreadRolloutLiveMirror({
158
176
  onStop = () => {},
159
177
  }) {
160
178
  const startedAt = now();
179
+ let lookupStartedAt = startedAt;
161
180
  const state = createMirrorState(threadId);
162
181
 
163
182
  let isStopped = false;
@@ -174,7 +193,10 @@ function createThreadRolloutLiveMirror({
174
193
  let wasSuppressed = false;
175
194
 
176
195
  const intervalId = setIntervalFn(tick, pollIntervalMs);
177
- tick();
196
+ let initialTickId = setImmediateFn(() => {
197
+ initialTickId = null;
198
+ tick();
199
+ });
178
200
 
179
201
  function tick() {
180
202
  if (isStopped) {
@@ -183,9 +205,30 @@ function createThreadRolloutLiveMirror({
183
205
 
184
206
  try {
185
207
  const currentTime = now();
208
+ const suppressedBeforeScan = isSuppressed();
209
+ if (suppressedBeforeScan) {
210
+ if (!wasSuppressed) {
211
+ rolloutPath = null;
212
+ lastSize = 0;
213
+ partialLine = "";
214
+ didBootstrap = false;
215
+ resetRunState(state);
216
+ }
217
+ wasSuppressed = true;
218
+ return;
219
+ }
220
+ if (wasSuppressed) {
221
+ rolloutPath = null;
222
+ lastSize = 0;
223
+ partialLine = "";
224
+ didBootstrap = false;
225
+ resetRunState(state);
226
+ lookupStartedAt = currentTime;
227
+ wasSuppressed = false;
228
+ }
186
229
 
187
230
  if (!rolloutPath) {
188
- if (currentTime - startedAt >= lookupTimeoutMs) {
231
+ if (currentTime - lookupStartedAt >= lookupTimeoutMs) {
189
232
  stop();
190
233
  return;
191
234
  }
@@ -201,20 +244,21 @@ function createThreadRolloutLiveMirror({
201
244
 
202
245
  const rolloutStat = fsModule.statSync(rolloutPath);
203
246
  const fileSize = rolloutStat.size;
204
- // While another live source streams this thread the tail keeps consuming
205
- // rollout lines with its emissions muted. Compare per-thread activity so
206
- // a quiet Desktop turn stays owned, while newer rollout growth can recover
207
- // from a stale connected snapshot.
247
+ // Re-check ownership with the rollout's activity time before bootstrapping.
248
+ // If another source owns the thread, leave the file untouched until that
249
+ // ownership expires.
208
250
  const suppressed = isSuppressed({
209
251
  fallbackActivityAt: Number(rolloutStat.mtimeMs) || 0,
210
252
  });
211
- if (wasSuppressed && !suppressed && didBootstrap) {
253
+ if (suppressed) {
254
+ rolloutPath = null;
212
255
  lastSize = 0;
213
256
  partialLine = "";
214
257
  didBootstrap = false;
215
258
  resetRunState(state);
259
+ wasSuppressed = true;
260
+ return;
216
261
  }
217
- wasSuppressed = suppressed;
218
262
  if (!didBootstrap) {
219
263
  didBootstrap = true;
220
264
  bootstrapFromExistingRollout({
@@ -346,6 +390,10 @@ function createThreadRolloutLiveMirror({
346
390
  // final partial-line flush must never leak the poll interval.
347
391
  isStopped = true;
348
392
  clearIntervalFn(intervalId);
393
+ if (initialTickId != null) {
394
+ clearImmediateFn(initialTickId);
395
+ initialTickId = null;
396
+ }
349
397
  if (partialLine) {
350
398
  const flushLine = partialLine;
351
399
  partialLine = "";
@@ -358,9 +406,30 @@ function createThreadRolloutLiveMirror({
358
406
  onStop();
359
407
  }
360
408
 
409
+ // Only a healthy, actively-tailed run with a real id counts: synthetic ids
410
+ // are not actionable app-server turn ids, and suppressed/awaiting states
411
+ // mean the mirror does not actually know what is running. While another live
412
+ // source owns the thread the mirror has no parsed file state, so reporting a
413
+ // turn id would resurrect exactly the state the bridge muted.
414
+ function getActiveTurnId() {
415
+ if (
416
+ isStopped
417
+ || wasSuppressed
418
+ || state.isDesktopOrigin === false
419
+ || state.awaitingCoherentBoundary
420
+ || state.suppressLiveActivityUntilGrowth
421
+ || state.activeTurnIdIsSynthetic
422
+ || state.pendingSyntheticTerminalTurnId
423
+ ) {
424
+ return null;
425
+ }
426
+ return state.activeTurnId || null;
427
+ }
428
+
361
429
  return {
362
430
  bump,
363
431
  stop,
432
+ getActiveTurnId,
364
433
  };
365
434
  }
366
435
 
@@ -401,12 +470,30 @@ function bootstrapFromExistingRollout({
401
470
  fsModule,
402
471
  });
403
472
  if (!bootstrapWindow) {
404
- // The active run starts outside the bounded bootstrap window. Do not emit
405
- // a plausible-looking tail: canonical history remains the baseline and
406
- // this mirror will still consume future growth normally.
407
473
  state.awaitingCoherentBoundary = true;
408
474
  return;
409
475
  }
476
+ if (!bootstrapWindow.coherent) {
477
+ // The active run starts outside the bounded bootstrap window. Do not emit
478
+ // a plausible-looking tail: canonical history remains the baseline. But do
479
+ // not go dark either — a long busy run would stop mirroring tool activity
480
+ // until its next turn boundary. Attach to the run in place instead, so
481
+ // growth from here on keeps streaming live.
482
+ const attached = attachToActiveRunFromTruncatedTail({
483
+ contents: bootstrapWindow.alignedContents,
484
+ boundary: bootstrapWindow.boundary,
485
+ state,
486
+ rolloutPath,
487
+ fsModule,
488
+ sendApplicationResponse,
489
+ nowMs,
490
+ staleActiveRunMaxAgeMs,
491
+ });
492
+ if (!attached) {
493
+ state.awaitingCoherentBoundary = true;
494
+ }
495
+ return;
496
+ }
410
497
  const { tailStart, contents: bootstrapContents } = bootstrapWindow;
411
498
  let initialContents = bootstrapContents;
412
499
  if (!initialContents) {
@@ -532,7 +619,8 @@ function bootstrapFromExistingRollout({
532
619
  // Expands backwards only until the newest active task has its opening user
533
620
  // message. Every expansion reads just the newly needed prefix, so a 30MB file
534
621
  // is read at most once rather than once per retry. The hard cap keeps bootstrap
535
- // work/memory bounded; no coherent opener means no replay.
622
+ // work/memory bounded; a capped window without a coherent opener comes back
623
+ // with `coherent: false` and must never be replayed as history.
536
624
  function readCoherentBootstrapWindow({ rolloutPath, fileSize, fsModule }) {
537
625
  const maxBytes = Math.min(fileSize, DEFAULT_BOOTSTRAP_MAX_BYTES);
538
626
  let windowBytes = Math.min(fileSize, DEFAULT_BOOTSTRAP_TAIL_BYTES);
@@ -549,10 +637,16 @@ function readCoherentBootstrapWindow({ rolloutPath, fileSize, fsModule }) {
549
637
  // some legitimate system/continuation turns have no materialized user row.
550
638
  // The opener requirement only protects a truncated tail.
551
639
  if (!boundary.hasActiveRun || boundary.hasOpeningUser || tailStart === 0) {
552
- return { tailStart, contents };
640
+ return { tailStart, contents, coherent: true };
553
641
  }
554
642
  if (windowBytes >= maxBytes || tailStart === 0) {
555
- return null;
643
+ return {
644
+ tailStart,
645
+ contents,
646
+ coherent: false,
647
+ alignedContents,
648
+ boundary,
649
+ };
556
650
  }
557
651
 
558
652
  const nextWindowBytes = Math.min(maxBytes, windowBytes * 2);
@@ -584,12 +678,21 @@ function inspectBootstrapRunBoundary(contents) {
584
678
  // closing terminal is evidence of an unknown active boundary, not permission
585
679
  // to replay a partial conversation.
586
680
  let unboundedActivitySinceTerminal = false;
587
-
588
- for (const rawLine of contents.split("\n")) {
589
- const parsed = safeParseJSON(rawLine.trim());
681
+ // Attach metadata for the incoherent-window case, so the caller never has to
682
+ // re-parse the (up to 64MB) window a second time.
683
+ let newestTaskStartedLineIndex = -1;
684
+ let lastEntryTimestamp = "";
685
+
686
+ const lines = contents.split("\n");
687
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
688
+ const parsed = safeParseJSON(lines[lineIndex].trim());
590
689
  if (!parsed) {
591
690
  continue;
592
691
  }
692
+ const entryTimestamp = readString(parsed.timestamp);
693
+ if (entryTimestamp) {
694
+ lastEntryTimestamp = entryTimestamp;
695
+ }
593
696
  const taskEventType = parsed?.type === "event_msg"
594
697
  ? readString(parsed?.payload?.type)
595
698
  : "";
@@ -611,6 +714,7 @@ function inspectBootstrapRunBoundary(contents) {
611
714
  hasOpeningUser = pendingUserBeforeStart;
612
715
  hasTurnOutputSinceStart = false;
613
716
  pendingUserBeforeStart = false;
717
+ newestTaskStartedLineIndex = lineIndex;
614
718
  continue;
615
719
  }
616
720
  if (!activeTurnId) {
@@ -653,6 +757,8 @@ function inspectBootstrapRunBoundary(contents) {
653
757
  return {
654
758
  hasActiveRun: Boolean(activeTurnId) || unboundedActivitySinceTerminal,
655
759
  hasOpeningUser,
760
+ newestTaskStartedLineIndex,
761
+ lastEntryTimestamp,
656
762
  };
657
763
  }
658
764
 
@@ -667,6 +773,58 @@ function isBootstrapNeutralRecord(entry, taskEventType = "") {
667
773
  || taskEventType === "context_updated";
668
774
  }
669
775
 
776
+ // Attaches mid-run when the active run's opener is beyond the bounded window:
777
+ // nothing already in the tail is emitted (it stays canonical-history
778
+ // territory), but run state is hydrated so subsequent growth mirrors live.
779
+ // Returns false when the tail proves the visible runs all closed — trailing
780
+ // bytes then belong to an unknown older boundary and stay suppressed.
781
+ function attachToActiveRunFromTruncatedTail({
782
+ contents,
783
+ boundary,
784
+ state,
785
+ rolloutPath,
786
+ fsModule,
787
+ sendApplicationResponse,
788
+ nowMs,
789
+ staleActiveRunMaxAgeMs,
790
+ }) {
791
+ const newestTaskStartedIndex = boundary?.newestTaskStartedLineIndex ?? -1;
792
+ if (newestTaskStartedIndex >= 0) {
793
+ // Hydrate through the shared reducer so parallel-turn and terminal
794
+ // semantics stay authoritative for what is still open at EOF.
795
+ processRolloutLines(contents.split("\n").slice(newestTaskStartedIndex), state, () => {});
796
+ if (!state.activeTurnId) {
797
+ return false;
798
+ }
799
+ } else {
800
+ // Mid-turn tail without its task_started: adopt a synthetic turn. The
801
+ // first non-terminal event carrying the real id promotes it, and a
802
+ // mismatched terminal closes it via the synthetic-terminal path.
803
+ state.activeTurnId = buildSyntheticTurnId(state, { timestamp: boundary?.lastEntryTimestamp || "" });
804
+ state.activeTurnIdIsSynthetic = true;
805
+ state.reasoningItemId = buildSyntheticItemId("thinking", state.threadId, state.activeTurnId);
806
+ }
807
+
808
+ if (isRolloutFileStale(rolloutPath, fsModule, nowMs, staleActiveRunMaxAgeMs)) {
809
+ // Same contract as the stale coherent bootstrap: stay silent until real
810
+ // growth proves the desktop process is alive again.
811
+ state.suppressLiveActivityUntilGrowth = true;
812
+ return true;
813
+ }
814
+
815
+ // A hydrated run that already carries a pending synthetic terminal is
816
+ // closing, not running: announcing it as live would just be followed by the
817
+ // tick's synthetic turn/completed one grace period later.
818
+ if (!state.pendingSyntheticTerminalTurnId) {
819
+ sendApplicationResponse(JSON.stringify(createNotification("turn/activity", {
820
+ threadId: state.threadId,
821
+ turnId: state.activeTurnId,
822
+ id: state.activeTurnId,
823
+ })));
824
+ }
825
+ return true;
826
+ }
827
+
670
828
  // After a bounded bootstrap cannot reach the old opener, consume only new
671
829
  // bytes. A later real user+task_started boundary safely starts a new live run;
672
830
  // everything before it remains canonical-history territory.
@@ -832,6 +990,7 @@ function synthesizeNotificationsFromRolloutEntry(entry, state, { nowMs = Date.no
832
990
  state.commandCalls.clear();
833
991
  state.applyPatchCalls.clear();
834
992
  state.emittedPatchApplyEndCalls.clear();
993
+ state.wrappedExecCallIdsByOuterId.clear();
835
994
 
836
995
  const startedParams = {
837
996
  threadId: state.threadId,
@@ -963,16 +1122,16 @@ function synthesizeNotificationsFromRolloutEntry(entry, state, { nowMs = Date.no
963
1122
  }
964
1123
 
965
1124
  if (itemType === "functioncall") {
966
- notifications.push(...toolStartNotifications(state, payload));
1125
+ notifications.push(...projectedToolStartNotifications(state, payload));
967
1126
  return notifications;
968
1127
  }
969
1128
 
970
1129
  if (itemType === "customtoolcall") {
971
- notifications.push(...customToolStartNotifications(state, payload));
1130
+ notifications.push(...projectedToolStartNotifications(state, payload));
972
1131
  return notifications;
973
1132
  }
974
1133
 
975
- if (itemType === "functioncalloutput") {
1134
+ if (itemType === "functioncalloutput" || itemType === "customtoolcalloutput") {
976
1135
  notifications.push(...toolOutputNotifications(state, payload));
977
1136
  return notifications;
978
1137
  }
@@ -1208,6 +1367,29 @@ function extractResponseItemMessageText(payload) {
1208
1367
  return responseItemMessageText(payload);
1209
1368
  }
1210
1369
 
1370
+ function projectedToolStartNotifications(state, payload) {
1371
+ if (isOrchestrationWaitCall(payload)) {
1372
+ return [];
1373
+ }
1374
+
1375
+ const projectedPayloads = expandExecWrapperToolCall(payload);
1376
+ const outerCallId = projectedPayloads[0]?.remodexWrappedExecCallId;
1377
+ if (outerCallId && projectedPayloads.length > 1) {
1378
+ state.wrappedExecCallIdsByOuterId.set(
1379
+ outerCallId,
1380
+ projectedPayloads.map((projectedPayload) => (
1381
+ readString(projectedPayload.call_id) || readString(projectedPayload.callId)
1382
+ )).filter(Boolean)
1383
+ );
1384
+ }
1385
+
1386
+ return projectedPayloads.flatMap((projectedPayload) => (
1387
+ normalizeRolloutItemType(projectedPayload.type) === "customtoolcall"
1388
+ ? customToolStartNotifications(state, projectedPayload)
1389
+ : toolStartNotifications(state, projectedPayload)
1390
+ ));
1391
+ }
1392
+
1211
1393
  function toolStartNotifications(state, payload) {
1212
1394
  if (!state.activeTurnId) {
1213
1395
  return [];
@@ -1265,6 +1447,7 @@ function toolStartNotifications(state, payload) {
1265
1447
  toolName,
1266
1448
  command: resolveToolCommand(toolName, argumentsObject),
1267
1449
  cwd: resolveToolWorkingDirectory(argumentsObject, state),
1450
+ wrappedExecCall: Boolean(payload.remodexWrappedExecCallId),
1268
1451
  });
1269
1452
 
1270
1453
  if (isCommandToolName(toolName)) {
@@ -1336,6 +1519,17 @@ function customToolStartNotifications(state, payload) {
1336
1519
  return notifications;
1337
1520
  }
1338
1521
 
1522
+ // Custom tool calls settle through custom_tool_call_output. Without tracking
1523
+ // them the activity row never completes, so it lingers between command groups.
1524
+ if (!isCommandToolName(toolName) && !state.applyPatchCalls.has(callId)) {
1525
+ state.commandCalls.set(callId, {
1526
+ toolName,
1527
+ command: toolName,
1528
+ cwd: readString(state.sessionMeta?.cwd) || "",
1529
+ wrappedExecCall: Boolean(payload.remodexWrappedExecCallId),
1530
+ });
1531
+ }
1532
+
1339
1533
  return [
1340
1534
  ...notifications,
1341
1535
  createNotification("codex/event/background_event", {
@@ -1416,8 +1610,28 @@ function toolOutputNotifications(state, payload) {
1416
1610
  return [];
1417
1611
  }
1418
1612
 
1613
+ const wrappedCallIds = state.wrappedExecCallIdsByOuterId.get(callId);
1614
+ if (Array.isArray(wrappedCallIds) && wrappedCallIds.length > 0) {
1615
+ state.wrappedExecCallIdsByOuterId.delete(callId);
1616
+ const outputRecipientId = wrappedCallIds.find((nestedCallId) => (
1617
+ isCommandToolName(state.commandCalls.get(nestedCallId)?.toolName)
1618
+ )) || wrappedCallIds[0];
1619
+ return wrappedCallIds.flatMap((nestedCallId) => toolOutputNotifications(state, {
1620
+ ...payload,
1621
+ call_id: nestedCallId,
1622
+ callId: nestedCallId,
1623
+ output: nestedCallId === outputRecipientId ? payload.output : "",
1624
+ }));
1625
+ }
1626
+
1419
1627
  const toolCall = state.commandCalls.get(callId);
1420
1628
  if (!toolCall) {
1629
+ if (state.applyPatchCalls.has(callId)) {
1630
+ return patchApplyEndNotifications(state, {
1631
+ ...payload,
1632
+ status: readString(payload.status) || "completed",
1633
+ });
1634
+ }
1421
1635
  return [];
1422
1636
  }
1423
1637
 
@@ -1433,7 +1647,8 @@ function toolOutputNotifications(state, payload) {
1433
1647
  return notifications;
1434
1648
  }
1435
1649
 
1436
- const output = readString(payload.output);
1650
+ const rawOutput = extractToolOutputText(payload.output);
1651
+ const output = toolCall.wrappedExecCall ? stripExecOutputEnvelope(rawOutput) : rawOutput;
1437
1652
  const notifications = [...ensureThinkingNotifications(state)];
1438
1653
  if (output) {
1439
1654
  notifications.push(createNotification("codex/event/exec_command_output_delta", {
@@ -1459,6 +1674,38 @@ function toolOutputNotifications(state, payload) {
1459
1674
  return notifications;
1460
1675
  }
1461
1676
 
1677
+ function extractToolOutputText(value) {
1678
+ if (typeof value === "string") {
1679
+ return value;
1680
+ }
1681
+ if (Array.isArray(value)) {
1682
+ return value.map(extractToolOutputText).join("");
1683
+ }
1684
+ if (!value || typeof value !== "object") {
1685
+ return "";
1686
+ }
1687
+
1688
+ for (const key of ["text", "output_text", "outputText"]) {
1689
+ if (typeof value[key] === "string") {
1690
+ return value[key];
1691
+ }
1692
+ }
1693
+ for (const key of ["content", "output", "result"]) {
1694
+ const text = extractToolOutputText(value[key]);
1695
+ if (text) {
1696
+ return text;
1697
+ }
1698
+ }
1699
+ return "";
1700
+ }
1701
+
1702
+ function stripExecOutputEnvelope(output) {
1703
+ return readString(output).replace(
1704
+ /^Script [^\n]*\nWall time [^\n]*\nOutput:\n?/,
1705
+ ""
1706
+ );
1707
+ }
1708
+
1462
1709
  function imageGenerationNotifications(state, payload, { preferCallId = false } = {}) {
1463
1710
  if (!state.activeTurnId) {
1464
1711
  return [];
@@ -1631,6 +1878,7 @@ function createMirrorState(threadId) {
1631
1878
  commandCalls: new Map(),
1632
1879
  applyPatchCalls: new Map(),
1633
1880
  emittedPatchApplyEndCalls: new Set(),
1881
+ wrappedExecCallIdsByOuterId: new Map(),
1634
1882
  emittedAgentMessageKeys: new Set(),
1635
1883
  agentMessageOccurrencesByBaseKey: new Map(),
1636
1884
  pendingEventAgentMessageOccurrencesByBaseKey: new Map(),
@@ -1796,8 +2044,19 @@ function genericToolActivityMessage(toolName) {
1796
2044
  }
1797
2045
  }
1798
2046
 
2047
+ // Mirrors the wording of genericToolActivityMessage so the completion line
2048
+ // supersedes the start line instead of stacking a second row beside it.
1799
2049
  function genericToolCompletionMessage(toolName) {
1800
- return `Completed ${readString(toolName)}`;
2050
+ switch (readString(toolName).toLowerCase()) {
2051
+ case "apply_patch":
2052
+ return "Applied patch";
2053
+ case "write_stdin":
2054
+ return "Wrote to terminal";
2055
+ case "read_thread_terminal":
2056
+ return "Read terminal output";
2057
+ default:
2058
+ return `Completed ${readString(toolName)}`;
2059
+ }
1801
2060
  }
1802
2061
 
1803
2062
  function createNotification(method, params = {}) {
@@ -1952,6 +2211,7 @@ function resetRunState(state) {
1952
2211
  state.commandCalls.clear();
1953
2212
  state.applyPatchCalls.clear();
1954
2213
  state.emittedPatchApplyEndCalls.clear();
2214
+ state.wrappedExecCallIdsByOuterId.clear();
1955
2215
  state.emittedAgentMessageKeys.clear();
1956
2216
  state.agentMessageOccurrencesByBaseKey.clear();
1957
2217
  state.pendingEventAgentMessageOccurrencesByBaseKey.clear();