codex-overleaf-link 2.2.0 → 2.3.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 (72) hide show
  1. package/README.md +25 -23
  2. package/extension/bootstrap/manifest.template.json +1 -1
  3. package/extension/runtime-manifest.json +5 -71
  4. package/extension/src/background.js +53 -69
  5. package/extension/src/backgroundUpdateCoordinator.js +128 -66
  6. package/extension/src/content/applyResultFormatters.js +2 -3
  7. package/extension/src/content/contentRuntime.js +650 -1449
  8. package/extension/src/content/contextTray.js +4 -6
  9. package/extension/src/content/diagnosticsController.js +1 -2
  10. package/extension/src/content/diffReviewPanel.js +14 -13
  11. package/extension/src/content/generated/content.bundle.js +41370 -0
  12. package/extension/src/content/generated/content.bundle.meta.json +102 -0
  13. package/extension/src/content/legacyGlobalRegistry.js +129 -0
  14. package/extension/src/content/markdownText.js +5 -7
  15. package/extension/src/content/modelPicker.js +1 -1
  16. package/extension/src/content/modelPickerSupport.js +10 -5
  17. package/extension/src/content/moduleRegistryKernel.js +125 -0
  18. package/extension/src/content/nativeCompatibilityController.js +313 -0
  19. package/extension/src/content/otWarmMirror.js +7 -5
  20. package/extension/src/content/pageBridgeClient.js +224 -0
  21. package/extension/src/content/panelMaintenance.js +8 -3
  22. package/extension/src/content/postNavigationSettlementPersistence.js +100 -0
  23. package/extension/src/content/projectProviderSelection.js +4 -12
  24. package/extension/src/content/projectSessionCleanup.js +3 -3
  25. package/extension/src/content/providerSettingsCoordinator.js +59 -26
  26. package/extension/src/content/providerSettingsDialog.js +30 -18
  27. package/extension/src/content/recentProjects.js +15 -23
  28. package/extension/src/content/runGuidanceController.js +1 -1
  29. package/extension/src/content/runQueueScheduler.js +129 -29
  30. package/extension/src/content/runSettlementPersistence.js +51 -0
  31. package/extension/src/content/runTimelineView.js +11 -8
  32. package/extension/src/content/scopedPersistenceCoordinator.js +100 -0
  33. package/extension/src/content/scopedPersistenceDetachedCommit.js +47 -0
  34. package/extension/src/content/scopedPersistencePanelState.js +111 -0
  35. package/extension/src/content/sessionManager.js +15 -12
  36. package/extension/src/content/sessionPersistence.js +67 -8
  37. package/extension/src/content/updateNotice.js +10 -4
  38. package/extension/src/content/writebackOrchestrator.js +91 -23
  39. package/extension/src/contentScript.js +5 -1
  40. package/extension/src/page/trackedChangesLifecycle.js +6 -1
  41. package/extension/src/pageBridge.js +47 -98
  42. package/extension/src/shared/agentTranscript.js +8 -5
  43. package/extension/src/shared/compatibility.js +1 -1
  44. package/extension/src/shared/governanceRules.js +1 -1
  45. package/extension/src/shared/managedUpdateProjection.js +337 -0
  46. package/extension/src/shared/nativeRequestIdentity.js +60 -0
  47. package/extension/src/shared/otText.js +0 -19
  48. package/extension/src/shared/pageRpcContract.js +136 -0
  49. package/extension/src/shared/runExecutionSnapshot.js +177 -0
  50. package/extension/src/shared/runExecutionSnapshotCodec.js +168 -0
  51. package/extension/src/shared/runInputQueue.js +81 -34
  52. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +79 -0
  53. package/extension/src/shared/scopedPersistenceQueuePolicy.js +181 -0
  54. package/extension/src/shared/scopedPersistenceTransaction.js +238 -0
  55. package/extension/src/shared/sessionState.js +64 -48
  56. package/extension/src/shared/settlementFacts.js +351 -0
  57. package/extension/src/shared/storageDb.js +19 -5
  58. package/extension/src/shared/storageMigration.js +275 -61
  59. package/extension/src/shared/storageSessionClaims.js +60 -0
  60. package/extension/src/shared/updateConsent.js +4 -0
  61. package/extension/src/shared/updateRevocationIntent.js +109 -0
  62. package/extension/src/shared/writebackEvidenceProjection.js +150 -0
  63. package/extension/src/shared/writebackOperationEvidence.js +143 -0
  64. package/extension/src/shared/writebackSettlement.js +705 -0
  65. package/native-host/src/codexRuntimeIdentity.js +1 -1
  66. package/native-host/src/codexSessionRunner.js +7 -13
  67. package/native-host/src/index.js +3 -69
  68. package/native-host/src/managedInstall.js +50 -8
  69. package/native-host/src/mirrorWorkspace.js +15 -8
  70. package/native-host/src/nativeTransportEnvelope.js +148 -0
  71. package/native-host/src/taskRunnerRuntime.js +3 -3
  72. package/package.json +13 -5
