@makerbi/remodex 1.5.8 → 2.0.1

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.
@@ -1,5 +1,6 @@
1
1
  // FILE: session-jsonl-history.js
2
- // Purpose: Reconstructs a small thread/turns/list page from local Codex session JSONL files.
2
+ // Purpose: Reconstructs a small thread/turns/list page from local Codex session JSONL files,
3
+ // including desktop-local timestamp metadata for mobile history rendering.
3
4
 
4
5
  const fs = require("fs");
5
6
  const { buildApplyPatchFileChangeItem } = require("./apply-patch-changes");
@@ -83,6 +84,7 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
83
84
  let activeTurnId = "";
84
85
  let sessionThreadId = normalizeString(threadId);
85
86
  let sessionCwd = "";
87
+ let sessionTimeZone = "";
86
88
  const skippedCallIds = new Set();
87
89
  const toolCallsByCallId = new Map();
88
90
  const pendingUserMessages = [];
@@ -115,6 +117,26 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
115
117
  || normalizeString(payload?.thread_id)
116
118
  || normalizeString(payload?.threadId);
117
119
  sessionCwd ||= normalizeString(payload?.cwd);
120
+ sessionTimeZone ||= normalizeString(payload?.timezone)
121
+ || normalizeString(payload?.timeZone)
122
+ || normalizeString(payload?.time_zone);
123
+ continue;
124
+ }
125
+
126
+ if (entry?.type === "turn_context") {
127
+ const payload = objectValue(entry.payload);
128
+ sessionCwd = normalizeString(payload?.cwd) || sessionCwd;
129
+ sessionTimeZone = normalizeString(payload?.timezone)
130
+ || normalizeString(payload?.timeZone)
131
+ || normalizeString(payload?.time_zone)
132
+ || sessionTimeZone;
133
+ activeTurnId = normalizeString(payload?.turn_id)
134
+ || normalizeString(payload?.turnId)
135
+ || activeTurnId;
136
+ if (activeTurnId) {
137
+ const turn = ensureTurn(turns, turnsById, activeTurnId, sessionThreadId, entry.timestamp);
138
+ applyHistoryTimeZone(turn, sessionTimeZone);
139
+ }
118
140
  continue;
119
141
  }
120
142
 
@@ -127,6 +149,7 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
127
149
  || activeTurnId
128
150
  || `turn-line-${index + 1}`;
129
151
  const turn = ensureTurn(turns, turnsById, activeTurnId, sessionThreadId, entry.timestamp);
152
+ applyHistoryTimeZone(turn, sessionTimeZone);
130
153
  flushPendingUserMessagesToTurn(turn, pendingUserMessages);
131
154
  continue;
132
155
  }
@@ -139,6 +162,7 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
139
162
  sessionThreadId,
140
163
  entry.timestamp
141
164
  );
165
+ applyHistoryTimeZone(turn, sessionTimeZone);
142
166
  turn.status = "completed";
143
167
  activeTurnId = "";
144
168
  continue;
@@ -162,6 +186,7 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
162
186
  toolCallsByCallId,
163
187
  });
164
188
  if (item) {
189
+ applyHistoryTimeZone(item, sessionTimeZone);
165
190
  turn.items.push(item);
166
191
  }
167
192
  continue;
@@ -170,6 +195,7 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
170
195
  if (eventType === "user_message") {
171
196
  const explicitTurnId = normalizeString(payload?.turn_id) || normalizeString(payload?.turnId);
172
197
  const item = createUserMessageHistoryItem(payload, index + 1, entry.timestamp);
198
+ applyHistoryTimeZone(item, sessionTimeZone);
173
199
  if (!explicitTurnId && !activeTurnId) {
174
200
  pushPendingUserMessage(pendingUserMessages, item);
175
201
  continue;
@@ -182,6 +208,7 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
182
208
  sessionThreadId,
183
209
  entry.timestamp
184
210
  );
211
+ applyHistoryTimeZone(turn, sessionTimeZone);
185
212
  addHistoryItemToTurn(turn, item);
186
213
  continue;
187
214
  }
@@ -207,6 +234,7 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
207
234
  sessionThreadId,
208
235
  entry.timestamp
209
236
  );
