codex-overleaf-link 2.5.0 → 2.6.0

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 (189) hide show
  1. package/README.md +155 -392
  2. package/README.zh-CN.md +154 -393
  3. package/extension/bootstrap/background.js +52 -9
  4. package/extension/bootstrap/manifest.template.json +1 -1
  5. package/extension/bootstrap/popup.html +1 -0
  6. package/extension/bootstrap/popupFallback.js +55 -0
  7. package/extension/bootstrap/updateStatus.js +1 -0
  8. package/extension/src/background.js +283 -55
  9. package/extension/src/backgroundBootstrapMigration.js +181 -0
  10. package/extension/src/backgroundSharedSessions.js +129 -16
  11. package/extension/src/backgroundUpdateCoordinator.js +242 -29
  12. package/extension/src/backgroundUpdateSafety.js +173 -0
  13. package/extension/src/content/activeTurnControl.js +171 -8
  14. package/extension/src/content/applyResultFormatters.js +46 -73
  15. package/extension/src/content/assetTransferBroker.js +72 -14
  16. package/extension/src/content/composerAttachments.js +104 -47
  17. package/extension/src/content/composerPanel.js +110 -12
  18. package/extension/src/content/contentRuntime.js +1555 -926
  19. package/extension/src/content/contextTray.js +8 -2
  20. package/extension/src/content/contextUsageView.js +267 -0
  21. package/extension/src/content/diagnosticsController.js +122 -96
  22. package/extension/src/content/diagnosticsExport.js +19 -5
  23. package/extension/src/content/diagnosticsPanel.js +48 -0
  24. package/extension/src/content/directoryCleanupRecovery.js +54 -0
  25. package/extension/src/content/generated/content.bundle.js +11077 -3412
  26. package/extension/src/content/generated/content.bundle.meta.json +14 -3
  27. package/extension/src/content/globalPreferencesController.js +1 -1
  28. package/extension/src/content/legacyGlobalRegistry.js +10 -0
  29. package/extension/src/content/localSkillsPanel.js +104 -14
  30. package/extension/src/content/markdownDomRenderer.js +5 -3
  31. package/extension/src/content/markdownText.js +47 -11
  32. package/extension/src/content/modelPicker.js +8 -4
  33. package/extension/src/content/nativeCompatibilityController.js +74 -30
  34. package/extension/src/content/otWarmMirror.js +5 -6
  35. package/extension/src/content/otWarmMirrorController.js +17 -20
  36. package/extension/src/content/pageBridgeClient.js +17 -4
  37. package/extension/src/content/panelMaintenance.js +46 -14
  38. package/extension/src/content/panelRenderer.js +57 -27
  39. package/extension/src/content/pendingInputView.js +1 -1
  40. package/extension/src/content/projectProviderSelection.js +13 -4
  41. package/extension/src/content/projectSessionCleanup.js +109 -62
  42. package/extension/src/content/projectSettingsCoordinator.js +67 -6
  43. package/extension/src/content/providerSettingsCoordinator.js +46 -8
  44. package/extension/src/content/providerSettingsDialog.js +73 -14
  45. package/extension/src/content/recentProjects.js +15 -8
  46. package/extension/src/content/runActivitySummary.js +160 -18
  47. package/extension/src/content/runCompletionMeta.js +532 -0
  48. package/extension/src/content/runController.js +39 -15
  49. package/extension/src/content/runFailureNotice.js +29 -13
  50. package/extension/src/content/runGuidanceController.js +72 -27
  51. package/extension/src/content/runGuidanceView.js +59 -10
  52. package/extension/src/content/runPresence.js +18 -8
  53. package/extension/src/content/runQueueScheduler.js +157 -47
  54. package/extension/src/content/runRecoveryActions.js +147 -0
  55. package/extension/src/content/runResultActions.js +28 -143
  56. package/extension/src/content/runReviewController.js +633 -0
  57. package/extension/src/content/runScrollLayout.js +21 -2
  58. package/extension/src/content/runTimelineView.js +367 -175
  59. package/extension/src/content/scopedPersistencePanelState.js +134 -20
  60. package/extension/src/content/selectionContextView.js +1 -1
  61. package/extension/src/content/sensitivePreflight.js +153 -0
  62. package/extension/src/content/sessionForkController.js +80 -17
  63. package/extension/src/content/sessionManager.js +50 -4
  64. package/extension/src/content/sessionMenuView.js +54 -18
  65. package/extension/src/content/sessionPersistence.js +25 -5
  66. package/extension/src/content/settingsPanel.js +22 -5
  67. package/extension/src/content/settingsWorkbench.js +132 -89
  68. package/extension/src/content/sharedSessionViewSync.js +49 -11
  69. package/extension/src/content/subagentActivityView.js +23 -7
  70. package/extension/src/content/updateIdle.js +4 -1
  71. package/extension/src/content/updateNotice.js +118 -12
  72. package/extension/src/content/updateSafetyReceiver.js +58 -0
  73. package/extension/src/content/writebackController.js +53 -4
  74. package/extension/src/content/writebackOrchestrator.js +116 -94
  75. package/extension/src/content/writingStyleSettings.js +35 -11
  76. package/extension/src/page/binaryAssetUploader.js +136 -14
  77. package/extension/src/page/compileBridge.js +193 -180
  78. package/extension/src/page/fileMover.js +256 -0
  79. package/extension/src/page/overleafCapabilities.js +4 -1
  80. package/extension/src/page/ownedDirectoryCleanup.js +94 -0
  81. package/extension/src/page/referenceProjects.js +1 -0
  82. package/extension/src/page/reviewContext.js +113 -0
  83. package/extension/src/page/saveState.js +6 -4
  84. package/extension/src/page/snapshotRouter.js +84 -39
  85. package/extension/src/page/textCoordinates.js +17 -1
  86. package/extension/src/page/textFileCreator.js +114 -26
  87. package/extension/src/page/trackedChangeCapture.js +12 -2
  88. package/extension/src/page/trackedChangeOwnership.js +19 -1
  89. package/extension/src/page/trackedChangeReplay.js +41 -21
  90. package/extension/src/page/trackedChangesLifecycle.js +217 -199
  91. package/extension/src/page/treeOperations.js +7 -10
  92. package/extension/src/page/updateSafetyProbe.js +41 -0
  93. package/extension/src/page/writebackReceiptJournal.js +2 -0
  94. package/extension/src/page/writebackRouter.js +103 -155
  95. package/extension/src/pageBridge.js +126 -69
  96. package/extension/src/popup.js +62 -10
  97. package/extension/src/shared/agentTranscript.js +373 -17
  98. package/extension/src/shared/auditRecords.js +4 -0
  99. package/extension/src/shared/compatibility.js +22 -6
  100. package/extension/src/shared/compileAdapter.js +129 -66
  101. package/extension/src/shared/composerAttachmentDraft.js +156 -0
  102. package/extension/src/shared/contextUsage.js +125 -0
  103. package/extension/src/shared/directoryCleanupProof.js +43 -0
  104. package/extension/src/shared/failureReasons.js +349 -4
  105. package/extension/src/shared/globalPreferences.js +30 -13
  106. package/extension/src/shared/governanceRules.js +4 -37
  107. package/extension/src/shared/i18n.js +590 -24
  108. package/extension/src/shared/lineReferences.js +38 -31
  109. package/extension/src/shared/managedUpdateProjection.js +2 -2
  110. package/extension/src/shared/nativeRequestIdentity.js +1 -0
  111. package/extension/src/shared/pageRpcContract.js +5 -4
  112. package/extension/src/shared/panelIcons.js +39 -0
  113. package/extension/src/shared/projectFiles.js +21 -44
  114. package/extension/src/shared/providerProfiles.js +5 -3
  115. package/extension/src/shared/reviewing.js +130 -1
  116. package/extension/src/shared/runActivityModel.js +70 -4
  117. package/extension/src/shared/runExecutionSnapshot.js +13 -0
  118. package/extension/src/shared/runInputQueue.js +48 -5
  119. package/extension/src/shared/selectionContext.js +12 -3
  120. package/extension/src/shared/sessionState.js +132 -28
  121. package/extension/src/shared/sessionTitle.js +14 -1
  122. package/extension/src/shared/settlementFacts.js +10 -2
  123. package/extension/src/shared/sharedSessionBridge.js +118 -27
  124. package/extension/src/shared/sharedSessionTransfer.js +140 -0
  125. package/extension/src/shared/staleGuard.js +166 -52
  126. package/extension/src/shared/storageDb.js +90 -26
  127. package/extension/src/shared/storageMigration.js +78 -112
  128. package/extension/src/shared/storageRunActions.js +267 -30
  129. package/extension/src/shared/subagentActivityModel.js +1 -1
  130. package/extension/src/shared/undoOperations.js +253 -32
  131. package/extension/src/shared/updateConsent.js +6 -4
  132. package/extension/src/shared/updateRuntimeIdentity.js +17 -3
  133. package/extension/src/shared/writebackIntent.js +16 -0
  134. package/extension/src/shared/writebackOperationEvidence.js +4 -15
  135. package/extension/src/shared/writebackSettlement.js +58 -40
  136. package/extension/styles/panel.css +1123 -493
  137. package/native-host/src/anthropicBridgeRequest.js +4 -2
  138. package/native-host/src/anthropicBridgeResponse.js +6 -2
  139. package/native-host/src/anthropicMessagesBridge.js +24 -16
  140. package/native-host/src/bootstrapMigration.js +296 -0
  141. package/native-host/src/bootstrapMigrationContract.js +101 -0
  142. package/native-host/src/bootstrapUpdate.js +269 -0
  143. package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
  144. package/native-host/src/chatBridgeRequest.js +60 -6
  145. package/native-host/src/chatBridgeResponse.js +20 -1
  146. package/native-host/src/chatCompletionsBridge.js +48 -15
  147. package/native-host/src/codexConfigPaths.js +106 -0
  148. package/native-host/src/codexHome.js +66 -73
  149. package/native-host/src/codexHomeScope.js +124 -0
  150. package/native-host/src/codexInheritedAuth.js +90 -0
  151. package/native-host/src/codexLocalSkills.js +301 -0
  152. package/native-host/src/codexPromptAssembly.js +114 -127
  153. package/native-host/src/codexProviderTest.js +24 -26
  154. package/native-host/src/codexSessionRunner.js +234 -198
  155. package/native-host/src/codexSessionTiming.js +18 -8
  156. package/native-host/src/codexSkillIsolation.js +170 -0
  157. package/native-host/src/codexThreadFork.js +19 -3
  158. package/native-host/src/index.js +19 -7
  159. package/native-host/src/managedInstall.js +110 -35
  160. package/native-host/src/managedInstallRecovery.js +140 -0
  161. package/native-host/src/managedRuntimeEvidence.js +57 -0
  162. package/native-host/src/mirrorWorkspace.js +92 -22
  163. package/native-host/src/nativeDoctor.js +15 -0
  164. package/native-host/src/nativeHelperLifecycle.js +21 -0
  165. package/native-host/src/nativeHostRegistration.js +33 -0
  166. package/native-host/src/nativeRunLifecycle.js +71 -0
  167. package/native-host/src/processStopBarrier.js +42 -7
  168. package/native-host/src/projectPathPlatform.js +30 -0
  169. package/native-host/src/providerContextError.js +20 -0
  170. package/native-host/src/providerHttp.js +80 -0
  171. package/native-host/src/providerProfile.js +4 -2
  172. package/native-host/src/providerReasoning.js +2 -7
  173. package/native-host/src/providerRuntime.js +1 -0
  174. package/native-host/src/providerStore.js +72 -14
  175. package/native-host/src/responsesPassthroughBridge.js +266 -52
  176. package/native-host/src/runtimeInstaller.js +21 -1
  177. package/native-host/src/selectionScope.js +36 -8
  178. package/native-host/src/subagentAdmission.js +26 -0
  179. package/native-host/src/subagentBroker.js +79 -66
  180. package/native-host/src/subagentTelemetry.js +19 -10
  181. package/native-host/src/subagentWorkspacePath.js +5 -2
  182. package/native-host/src/taskRunnerRuntime.js +92 -57
  183. package/native-host/src/textPatch.js +473 -377
  184. package/native-host/src/tomlStatements.js +140 -0
  185. package/native-host/src/updateManager.js +409 -46
  186. package/native-host/src/writingStyleRuntime.js +57 -29
  187. package/native-host/src/writingStyleStore.js +73 -0
  188. package/package.json +5 -8
  189. package/scripts/install-managed.mjs +1 -0