@@ -0,0 +1,238 @@
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) {
3
+ module.exports = factory(
4
+ require('./scopedPersistenceQueuePolicy'),
5
+ require('./scopedPersistenceBrowserAdapter')
6
+ );
7
+ } else {
8
+ root.CodexOverleafModuleRegistry.define('ScopedPersistenceTransaction', [
9
+ 'ScopedPersistenceQueuePolicy',
10
+ 'ScopedPersistenceBrowserAdapter'
11
+ ], factory);
12
+ }
13
+ })(typeof globalThis !== 'undefined' ? globalThis : this, function (QueuePolicy, BrowserAdapter) {
14
+ 'use strict';
15
+
16
+ var applyQueueMutations = QueuePolicy.applyQueueMutations;
17
+ var cleanPart = QueuePolicy.cleanPart;
18
+ var createQueueClaim = QueuePolicy.createQueueClaim;
19
+ var isClaimCurrent = QueuePolicy.isClaimCurrent;
20
+ var mergeTombstones = QueuePolicy.mergeTombstones;
21
+ var normalizeMeta = QueuePolicy.normalizeMeta;
22
+ var normalizeQueueMutations = QueuePolicy.normalizeQueueMutations;
23
+ var normalizeRevision = QueuePolicy.normalizeRevision;
24
+ var createBrowserAdapter = BrowserAdapter.createBrowserAdapter;
25
+ var normalizeScope = BrowserAdapter.normalizeScope;
26
+ var scopeKey = BrowserAdapter.scopeKey;
27
+
28
+ function sameScope(left, right) {
29
+ return Boolean(left && right
30
+ && left.accountScopeId === right.accountScopeId
31
+ && left.projectId === right.projectId);
32
+ }
33
+
34
+
35
+ function createCoordinator(options) {
36
+ options = options || {};
37
+ var adapter = options.adapter || createBrowserAdapter(options);
38
+ var writerId = cleanPart(options.writerId) || randomId();
39
+ var generation = 0;
40
+ var active = null;
41
+
42
+ async function beginHydration(inputScope) {
43
+ var scope = normalizeScope(inputScope);
44
+ generation += 1;
45
+ var tokenGeneration = generation;
46
+ active = makeToken(scope, tokenGeneration, 0, false, 0);
47
+ var meta = await strictRead(adapter, scope);
48
+ var token = makeToken(scope, tokenGeneration, meta.revision, false, meta.queueRevision);
49
+ if (active && active.generation === tokenGeneration && sameScope(active, token)) active = token;
50
+ return token;
51
+ }
52
+
53
+ async function captureCommitView(inputScope, captureOptions) {
54
+ var scope = normalizeScope(inputScope);
55
+ var detached = Boolean(captureOptions && captureOptions.detached);
56
+ if (!detached && active && active.projectId === scope.projectId) {
57
+ scope = normalizeScope({
58
+ accountScopeId: active.accountScopeId,
59
+ projectId: scope.projectId
60
+ });
61
+ }
62
+ if (!detached && active && sameScope(active, scope)) {
63
+ return makeToken(scope, active.generation, active.revision, false, active.queueRevision);
64
+ }
65
+ var meta = await strictRead(adapter, scope);
66
+ return makeToken(scope, detached ? 0 : generation, meta.revision, detached, meta.queueRevision);
67
+ }
68
+
69
+ function isCurrent(token) {
70
+ return Boolean(token && active && token.detached !== true
71
+ && token.generation === active.generation && sameScope(token, active));
72
+ }
73
+
74
+ async function commit(token, action, commitOptions) {
75
+ if (!token || typeof action !== 'function' || !token.projectId) {
76
+ return { ok: false, reason: 'invalid_commit' };
77
+ }
78
+ var scope = normalizeScope(token);
79
+ if (!token.detached && !isCurrent(token)) return { ok: false, reason: 'stale_view' };
80
+ return adapter.withLock(scope, async function () {
81
+ if (!token.detached && !isCurrent(token)) return { ok: false, reason: 'stale_view' };
82
+ var currentMeta = await strictRead(adapter, scope);
83
+ if (!token.detached && !isCurrent(token)) return { ok: false, reason: 'stale_view' };
84
+ var conflict = currentMeta.revision !== normalizeRevision(token.revision);
85
+ if (conflict && !(commitOptions && commitOptions.rebase === true)) {
86
+ return {
87
+ ok: false,
88
+ reason: 'revision_conflict',
89
+ expectedRevision: token.revision,
90
+ actualRevision: currentMeta.revision
91
+ };
92
+ }
93
+ var queueMutations = normalizeQueueMutations(commitOptions);
94
+ if (queueMutations.length
95
+ && currentMeta.queueRevision !== normalizeRevision(token.queueRevision)) {
96
+ if (!token.detached && isCurrent(token)) {
97
+ active = makeToken(
98
+ scope,
99
+ token.generation,
100
+ currentMeta.revision,
101
+ false,
102
+ currentMeta.queueRevision
103
+ );
104
+ }
105
+ return {
106
+ ok: false,
107
+ reason: 'queue_revision_conflict',
108
+ expectedRevision: token.queueRevision,
109
+ actualRevision: currentMeta.queueRevision,
110
+ actualStateRevision: currentMeta.revision
111
+ };
112
+ }
113
+ var projected = applyQueueMutations(currentMeta, queueMutations, writerId);
114
+ if (!projected.ok) return projected;
115
+ var nextMeta = {
116
+ ...projected.meta,
117
+ revision: currentMeta.revision + 1,
118
+ writerId: writerId,
119
+ updatedAt: new Date().toISOString(),
120
+ sessionTombstones: mergeTombstones(
121
+ projected.meta.sessionTombstones,
122
+ commitOptions && commitOptions.sessionTombstones,
123
+ 200
124
+ )
125
+ };
126
+ await adapter.write(scope, nextMeta);
127
+ if (!token.detached && isCurrent(token)) {
128
+ active = makeToken(
129
+ scope,
130
+ token.generation,
131
+ nextMeta.revision,
132
+ false,
133
+ nextMeta.queueRevision
134
+ );
135
+ }
136
+ var value;
137
+ try {
138
+ value = await action({
139
+ scope: scope,
140
+ baseRevision: currentMeta.revision,
141
+ conflict: conflict,
142
+ writerId: writerId,
143
+ currentMeta: currentMeta,
144
+ nextMeta: nextMeta
145
+ });
146
+ } catch (error) {
147
+ if (queueMutations.some(function (mutation) {
148
+ return ['remove', 'release', 'restore'].includes(cleanPart(mutation.type));
149
+ })) {
150
+ var recoveredMeta = {
151
+ ...currentMeta,
152
+ revision: nextMeta.revision + 1,
153
+ queueRevision: nextMeta.queueRevision + 1,
154
+ writerId: writerId,
155
+ updatedAt: new Date().toISOString()
156
+ };
157
+ try {
158
+ await adapter.write(scope, recoveredMeta);
159
+ if (!token.detached && isCurrent(token)) {
160
+ active = makeToken(
161
+ scope,
162
+ token.generation,
163
+ recoveredMeta.revision,
164
+ false,
165
+ recoveredMeta.queueRevision
166
+ );
167
+ }
168
+ } catch (recoveryError) {
169
+ if (error && typeof error === 'object') {
170
+ error.persistenceRecoveryError = recoveryError.message || String(recoveryError);
171
+ }
172
+ }
173
+ }
174
+ throw error;
175
+ }
176
+ return {
177
+ ok: true,
178
+ value: value,
179
+ revision: nextMeta.revision,
180
+ queueRevision: nextMeta.queueRevision,
181
+ queueClaims: nextMeta.queueClaims,
182
+ rebased: conflict,
183
+ superseded: !token.detached && !isCurrent(token)
184
+ };
185
+ });
186
+ }
187
+
188
+ return Object.freeze({
189
+ beginHydration: beginHydration,
190
+ captureCommitView: captureCommitView,
191
+ commit: commit,
192
+ getActiveView: function () {
193
+ return active
194
+ ? makeToken(active, active.generation, active.revision, false, active.queueRevision)
195
+ : null;
196
+ },
197
+ getWriterId: function () { return writerId; },
198
+ invalidate: function () {
199
+ generation += 1;
200
+ active = null;
201
+ },
202
+ isCurrent: isCurrent
203
+ });
204
+ }
205
+
206
+ function makeToken(scope, tokenGeneration, revision, detached, queueRevision) {
207
+ return Object.freeze({
208
+ accountScopeId: scope.accountScopeId,
209
+ projectId: scope.projectId,
210
+ generation: normalizeRevision(tokenGeneration),
211
+ revision: normalizeRevision(revision),
212
+ queueRevision: normalizeRevision(queueRevision),
213
+ detached: detached === true
214
+ });
215
+ }
216
+
217
+ async function strictRead(adapter, scope) {
218
+ return normalizeMeta(await adapter.read(scope));
219
+ }
220
+
221
+ function randomId() {
222
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
223
+ return crypto.randomUUID();
224
+ }
225
+ return 'writer-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2);
226
+ }
227
+
228
+ return Object.freeze({
229
+ createBrowserAdapter: createBrowserAdapter,
230
+ createCoordinator: createCoordinator,
231
+ createQueueClaim: createQueueClaim,
232
+ isClaimCurrent: isClaimCurrent,
233
+ mergeTombstones: mergeTombstones,
234
+ normalizeScope: normalizeScope,
235
+ sameScope: sameScope,
236
+ scopeKey: scopeKey
237
+ });
238
+ });
@@ -1,16 +1,28 @@
1
1
  (function initSessionState(root, factory) {
2
2
  if (typeof module === 'object' && module.exports) {
3
- module.exports = factory();
3
+ module.exports = factory(
4
+ require('./i18n'),
5
+ require('./settlementFacts'),
6
+ require('./runInputQueue'),
7
+ require('./lineReferences'),
8
+ require('./pathRedaction')
9
+ );
4
10
  } else {
5
- root.CodexOverleafSessionState = factory();
6
- }
7
- })(typeof globalThis !== 'undefined' ? globalThis : window, function sessionStateFactory() {
11
+ root.CodexOverleafModuleRegistry.define(
12
+ 'SessionState',
13
+ ['I18n', 'SettlementFacts', 'RunInputQueue', 'LineReferences', 'PathRedaction'],
14
+ factory
15
+ );
16
+ }
17
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function sessionStateFactory(
18
+ i18n,
19
+ SettlementFacts,
20
+ RunInputQueue,
21
+ LineReferences,
22
+ PathRedaction
23
+ ) {
8
24
  'use strict';
9
25
 
10
- const i18n = (typeof module === 'object' && module.exports)
11
- ? require('./i18n')
12
- : (typeof globalThis !== 'undefined' ? globalThis : window).CodexOverleafI18n;
13
-
14
26
  const DEFAULT_PANEL_STATE = {
15
27
  mode: 'confirm',
16
28
  providerId: 'builtin',
@@ -109,9 +121,6 @@
109
121
  /\b(?:sk|pk)-[A-Za-z0-9][A-Za-z0-9_-]{7,}\b/g,
110
122
  /\b(?:api[_-]?key|token|password|passwd|secret)\b\s*[:=]\s*["']?[^"'\s,;]+["']?/gi
111
123
  ];
112
- const LineReferences = loadLineReferences();
113
- const PathRedaction = loadPathRedaction();
114
-
115
124
  function normalizePanelState(input = {}, options = {}) {
116
125
  const state = {
117
126
  ...DEFAULT_PANEL_STATE,
@@ -226,7 +235,15 @@
226
235
  requireReviewing: session.requireReviewing !== false,
227
236
  focusFiles: normalizeFocusFiles(session.focusFiles),
228
237
  codexThreadId: typeof session.codexThreadId === 'string' ? session.codexThreadId : '',
229
- pendingInputs: normalizePendingInputs(session.pendingInputs, options.restoreRunningRuns === true)
238
+ pendingInputs: normalizePendingInputs(
239
+ session.pendingInputs,
240
+ options.restoreRunningRuns === true,
241
+ {
242
+ ...fallbackState,
243
+ ...session,
244
+ focusFiles: normalizeFocusFiles(session.focusFiles)
245
+ }
246
+ )
230
247
  };
231
248
  }
232
249
 
@@ -626,6 +643,18 @@
626
643
  interruptedDraft: run.interruptedDraft ? sanitizeAssistantVisibleValue(run.interruptedDraft) : undefined
627
644
  };
628
645
 
646
+ if (run.executionSnapshot && typeof run.executionSnapshot === 'object') {
647
+ normalized.executionSnapshot = sanitizeAssistantVisibleValue(run.executionSnapshot);
648
+ }
649
+ const storedSettlement = run.settlement && typeof run.settlement === 'object'
650
+ ? run.settlement
651
+ : run.settlementFacts;
652
+ if (storedSettlement && typeof storedSettlement === 'object') {
653
+ normalized.settlement = sanitizeAssistantVisibleValue(storedSettlement);
654
+ }
655
+ if (run.changedDocument === true) {
656
+ normalized.changedDocument = true;
657
+ }
629
658
  applyTrackedChangeStatus(normalized, run.trackedChangeStatus);
630
659
 
631
660
  return normalized;
@@ -658,7 +687,7 @@
658
687
  // the run returns to the legacy-undo world. A terminal status with no refs
659
688
  // is kept — step 3 already empties terminal payloads and the label stays
660
689
  // meaningful.
661
- if (!hasRefs && status !== undefined && !TERMINAL_TRACKED_CHANGE_STATUS.has(status)) {
690
+ if (!hasRefs && status === 'pending') {
662
691
  status = undefined;
663
692
  }
664
693
 
@@ -1121,10 +1150,18 @@
1121
1150
  .filter(run => Array.isArray(run.undoOperations) && run.undoOperations.length)
1122
1151
  .slice(0, limits.maxUndoRunsPerSession)
1123
1152
  .map(run => run.id));
1124
- return selectedRuns.map(run => compactRunForStorage(run, limits, undoRunIds.has(run.id)));
1153
+ const settlementFactsByRunId = SettlementFacts.compactSessionSettlementFacts(selectedRuns, {
1154
+ sanitize: sanitizeAssistantVisibleValue
1155
+ });
1156
+ return selectedRuns.map(run => compactRunForStorage(
1157
+ run,
1158
+ limits,
1159
+ undoRunIds.has(run.id),
1160
+ settlementFactsByRunId.get(run.id)
1161
+ ));
1125
1162
  }