237
+ applyHistoryTimeZone(turn, sessionTimeZone);
210
238
  const item = normalizeResponseItemForHistory(payload, index + 1, {
211
239
  cwd: sessionCwd,
212
240
  toolCallsByCallId,
@@ -222,6 +250,7 @@ function parseSessionJsonlTurns(content, { threadId = "" } = {}) {
222
250
  if (itemTimestamp && !item.timestamp) {
223
251
  item.timestamp = itemTimestamp;
224
252
  }
253
+ applyHistoryTimeZone(item, sessionTimeZone);
225
254
  addHistoryItemToTurn(turn, item);
226
255
  }
227
256
  }
@@ -336,6 +365,12 @@ function historyItemTimestamp(item, fallbackTimestamp = "") {
336
365
  return firstNonEmptyString([
337
366
  normalizeString(item?.createdAt),
338
367
  normalizeString(item?.created_at),
368
+ normalizeString(item?.startedAt),
369
+ normalizeString(item?.started_at),
370
+ normalizeString(item?.completedAt),
371
+ normalizeString(item?.completed_at),
372
+ normalizeString(item?.endedAt),
373
+ normalizeString(item?.ended_at),
339
374
  normalizeString(item?.timestamp),
340
375
  normalizeString(item?.time),
341
376
  normalizeString(fallbackTimestamp),
@@ -379,6 +414,7 @@ function flushPendingUserMessagesToTurn(turn, pendingUserMessages) {
379
414
  }
380
415
 
381
416
  for (const item of pendingUserMessages.splice(0)) {
417
+ applyHistoryTimeZone(item, normalizeString(turn.timeZone) || normalizeString(turn.timezone));
382
418
  addHistoryItemToTurn(turn, item);
383
419
  }
384
420
  }
@@ -403,6 +439,23 @@ function ensureTurn(turns, turnsById, turnId, threadId, timestamp) {
403
439
  return turn;
404
440
  }
405
441
 
442
+ function applyHistoryTimeZone(target, timeZone) {
443
+ const normalizedTimeZone = normalizeString(timeZone);
444
+ if (!target || !normalizedTimeZone) {
445
+ return target;
446
+ }
447
+ if (!target.timeZoneIdentifier) {
448
+ target.timeZoneIdentifier = normalizedTimeZone;
449
+ }
450
+ if (!target.timeZone) {
451
+ target.timeZone = normalizedTimeZone;
452
+ }
453
+ if (!target.timezone) {
454
+ target.timezone = normalizedTimeZone;
455
+ }
456
+ return target;
457
+ }
458
+
406
459
  function normalizeResponseItemForHistory(payload, lineNumber, { cwd = "", toolCallsByCallId = new Map() } = {}) {
407
460
  const type = normalizeHistoryItemType(payload.type);
408
461
  if (!type) {
@@ -8,7 +8,8 @@ const OPENAI_TRANSCRIPTIONS_URL = "https://api.openai.com/v1/audio/transcription
8
8
  const CHATGPT_TRANSCRIPTIONS_URL = "https://chatgpt.com/backend-api/transcribe";
9
9
  const DEFAULT_TRANSCRIPTION_MODEL = "gpt-4o-mini-transcribe";
10
10
  const MAX_AUDIO_BYTES = 10 * 1024 * 1024;
11
- const MAX_DURATION_MS = 120_000;
11
+ const MAX_DURATION_SECONDS = 150;
12
+ const MAX_DURATION_MS = MAX_DURATION_SECONDS * 1_000;
12
13
 
13
14
  function createVoiceHandler({
14
15
  sendCodexRequest,
@@ -95,7 +96,7 @@ async function transcribeVoice(
95
96
  throw voiceError("invalid_duration", "Voice messages must include a positive duration.");
96
97
  }
97
98
  if (durationMs > MAX_DURATION_MS) {
98
- throw voiceError("duration_too_long", "Voice messages are limited to 120 seconds.");
99
+ throw voiceError("duration_too_long", `Voice messages are limited to ${MAX_DURATION_SECONDS} seconds.`);
99
100
  }
100
101
 
101
102
  const audioBuffer = decodeAudioBase64(params.audioBase64);
@@ -283,7 +284,36 @@ function normalizeBase64(value) {
283
284
  }
284
285
 
285
286
  function isLikelyBase64(value) {
286
- return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
287
+ if (typeof value !== "string" || value.length === 0 || value.length % 4 !== 0) {
288
+ return false;
289
+ }
290
+
291
+ const paddingStart = value.indexOf("=");
292
+ if (paddingStart !== -1) {
293
+ const paddingLength = value.length - paddingStart;
294
+ if (paddingLength > 2) {
295
+ return false;
296
+ }
297
+ for (let i = paddingStart; i < value.length; i += 1) {
298
+ if (value[i] !== "=") {
299
+ return false;
300
+ }
301
+ }
302
+ }
303
+
304
+ // Avoid one giant regex: V8 can overflow its stack on multi-MB voice clips.
305
+ const dataEnd = paddingStart === -1 ? value.length : paddingStart;
306
+ for (let i = 0; i < dataEnd; i += 1) {
307
+ const code = value.charCodeAt(i);
308
+ const isUppercase = code >= 65 && code <= 90;
309
+ const isLowercase = code >= 97 && code <= 122;
310
+ const isDigit = code >= 48 && code <= 57;
311
+ if (!isUppercase && !isLowercase && !isDigit && value[i] !== "+" && value[i] !== "/") {
312
+ return false;
313
+ }
314
+ }
315
+
316
+ return true;
287
317
  }
288
318
 
289
319
  function hasRiffWaveHeader(buffer) {