@@ -1,7 +1,7 @@
1
1
  (function initStorageDb(root, factory) {
2
2
  if (typeof module === 'object' && module.exports) {
3
3
  module.exports = factory(require('./storageRunActions'), require('./runInputQueue'),
4
- require('./settlementFacts'), require('./storageSessionClaims'), require('./sessionState'), require('./runActivityModel'), require('./sharedSessionBridge'), require('./subagentActivityModel'), require('./storageValuePruning'));
4
+ require('./settlementFacts'), require('./storageSessionClaims'), require('./sessionState'), require('./runActivityModel'), require('./sharedSessionBridge'), require('./subagentActivityModel'), require('./storageValuePruning'), require('./composerAttachmentDraft'), require('./sharedSessionTransfer'), require('./contextUsage'));
5
5
  } else {
6
6
  root.CodexOverleafModuleRegistry.define('StorageDb', [
7
7
  'StorageRunActions',
@@ -12,10 +12,13 @@
12
12
  'RunActivityModel',
13
13
  'SharedSessionBridge',
14
14
  'SubagentActivityModel',
15
- 'StorageValuePruning'
15
+ 'StorageValuePruning',
16
+ 'ComposerAttachmentDraft',
17
+ 'SharedSessionTransfer',
18
+ 'ContextUsage'
16
19
  ], factory);
17
20
  }
18
- })(typeof globalThis !== 'undefined' ? globalThis : window, function storageDbFactory(StorageRunActions, RunInputQueue, SettlementFacts, StorageSessionClaims, SessionState, RunActivityModel, SharedSessionBridge, SubagentActivityModel, StorageValuePruning) {
21
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function storageDbFactory(StorageRunActions, RunInputQueue, SettlementFacts, StorageSessionClaims, SessionState, RunActivityModel, SharedSessionBridge, SubagentActivityModel, StorageValuePruning, ComposerAttachmentDraft, SharedSessionTransfer, ContextUsage) {
19
22
  'use strict';
20
23
  const { removeEmptySummaryFields, removeEmptyFields } = StorageValuePruning;
21
24
  if (!StorageRunActions?.compactRunsForStorage || !StorageRunActions?.compactRunActionPayload || !StorageRunActions?.compactProviderSnapshot || !StorageRunActions?.compactRunExecutionSnapshot || !StorageRunActions?.compactStructuredEventValue || !StorageRunActions?.hashString || !RunInputQueue?.compactForStorage || !SettlementFacts?.compactSettlementFacts || !StorageSessionClaims?.createSessionClaimer) {
@@ -140,6 +143,7 @@
140
143
  });
141
144
  }
142
145
  var claimSessionsForAccount = StorageSessionClaims.createSessionClaimer(openDb, function () { return IDBKeyRange; });
146
+ var composerDraftStore = ComposerAttachmentDraft.createStore(openDb);
143
147
 
144
148
  function putRecord(storeName, record) {
145
149
  return openDb().then(function (db) {
@@ -237,17 +241,7 @@
237
241
  }
238
242
 
239
243
  function clearAllStores() {
240
- return openDb().then(function (db) {
241
- var storeNames = Object.keys(STORES);
242
- return new Promise(function (resolve, reject) {
243
- var tx = db.transaction(storeNames, 'readwrite');
244
- for (var i = 0; i < storeNames.length; i++) {
245
- tx.objectStore(storeNames[i]).clear();
246
- }
247
- tx.oncomplete = function () { resolve(); };
248
- tx.onerror = function (event) { reject(event.target.error); };
249
- });
250
- });
244
+ return composerDraftStore.clear(Object.keys(STORES));
251
245
  }
252
246
 
253
247
  // --- Record builders ---
@@ -277,12 +271,15 @@
277
271
  var lastActivityAt = typeof input.lastActivityAt === 'string' && input.lastActivityAt
278
272
  ? input.lastActivityAt
279
273
  : updatedAt;
280
- return {
274
+ var record = {
281
275
  id: input.id || generateId('ses'),
282
276
  projectId: input.projectId || '',
283
277
  title: normalizeSessionTitleForStorage(input.title, titleSource),
284
278
  titleSource: titleSource,
285
279
  codexThreadId: typeof input.codexThreadId === 'string' ? input.codexThreadId : '',
280
+ contextUsage: ContextUsage.normalize(input.contextUsage),
281
+ forkedFromSessionId: normalizeTextField(input.forkedFromSessionId, 160),
282
+ forkedFromRunId: normalizeTextField(input.forkedFromRunId, 160),
286
283
  status: typeof input.status === 'string' && input.status ? input.status : 'active',
287
284
  focusFiles: normalizePathList(input.focusFiles),
288
285
  selectionContext: SessionState.normalizeSelectionContext(input.selectionContext),
@@ -293,7 +290,8 @@
293
290
  normalizePaths: normalizePathList
294
291
  }),
295
292
  history: compactHistoryForStorage(input.history),
296
- runs: compactRunsForStorage(input.runs, options),
293
+ runs: compactRunsForStorage(input.runs, { preserveRunActionPayload: false,
294
+ deferDirectoryCleanup: options.preserveRunActionPayload === true || options.deferDirectoryCleanup === true }),
297
295
  task: normalizeDisplayTextForStorage(input.task, SESSION_STORAGE_LIMITS.taskChars),
298
296
  mode: normalizeCurrentMode(input.mode), providerId: typeof input.providerId === 'string' && input.providerId ? input.providerId : 'builtin',
299
297
  model: typeof input.model === 'string' ? input.model : '',
@@ -307,6 +305,34 @@
307
305
  accountScopeUnavailable: accountScopeUnavailable,
308
306
  safeTaskSummary: safeTaskSummary
309
307
  };
308
+ // Optional provenance for the automatic clear of one captured submission.
309
+ // It is envelope metadata, not run/review authority; no schema migration is needed.
310
+ if (record.task === '' && typeof input.draftConsumption?.task === 'string'
311
+ && input.draftConsumption.task && typeof input.draftConsumption.runId === 'string'
312
+ && input.draftConsumption.runId && record.runs.some(run => run.id === input.draftConsumption.runId
313
+ && !run.forkSnapshot && run.runProjectId === record.projectId)) {
314
+ record.draftConsumption = {
315
+ runId: input.draftConsumption.runId,
316
+ task: normalizeDisplayTextForStorage(input.draftConsumption.task, SESSION_STORAGE_LIMITS.taskChars)
317
+ };
318
+ }
319
+ if (options.preserveRunActionPayload === true) {
320
+ // Count the real display record before allocating recovery space. Adding
321
+ // older checkpoints must not make an otherwise valid history unwritable.
322
+ var metadataText = JSON.stringify(record), metadataBytes = SharedSessionTransfer.byteLength(metadataText);
323
+ record.runs = compactRunsForStorage(input.runs, { ...options,
324
+ canRetainActionPayload: function (bytes, chars) {
325
+ var totalBytes = metadataBytes + bytes + 4096, totalChars = metadataText.length + chars + 4096;
326
+ return totalBytes <= SharedSessionTransfer.MAX_WIRE_BYTES
327
+ || (totalBytes <= SharedSessionTransfer.MAX_RECORD_BYTES && totalChars * 2 <= SharedSessionTransfer.MAX_WIRE_BYTES);
328
+ } });
329
+ }
330
+ for (var run of record.runs) SessionState.pruneRunRecoveryScope(run, record);
331
+ return record;
332
+ }
333
+
334
+ function compactSessionBatchActions(records, options) {
335
+ return StorageRunActions.compactSessionBatchActions(records, options, buildSessionRecord, SharedSessionTransfer);
310
336
  }
311
337
 
312
338
  function resolveAccountScopeId(input) {
@@ -417,11 +443,14 @@
417
443
  var now = new Date().toISOString();
418
444
  return {
419
445
  id: input.id || generateId('aud'),
446
+ accountScopeId: typeof input.accountScopeId === 'string' ? input.accountScopeId : '',
420
447
  projectId: typeof input.projectId === 'string' ? input.projectId : '',
421
448
  sessionId: typeof input.sessionId === 'string' ? input.sessionId : '',
422
449
  turnId: typeof input.turnId === 'string' ? input.turnId : '',
423
450
  createdAt: typeof input.createdAt === 'string' ? input.createdAt : now,
424
451
  completedAt: typeof input.completedAt === 'string' ? input.completedAt : '',
452
+ requireReviewing: typeof input.requireReviewing === 'boolean' ? input.requireReviewing : undefined,
453
+ trackingDecision: ['continue', 'disable'].includes(input.trackingDecision) ? input.trackingDecision : '',
425
454
  mode: typeof input.mode === 'string' ? input.mode : '', ...StorageRunActions.compactProviderSnapshot(input),
426
455
  model: typeof input.model === 'string' ? input.model : '',
427
456
  reasoningEffort: typeof input.reasoningEffort === 'string' ? input.reasoningEffort : '',
@@ -466,7 +495,8 @@
466
495
  customInstructionsByProject: normalizeStringMap(state.customInstructionsByProject),
467
496
  governanceRulesByProject: normalizeGovernanceRulesMap(state.governanceRulesByProject),
468
497
  selectedLocalSkillIdsByProject: normalizeStringListMap(state.selectedLocalSkillIdsByProject),
469
- codexOverleafSkillEnabled: normalizeCodexOverleafSkillEnabledMap(state.codexOverleafSkillEnabled)
498
+ codexOverleafSkillEnabled: normalizeCodexOverleafSkillEnabledMap(state.codexOverleafSkillEnabled),
499
+ codexLocalSkillEnabled: SessionState.normalizeCodexLocalSkillEnabled(state.codexLocalSkillEnabled)
470
500
  };
471
501
  return prefs;
472
502
  }
@@ -519,7 +549,7 @@
519
549
  continue;
520
550
  }