1126
1163
 
1127
- function compactRunForStorage(run, limits, keepUndoPayload) {
1164
+ function compactRunForStorage(run, limits, keepUndoPayload, settlementFacts = null) {
1128
1165
  const undoPayload = compactUndoPayload(run, limits, keepUndoPayload);
1129
1166
  const compact = {
1130
1167
  id: run.id,
@@ -1151,6 +1188,15 @@
1151
1188
  nativeEventSeq: Number.isFinite(Number(run.nativeEventSeq)) ? Number(run.nativeEventSeq) : 0,
1152
1189
  queueItemId: normalizeTextField(run.queueItemId, 160)
1153
1190
  };
1191
+ if (run.executionSnapshot && typeof run.executionSnapshot === 'object') {
1192
+ compact.executionSnapshot = sanitizeAssistantVisibleValue(run.executionSnapshot);
1193
+ }
1194
+ if (settlementFacts && typeof settlementFacts === 'object') {
1195
+ compact.settlement = settlementFacts;
1196
+ }
1197
+ if (run.changedDocument === true) {
1198
+ compact.changedDocument = true;
1199
+ }
1154
1200
  if (run.interruptedDraft) {
1155
1201
  compact.interruptedDraft = sanitizeAssistantVisibleValue(run.interruptedDraft);
1156
1202
  }
@@ -1384,11 +1430,9 @@
1384
1430
  }));