521
551
  result[key] = typeof value[rawKey] === 'string'
522
- ? normalizeTextField(value[rawKey], CUSTOM_INSTRUCTIONS_MAX_CHARS)
552
+ ? normalizeDisplayTextForStorage(value[rawKey], CUSTOM_INSTRUCTIONS_MAX_CHARS)
523
553
  : '';
524
554
  }
525
555
  return result;
@@ -640,9 +670,9 @@
640
670
  function normalizeSessionTitleForStorage(value, titleSource) {
641
671
  var title = typeof value === 'string' ? value.trim() : '';
642
672
  if (titleSource === 'manual') {
643
- return normalizeTextField(title === LEGACY_DEFAULT_SESSION_TITLE ? '' : title, SESSION_STORAGE_LIMITS.sessionTitleChars);
673
+ return normalizeDisplayTextForStorage(title === LEGACY_DEFAULT_SESSION_TITLE ? '' : title, SESSION_STORAGE_LIMITS.sessionTitleChars);
644
674
  }
645
- return normalizeTextField(title === LEGACY_DEFAULT_SESSION_TITLE ? '' : title, SESSION_STORAGE_LIMITS.sessionTitleChars);
675
+ return normalizeDisplayTextForStorage(title === LEGACY_DEFAULT_SESSION_TITLE ? '' : title, SESSION_STORAGE_LIMITS.sessionTitleChars);
646
676
  }