1385
1431
  }
1386
1432
 
1387
- function normalizePendingInputs(value, recoverActive = false) {
1388
- const Queue = (typeof globalThis !== 'undefined' ? globalThis.CodexOverleafRunInputQueue : null)
1389
- || (typeof module === 'object' && module.exports ? require('./runInputQueue') : null);
1390
- if (Queue?.normalizeQueue) {
1391
- return Queue.normalizeQueue(value, { recoverActive });
1433
+ function normalizePendingInputs(value, recoverActive = false, fallbackInput = {}) {
1434
+ if (RunInputQueue?.normalizeQueue) {
1435
+ return RunInputQueue.normalizeQueue(value, { recoverActive, fallbackInput });
1392
1436
  }
1393
1437
  return [];
1394
1438
  }
@@ -1442,34 +1486,6 @@
1442
1486
  return /(?:file:\/\/\/?|[A-Za-z]:[\\/]|\/(?:Users|home|private|var|tmp)\/|[\\/]\.codex-overleaf[\\/]projects[\\/]|\.codex-overleaf[\\/]projects[\\/])/i.test(String(value || ''));
1443
1487
  }
1444
1488
 
1445
- function loadLineReferences() {
1446
- if (typeof globalThis !== 'undefined' && globalThis.CodexOverleafLineReferences) {
1447
- return globalThis.CodexOverleafLineReferences;
1448
- }
1449
- if (typeof require === 'function') {
1450
- try {
1451
- return require('./lineReferences');
1452
- } catch (_error) {
1453
- return null;
1454
- }
1455
- }
1456
- return null;
1457
- }
1458
-
1459
- function loadPathRedaction() {
1460
- if (typeof globalThis !== 'undefined' && globalThis.CodexOverleafPathRedaction) {
1461
- return globalThis.CodexOverleafPathRedaction;
1462
- }
1463
- if (typeof require === 'function') {
1464
- try {
1465
- return require('./pathRedaction');
1466
- } catch (_error) {
1467
- return null;
1468
- }
1469
- }
1470
- return null;
1471
- }
1472
-
1473
1489
  function fallbackSanitizeLocalReferences(value) {
1474
1490
  return String(value || '')
1475
1491
  .replace(/\[([^\]]*)\]\(([^)]*)\)/g, (_raw, label, target) => {