647
677
 
648
678
  function compactHistoryForStorage(history) {
@@ -660,12 +690,14 @@
660
690
  function compactRunsForStorage(runs, options) {
661
691
  return StorageRunActions.compactRunsForStorage(runs, options, SESSION_STORAGE_LIMITS.maxRunsPerSession, compactRunForStorage);
662
692
  }
663
- function compactRunForStorage(run, keepActionPayload) {
693
+ function compactRunForStorage(run, keepActionPayload, preparedActionPayload) {
664
694
  run = SessionState.recoverRecordedRunFailure(run);
665
- var actionPayload = StorageRunActions.compactRunActionPayload(run, keepActionPayload);
695
+ var actionPayload = preparedActionPayload || StorageRunActions.compactRunActionPayload(run, keepActionPayload);
666
696
  var compact = {
667
697
  ...SessionState.pickWritebackRecovery(run),
668
698
  id: run.id,
699
+ forkSnapshot: run.forkSnapshot === true,
700
+ forkSourceRunId: normalizeTextField(run.forkSourceRunId, 160),
669
701
  task: normalizeDisplayTextForStorage(run.task || 'untitled task', SESSION_STORAGE_LIMITS.taskChars),
670
702
  mode: typeof run.mode === 'string' ? redactSecretLikeText(run.mode) : '', ...StorageRunActions.compactProviderSnapshot(run),
671
703
  ...StorageRunActions.compactRunExecutionSnapshot(run, function (text) { return normalizeTextField(text, 4096); }),
@@ -686,9 +718,14 @@
686
718
  undoTrackedChanges: actionPayload.undoTrackedChanges,
687
719
  undoExpectedFiles: actionPayload.undoExpectedFiles,
688
720
  ...(actionPayload.trackedChangeCaptures ? { trackedChangeCaptures: actionPayload.trackedChangeCaptures } : {}),
721
+ ...(actionPayload.pendingDirectoryCleanup ? { pendingDirectoryCleanup: actionPayload.pendingDirectoryCleanup } : {}),
722
+ ...(actionPayload.recoveryRetention ? { recoveryRetention: SessionState.normalizeRecoveryRetention(actionPayload.recoveryRetention) } : {}),
689
723
  undoStatus: normalizeDisplayTextForStorage(run.undoStatus, SESSION_STORAGE_LIMITS.statusTextChars),
724
+ ...(run.undoOwnerProtocol === 1 ? { undoOwnerProtocol: 1 } : {}),
690
725
  nativeRequestId: normalizeTextField(run.nativeRequestId, 160),
726
+ ...(run.operation === 'compact' ? { operation: 'compact' } : {}),
691
727
  codexThreadId: normalizeTextField(run.codexThreadId, 160), codexTurnId: normalizeTextField(run.codexTurnId, 160),
728
+ contextUsage: run.forkSnapshot === true ? null : ContextUsage.normalize(run.contextUsage),
692
729
  nativeEventSeq: Number.isFinite(Number(run.nativeEventSeq)) ? Number(run.nativeEventSeq) : 0,
693
730
  queueItemId: normalizeTextField(run.queueItemId, 160)
694
731
  };
@@ -725,6 +762,7 @@
725
762
  status: normalizeEventStatus(event.status),
726
763
  timestamp: typeof event.timestamp === 'string' ? redactSecretLikeText(event.timestamp) : '',
727
764
  kind: typeof event.kind === 'string' ? redactSecretLikeText(event.kind) : 'activity',
765
+ guidanceId: normalizeTextField(event.guidanceId, 160),
728
766
  streamKey: typeof event.streamKey === 'string' ? redactSecretLikeText(event.streamKey) : '',
729
767
  streamRole: typeof event.streamRole === 'string' ? redactSecretLikeText(event.streamRole) : ''
730
768
  };
@@ -754,13 +792,26 @@
754
792
  if (event.failure) {
755
793
  compact.failure = compactStructuredEventValueForStorage(event.failure, 0);
756
794
  }
795
+ if (Array.isArray(event.compileErrors) && event.compileErrors.length) {
796
+ compact.compileErrors = event.compileErrors.slice(0, 5)
797
+ .map(item => normalizeDisplayTextForStorage(String(item), SESSION_STORAGE_LIMITS.detailChars))
798
+ .filter(Boolean);
799
+ }
800
+ if (Array.isArray(event.rejectedHunks) && event.rejectedHunks.length) {
801
+ compact.rejectedHunks = event.rejectedHunks.slice(0, 10)
802
+ .map(item => ({
803
+ path: normalizeDisplayTextForStorage(String(item?.path || ''), SESSION_STORAGE_LIMITS.pathChars),
804
+ summary: normalizeDisplayTextForStorage(String(item?.summary || ''), SESSION_STORAGE_LIMITS.detailChars)
805
+ }))
806
+ .filter(item => item.path);
807
+ }
757
808
  return compact;
758
809
  });
759
810
  }
760
811
 
761
812
  // Deep-copies a known-safe structured event value (the completion-report
762
813
  // {conclusion, body, meta[]} payload, or a FailureReason object) preserving
763
- // its shape while redacting + truncating every string field. Bounded depth +
814
+ // its shape while applying display-path rules and string limits. Bounded depth +
764
815
  // breadth so a pathological value can't blow up the stored record.
765
816
  function compactStructuredEventValueForStorage(value, depth) {
766
817
  return StorageRunActions.compactStructuredEventValue(value, {
@@ -803,7 +854,11 @@
803
854
  }
804
855
 
805
856
  function normalizeDisplayTextForStorage(value, maxChars) {
806
- return normalizeTextField(value, maxChars);
857
+ var text = sanitizeAssistantVisibleText(value);
858
+ if (!Number.isFinite(maxChars) || maxChars <= 0 || text.length <= maxChars) {
859
+ return text;
860
+ }
861
+ return text.slice(0, Math.max(0, maxChars - 1)) + '…';
807
862
  }
808
863
 
809
864
  function summarizeStructuredValueForStorage(value, maxChars) {
@@ -1013,7 +1068,7 @@
1013
1068
  }
1014
1069
 
1015
1070
  function normalizeTextField(value, maxChars) {
1016
- var text = sanitizeAssistantVisibleText(value);
1071
+ var text = sanitizeAssistantVisibleText(redactSecretLikeText(value));
1017
1072
  if (!Number.isFinite(maxChars) || maxChars <= 0 || text.length <= maxChars) {
1018
1073
  return text;
1019
1074
  }
@@ -1024,7 +1079,8 @@
1024
1079
  if (typeof value !== 'string' || !value) {
1025
1080
  return '';
1026
1081
  }
1027
- var text = redactSecretLikeText(value);
1082
+ // Preserve conversation examples and quotations through save/reload.
1083
+ var text = value;
1028
1084
  if (!mightContainLocalReferenceText(text)) {
1029
1085
  return text;
1030
1086
  }
@@ -1309,8 +1365,16 @@
1309
1365
  deleteByIndex: deleteByIndex,
1310
1366
  clearStore: clearStore,
1311
1367
  clearAllStores: clearAllStores,
1368
+ clearAuxiliaryStores: function () { return composerDraftStore.clear(Object.keys(STORES).filter(name => name !== 'sessions')); },
1369
+ readComposerAttachmentDraft: composerDraftStore.read,
1370
+ writeComposerAttachmentDraft: composerDraftStore.write,
1312
1371
  buildSessionRecord: buildSessionRecord,
1372
+ compactSessionBatchActions: compactSessionBatchActions,
1373
+ projectRetentionWarnings: StorageRunActions.projectRetentionWarnings,
1374
+ projectRetentionUpdates: StorageRunActions.projectRetentionUpdates,
1313
1375
  mergeSessionReviewState: StorageRunActions.mergeSessionReviewState,
1376
+ copyRunReviewState: StorageRunActions.copyRunReviewState,
1377
+ reviewStateSnapshot: StorageRunActions.reviewStateSnapshot,
1314
1378
  buildTurnRecord: buildTurnRecord,
1315
1379
  buildEventRecord: buildEventRecord,
1316
1380
  buildArtifactRecord: buildArtifactRecord,
@@ -8,6 +8,7 @@
8
8
  'use strict';
9
9
 
10
10
  var PREFS_KEY = 'codexOverleafPrefs';
11
+ var LEGACY_MIGRATION_PREFIX = 'codexOverleafLegacyPanelMigration:';
11
12
  var SESSION_TOMBSTONES_KEY = 'codexOverleafSessionTombstones';
12
13
  var SESSION_TOMBSTONE_ENTRY_PREFIX = 'codexOverleafSessionTombstone:v2:';
13
14
  var MAX_DELETED_SESSION_IDS_PER_PROJECT = 100;
@@ -18,6 +19,7 @@
18
19
  'experimentalOtByProject',
19
20
  'customInstructionsByProject',
20
21
  'governanceRulesByProject',
22
+ 'reviewingAvailabilityByProject',
21
23
  'selectedLocalSkillIdsByProject'
22
24
  ];
23
25
  var projectPreferenceLockTails = {};
@@ -129,7 +131,12 @@
129
131
  ? incoming[mapName]
130
132
  : {};
131
133
  if (Object.prototype.hasOwnProperty.call(incomingMap, projectId)) {
132
- storedMap[scopedKey] = copyPreferenceValue(incomingMap[projectId]);
134
+ const previous = storedMap[scopedKey], observation = incomingMap[projectId];
135
+ if (mapName !== 'reviewingAvailabilityByProject'
136
+ || !(Number(previous?.observedAt) > Number(observation?.observedAt)
137
+ || (previous?.observedAt === observation?.observedAt && previous?.status === 'available'))) {
138
+ storedMap[scopedKey] = copyPreferenceValue(observation);
139
+ }
133
140
  }
134
141
  delete storedMap[projectId];
135
142
  next[mapName] = storedMap;
@@ -139,118 +146,77 @@
139
146
 
140
147
  function runMigrationIfNeeded(projectId, legacyStorageKey, accountScopeId) {
141
148
  projectId = normalizeProjectPrefKey(projectId);
142
- var normalizedAccountScopeId = normalizeTextField(accountScopeId, PROJECT_PREF_KEY_MAX_CHARS);
143
- if (!normalizedAccountScopeId || !projectId) {
144
- return Promise.resolve({
145
- prefs: normalizePrefs({}),
146
- sessions: [],
147
- activeSessionId: '',
148
- migrated: false,
149
- reason: 'account_scope_unavailable'
150
- });
151
- }
152
- return withProjectPreferenceLock(projectId, function () {
153
- return chrome.storage.local.get(null).then(function (stored) {
154
- var claimed = claimLegacyProjectPreferences(
155
- stored[PREFS_KEY] || {},
156
- normalizedAccountScopeId,
157
- projectId
158
- );
159
- var storedPrefs = claimed.prefs;
160
- var persistClaim = claimed.changed
161
- ? chrome.storage.local.set({ [PREFS_KEY]: storedPrefs })
162
- : Promise.resolve();
163
- return persistClaim.then(function () {
164
- var prefs = buildProjectPreferenceView(
165
- storedPrefs,
166
- normalizedAccountScopeId,
167
- projectId
168
- );
169
- var tombstones = collectSessionTombstones(stored);
170
- var deletedSessionIds = getDeletedSessionIds(tombstones, projectId);
171
- var schemaVersion = prefs.storageSchemaVersion || 0;
172
-
173
- if (schemaVersion >= StorageDb.TARGET_SCHEMA_VERSION) {
174
- var activeSessionByProject = prefs.activeSessionByProject || {};
175
- var activeSessionId = activeSessionByProject[projectId] || '';
176
- if (typeof StorageDb.claimSessionsForAccount !== 'function') {
177
- return Promise.reject(Object.assign(
178
- new Error('Atomic legacy-session claiming is unavailable.'),
179
- { code: 'scoped_claim_unavailable' }
180
- ));
181
- }
182
- return StorageDb.claimSessionsForAccount(
183
- projectId,
184
- normalizedAccountScopeId,
185
- deletedSessionIds
186
- ).then(function (visibleSessions) {
187
- var visibleActiveSessionId = visibleSessions.some(function (session) {
188
- return session && session.id === activeSessionId;
189
- })
190
- ? activeSessionId
191
- : visibleSessions.length
192
- ? visibleSessions[visibleSessions.length - 1].id
193
- : '';
194
- return {
195
- prefs: prefs,
196
- sessions: visibleSessions,
197
- activeSessionId: visibleActiveSessionId,
198
- migrated: false
199
- };
200
- });
201
- }
202
-
203
- // Migration v0 → v1
204
- var legacyBlob = stored[legacyStorageKey] || {};
205
- var legacySessions = Array.isArray(legacyBlob.sessions) ? legacyBlob.sessions : [];
206
- var migratedSessions = [];
207
-
208
- for (var i = 0; i < legacySessions.length; i++) {
209
- var legacy = legacySessions[i];
210
- if (!legacy || !legacy.id) { continue; }
211
- if (deletedSessionIds.indexOf(legacy.id) !== -1) { continue; }
212
- var record = StorageDb.buildSessionRecord(
213
- buildLegacySessionRecordInput(projectId, legacyBlob, legacy, normalizedAccountScopeId)
214
- );
215
- migratedSessions.push(record);
216
- }
217
-
218
- var putPromise = migratedSessions.length
219
- ? StorageDb.putRecords('sessions', migratedSessions)
220
- : Promise.resolve([]);
221
-
222
- return putPromise.then(function () {
223
- var newPrefs = StorageDb.extractLightweightPrefs(legacyBlob, projectId);
224
- newPrefs.activeSessionByProject = StorageDb.buildActiveSessionByProject(
225
- {},
226
- projectId,
227
- legacyBlob.activeSessionId || (migratedSessions.length ? migratedSessions[migratedSessions.length - 1].id : '')
228
- );
229
- var mergedPrefs = mergeScopedProjectPreferences(
230
- storedPrefs,
231
- newPrefs,
232
- normalizedAccountScopeId,
233
- projectId
234
- );
235
- var prefsView = buildProjectPreferenceView(
236
- mergedPrefs,
237
- normalizedAccountScopeId,
238
- projectId
239
- );
240
-
241
- return chrome.storage.local.set({ [PREFS_KEY]: mergedPrefs }).then(function () {
242
- return chrome.storage.local.remove(legacyStorageKey).catch(function () {});
243
- }).then(function () {
244
- return {
245
- prefs: prefsView,
246
- sessions: migratedSessions,
247
- activeSessionId: prefsView.activeSessionByProject[projectId] || '',
248
- migrated: true
249
- };
250
- });
251
- });
149
+ var account = normalizeTextField(accountScopeId, PROJECT_PREF_KEY_MAX_CHARS);
150
+ if (!account || !projectId) return Promise.resolve({ prefs: normalizePrefs({}), sessions: [],
151
+ activeSessionId: '', migrated: false, reason: 'account_scope_unavailable' });
152
+ return withProjectPreferenceLock(projectId, async function () {
153
+ var stored = await chrome.storage.local.get(null);
154
+ var claimed = claimLegacyProjectPreferences(stored[PREFS_KEY] || {}, account, projectId);
155
+ var storedPrefs = claimed.prefs;
156
+ if (claimed.changed) await chrome.storage.local.set({ [PREFS_KEY]: storedPrefs });
157
+ var prefs = buildProjectPreferenceView(storedPrefs, account, projectId);
158
+ var deleted = getDeletedSessionIds(collectSessionTombstones(stored), projectId);
159
+ var markerKey = LEGACY_MIGRATION_PREFIX + encodeURIComponent(String(legacyStorageKey || ''));
160
+ var marker = stored[markerKey];
161
+ var legacyBlob = stored[legacyStorageKey];
162
+ var hasLegacy = Boolean(legacyBlob && typeof legacyBlob === 'object' && !Array.isArray(legacyBlob));
163
+ var schemaCurrent = (prefs.storageSchemaVersion || 0) >= StorageDb.TARGET_SCHEMA_VERSION;
164
+ if (marker && (marker.projectId !== projectId || marker.sourceKey !== legacyStorageKey || !marker.accountScopeId)) {
165
+ throw Object.assign(new Error('The legacy history source has a conflicting migration identity.'), { code: 'legacy_migration_scope_conflict' });
166
+ }
167
+ if (typeof StorageDb.claimSessionsForAccount !== 'function') {
168
+ throw Object.assign(new Error('Atomic legacy-session claiming is unavailable.'), { code: 'scoped_claim_unavailable' });
169
+ }
170
+ var visible = await StorageDb.claimSessionsForAccount(projectId, account, deleted);
171
+ function result(currentPrefs, sessions, migrated) {
172
+ var wanted = currentPrefs.activeSessionByProject?.[projectId] || '';
173
+ return { prefs: currentPrefs, sessions: sessions,
174
+ activeSessionId: sessions.some(session => session.id === wanted) ? wanted : sessions.at(-1)?.id || '',
175
+ migrated: migrated };
176
+ }
177
+ if ((schemaCurrent && !hasLegacy) || marker?.complete || (marker && marker.accountScopeId !== account)) {
178
+ return result(prefs, visible, false);
179
+ }
180
+ legacyBlob = hasLegacy ? legacyBlob : {};
181
+ var legacySessions = Array.isArray(legacyBlob.sessions) ? legacyBlob.sessions : [];
182
+ var owners = new Set([legacyBlob.accountScopeId, legacyBlob.__codexOverleafFallbackAccountScopeId,
183
+ ...legacySessions.map(session => session?.accountScopeId)].filter(value => typeof value === 'string' && value));
184
+ if ([...owners].some(owner => owner !== account)) return result(prefs, visible, false);
185
+ // The shared preferences lock serializes this source claim across accounts.
186
+ // Keep it after a write failure; only its owner can finish the import.
187
+ if (hasLegacy && !marker) {
188
+ marker = { sourceKey: legacyStorageKey, projectId: projectId, accountScopeId: account, complete: false };
189
+ await chrome.storage.local.set({ [markerKey]: marker });
190
+ }
191
+ var existingIds = new Set(visible.map(session => session.id));
192
+ var incoming = legacySessions.filter(session => session?.id && !deleted.includes(session.id) && !existingIds.has(session.id))
193
+ .map(session => StorageDb.buildSessionRecord(buildLegacySessionRecordInput(projectId, legacyBlob, session, account)));
194
+ var written = incoming.length ? await StorageDb.putRecords('sessions', incoming) : [];
195
+ if (incoming.length && (!Array.isArray(written) || incoming.some(session => !written.some(record =>
196
+ record.id === session.id && record.accountScopeId === account && record.projectId === projectId)))) {
197
+ throw Object.assign(new Error('Legacy history was not confirmed in the main session store.'), { code: 'legacy_migration_not_persisted' });
198
+ }
199
+ var sessions = [...visible, ...written];
200
+ var newPrefs = StorageDb.extractLightweightPrefs(legacyBlob, projectId);
201
+ if (schemaCurrent) {
202
+ // A later project's import must not reset current global preferences.
203
+ var legacyPrefs = newPrefs;
204
+ newPrefs = Object.assign({}, legacyPrefs, prefs);
205
+ PROJECT_SCOPED_PREF_MAPS.forEach(function (name) {
206
+ newPrefs[name] = Object.assign({}, legacyPrefs[name] || {}, prefs[name] || {});
252
207
  });
253
- });
208
+ }
209
+ var currentActive = prefs.activeSessionByProject?.[projectId];
210
+ var activeId = sessions.some(session => session.id === currentActive) ? currentActive
211
+ : legacyBlob.activeSessionId || sessions.at(-1)?.id || '';
212
+ newPrefs.activeSessionByProject = StorageDb.buildActiveSessionByProject({}, projectId, activeId);
213
+ var mergedPrefs = mergeScopedProjectPreferences(storedPrefs, newPrefs, account, projectId);
214
+ await chrome.storage.local.set({ [PREFS_KEY]: mergedPrefs });
215
+ // Completion is per source and owner, independent of the global schema.
216
+ // A failed cleanup cannot replay old content or transfer it to another account.
217
+ if (hasLegacy) await chrome.storage.local.set({ [markerKey]: { ...marker, complete: true } });
218
+ await chrome.storage.local.remove(legacyStorageKey).catch(function () {});
219
+ return result(buildProjectPreferenceView(mergedPrefs, account, projectId), sessions, true);
254
220
  });
255
221
  }
256
222