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.
- package/README.md +25 -23
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/runtime-manifest.json +5 -71
- package/extension/src/background.js +53 -69
- package/extension/src/backgroundUpdateCoordinator.js +128 -66
- package/extension/src/content/applyResultFormatters.js +2 -3
- package/extension/src/content/contentRuntime.js +650 -1449
- package/extension/src/content/contextTray.js +4 -6
- package/extension/src/content/diagnosticsController.js +1 -2
- package/extension/src/content/diffReviewPanel.js +14 -13
- package/extension/src/content/generated/content.bundle.js +41370 -0
- package/extension/src/content/generated/content.bundle.meta.json +102 -0
- package/extension/src/content/legacyGlobalRegistry.js +129 -0
- package/extension/src/content/markdownText.js +5 -7
- package/extension/src/content/modelPicker.js +1 -1
- package/extension/src/content/modelPickerSupport.js +10 -5
- package/extension/src/content/moduleRegistryKernel.js +125 -0
- package/extension/src/content/nativeCompatibilityController.js +313 -0
- package/extension/src/content/otWarmMirror.js +7 -5
- package/extension/src/content/pageBridgeClient.js +224 -0
- package/extension/src/content/panelMaintenance.js +8 -3
- package/extension/src/content/postNavigationSettlementPersistence.js +100 -0
- package/extension/src/content/projectProviderSelection.js +4 -12
- package/extension/src/content/projectSessionCleanup.js +3 -3
- package/extension/src/content/providerSettingsCoordinator.js +59 -26
- package/extension/src/content/providerSettingsDialog.js +30 -18
- package/extension/src/content/recentProjects.js +15 -23
- package/extension/src/content/runGuidanceController.js +1 -1
- package/extension/src/content/runQueueScheduler.js +129 -29
- package/extension/src/content/runSettlementPersistence.js +51 -0
- package/extension/src/content/runTimelineView.js +11 -8
- package/extension/src/content/scopedPersistenceCoordinator.js +100 -0
- package/extension/src/content/scopedPersistenceDetachedCommit.js +47 -0
- package/extension/src/content/scopedPersistencePanelState.js +111 -0
- package/extension/src/content/sessionManager.js +15 -12
- package/extension/src/content/sessionPersistence.js +67 -8
- package/extension/src/content/updateNotice.js +10 -4
- package/extension/src/content/writebackOrchestrator.js +91 -23
- package/extension/src/contentScript.js +5 -1
- package/extension/src/page/trackedChangesLifecycle.js +6 -1
- package/extension/src/pageBridge.js +47 -98
- package/extension/src/shared/agentTranscript.js +8 -5
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/governanceRules.js +1 -1
- package/extension/src/shared/managedUpdateProjection.js +337 -0
- package/extension/src/shared/nativeRequestIdentity.js +60 -0
- package/extension/src/shared/otText.js +0 -19
- package/extension/src/shared/pageRpcContract.js +136 -0
- package/extension/src/shared/runExecutionSnapshot.js +177 -0
- package/extension/src/shared/runExecutionSnapshotCodec.js +168 -0
- package/extension/src/shared/runInputQueue.js +81 -34
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +79 -0
- package/extension/src/shared/scopedPersistenceQueuePolicy.js +181 -0
- package/extension/src/shared/scopedPersistenceTransaction.js +238 -0
- package/extension/src/shared/sessionState.js +64 -48
- package/extension/src/shared/settlementFacts.js +351 -0
- package/extension/src/shared/storageDb.js +19 -5
- package/extension/src/shared/storageMigration.js +275 -61
- package/extension/src/shared/storageSessionClaims.js +60 -0
- package/extension/src/shared/updateConsent.js +4 -0
- package/extension/src/shared/updateRevocationIntent.js +109 -0
- package/extension/src/shared/writebackEvidenceProjection.js +150 -0
- package/extension/src/shared/writebackOperationEvidence.js +143 -0
- package/extension/src/shared/writebackSettlement.js +705 -0
- package/native-host/src/codexRuntimeIdentity.js +1 -1
- package/native-host/src/codexSessionRunner.js +7 -13
- package/native-host/src/index.js +3 -69
- package/native-host/src/managedInstall.js +50 -8
- package/native-host/src/mirrorWorkspace.js +15 -8
- package/native-host/src/nativeTransportEnvelope.js +148 -0
- package/native-host/src/taskRunnerRuntime.js +3 -3
- package/package.json +13 -5
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
(function initCodexOverleafWritebackEvidenceProjection(root, factory) {
|
|
2
|
+
const api = factory();
|
|
3
|
+
if (typeof module === 'object' && module.exports) module.exports = api;
|
|
4
|
+
if (root) root.CodexOverleafWritebackEvidenceProjection = api;
|
|
5
|
+
})(typeof window !== 'undefined' ? window : globalThis, function writebackEvidenceProjectionFactory() {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function aggregateFileSettlements(operationEvidence = [], readbacks = []) {
|
|
9
|
+
const byPath = new Map();
|
|
10
|
+
const byRelatedPath = new Map();
|
|
11
|
+
for (const evidence of operationEvidence) {
|
|
12
|
+
const key = evidence.path || evidence.targetPath || 'unknown file';
|
|
13
|
+
if (!byPath.has(key)) {
|
|
14
|
+
byPath.set(key, {
|
|
15
|
+
path: key,
|
|
16
|
+
operationIds: [],
|
|
17
|
+
relatedPaths: [],
|
|
18
|
+
applied: 'none',
|
|
19
|
+
documentEffect: 'unchanged',
|
|
20
|
+
readBack: 'unknown',
|
|
21
|
+
recoveryKind: '',
|
|
22
|
+
failureCodes: [],
|
|
23
|
+
operationCount: 0,
|
|
24
|
+
appliedCount: 0,
|
|
25
|
+
failedCount: 0
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const file = byPath.get(key);
|
|
29
|
+
file.operationCount++;
|
|
30
|
+
file.operationIds.push(evidence.operationId);
|
|
31
|
+
if (evidence.targetPath && evidence.targetPath !== key && !file.relatedPaths.includes(evidence.targetPath)) {
|
|
32
|
+
file.relatedPaths.push(evidence.targetPath);
|
|
33
|
+
byRelatedPath.set(evidence.targetPath, file);
|
|
34
|
+
}
|
|
35
|
+
if (evidence.collection === 'applied' && evidence.ok !== false) file.appliedCount++;
|
|
36
|
+
if (evidence.collection !== 'applied' || evidence.ok === false) file.failedCount++;
|
|
37
|
+
if (evidence.changedDocument) file.documentEffect = 'changed';
|
|
38
|
+
else if (evidence.mayHaveMutated && file.documentEffect !== 'changed') file.documentEffect = 'possible';
|
|
39
|
+
for (const code of evidence.failureCodes) {
|
|
40
|
+
if (!file.failureCodes.includes(code)) file.failureCodes.push(code);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
for (const readback of normalizeFileReadbackEvidence(readbacks)) {
|
|
44
|
+
const file = byPath.get(readback.path) || byRelatedPath.get(readback.path);
|
|
45
|
+
if (!file) continue;
|
|
46
|
+
const deletesPath = operationEvidence.some(evidence =>
|
|
47
|
+
evidence.kind === 'delete' && evidence.path === readback.path
|
|
48
|
+
);
|
|
49
|
+
file.readBack = deletesPath && readback.state === 'missing' ? 'match' : readback.state;
|
|
50
|
+
if (file.readBack === 'mismatch') {
|
|
51
|
+
file.documentEffect = file.documentEffect === 'unchanged' ? 'possible' : file.documentEffect;
|
|
52
|
+
if (!file.failureCodes.includes('write_observed_mismatch')) {
|
|
53
|
+
file.failureCodes.push('write_observed_mismatch');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return Array.from(byPath.values()).map(file => {
|
|
58
|
+
file.applied = file.appliedCount === file.operationCount
|
|
59
|
+
? 'complete'
|
|
60
|
+
: file.appliedCount > 0
|
|
61
|
+
? 'partial'
|
|
62
|
+
: file.failedCount > 0
|
|
63
|
+
? 'failed'
|
|
64
|
+
: 'none';
|
|
65
|
+
delete file.operationCount;
|
|
66
|
+
delete file.appliedCount;
|
|
67
|
+
delete file.failedCount;
|
|
68
|
+
return file;
|
|
69
|
+
}).sort((left, right) => left.path.localeCompare(right.path));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function normalizeFileReadbackEvidence(value = []) {
|
|
73
|
+
return (Array.isArray(value) ? value : [])
|
|
74
|
+
.filter(item => item && typeof item.path === 'string')
|
|
75
|
+
.map(item => ({
|
|
76
|
+
path: item.path,
|
|
77
|
+
state: ['match', 'mismatch', 'missing', 'unknown'].includes(item.state)
|
|
78
|
+
? item.state
|
|
79
|
+
: 'unknown'
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function deriveApplyResultReadbacks(applyResult = {}) {
|
|
84
|
+
const readbacksByPath = new Map();
|
|
85
|
+
const record = (path, state) => {
|
|
86
|
+
if (typeof path !== 'string' || !path) return;
|
|
87
|
+
const current = readbacksByPath.get(path);
|
|
88
|
+
if (current === 'mismatch') return;
|
|
89
|
+
if (state === 'mismatch' || !current) readbacksByPath.set(path, state);
|
|
90
|
+
};
|
|
91
|
+
for (const entry of [
|
|
92
|
+
...(Array.isArray(applyResult?.applied) ? applyResult.applied : []),
|
|
93
|
+
...(Array.isArray(applyResult?.skipped) ? applyResult.skipped : [])
|
|
94
|
+
]) {
|
|
95
|
+
const operation = entry?.operation || {};
|
|
96
|
+
const result = entry?.result || {};
|
|
97
|
+
const code = result?.failure?.code || result?.code || '';
|
|
98
|
+
const path = operation.type === 'rename' || operation.type === 'move'
|
|
99
|
+
? operation.to || operation.path
|
|
100
|
+
: operation.path;
|
|
101
|
+
if (code === 'write_observed_mismatch') {
|
|
102
|
+
record(path, 'mismatch');
|
|
103
|
+
} else if (result.verified === true) {
|
|
104
|
+
record(path, operation.type === 'delete' ? 'missing' : 'match');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return Array.from(readbacksByPath, ([path, state]) => ({ path, state }));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function deriveDocumentEffect(operationEvidence = []) {
|
|
111
|
+
if (operationEvidence.some(entry => entry.changedDocument === true)) return 'changed';
|
|
112
|
+
if (operationEvidence.some(entry => entry.mayHaveMutated === true)) return 'possibly-changed';
|
|
113
|
+
if (operationEvidence.length) return 'unchanged';
|
|
114
|
+
return 'unknown';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function deriveAppliedEvidence(operations = [], operationEvidence = []) {
|
|
118
|
+
const plannedCount = Array.isArray(operations) ? operations.length : 0;
|
|
119
|
+
const applied = operationEvidence.filter(entry => entry.collection === 'applied');
|
|
120
|
+
const skipped = operationEvidence.filter(entry => entry.collection === 'skipped');
|
|
121
|
+
const successful = applied.filter(entry => entry.ok !== false);
|
|
122
|
+
if (!plannedCount && !operationEvidence.length) return 'none';
|
|
123
|
+
if (!successful.length && (skipped.length || applied.some(entry => entry.ok === false))) return 'none';
|
|
124
|
+
if (successful.length && (skipped.length || applied.some(entry => entry.ok === false))) return 'partial';
|
|
125
|
+
if (successful.length && (!plannedCount || successful.length >= plannedCount)) return 'complete';
|
|
126
|
+
return successful.length ? 'partial' : 'unknown';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function deriveReadbackEvidence(fileSettlements = [], readbacks = []) {
|
|
130
|
+
if (!Array.isArray(readbacks) || !readbacks.length) return 'not-attempted';
|
|
131
|
+
const states = fileSettlements.map(file => file.readBack);
|
|
132
|
+
if (states.includes('mismatch')) return 'mismatch';
|
|
133
|
+
const exactCount = states.filter(state => state === 'match').length;
|
|
134
|
+
const unavailableCount = states.filter(state =>
|
|
135
|
+
state === 'missing' || state === 'unknown'
|
|
136
|
+
).length;
|
|
137
|
+
if (exactCount && unavailableCount) return 'partial';
|
|
138
|
+
if (exactCount && exactCount === states.length) return 'exact';
|
|
139
|
+
return 'unavailable';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return Object.freeze({
|
|
143
|
+
aggregateFileSettlements,
|
|
144
|
+
deriveAppliedEvidence,
|
|
145
|
+
deriveApplyResultReadbacks,
|
|
146
|
+
deriveDocumentEffect,
|
|
147
|
+
deriveReadbackEvidence,
|
|
148
|
+
normalizeFileReadbackEvidence
|
|
149
|
+
});
|
|
150
|
+
});
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
(function initCodexOverleafWritebackOperationEvidence(root, factory) {
|
|
2
|
+
if (typeof module === 'object' && module.exports) {
|
|
3
|
+
module.exports = factory();
|
|
4
|
+
} else {
|
|
5
|
+
root.CodexOverleafModuleRegistry.define('WritebackOperationEvidence', [], factory);
|
|
6
|
+
}
|
|
7
|
+
})(typeof window !== 'undefined' ? window : globalThis, function writebackOperationEvidenceFactory() {
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
function normalizeOperationEvidence(operations = [], applyResult = {}) {
|
|
11
|
+
const planned = Array.isArray(operations) ? operations : [];
|
|
12
|
+
const entries = [];
|
|
13
|
+
const claimedPlanned = new Set();
|
|
14
|
+
let fallbackCursor = 0;
|
|
15
|
+
|
|
16
|
+
const operationKey = operation => {
|
|
17
|
+
if (!operation || typeof operation !== 'object') return '';
|
|
18
|
+
return normalizeText(operation.id)
|
|
19
|
+
|| [
|
|
20
|
+
normalizeText(operation.type),
|
|
21
|
+
normalizeText(operation.path || operation.from),
|
|
22
|
+
normalizeText(operation.to || operation.destinationPath),
|
|
23
|
+
Number.isFinite(Number(operation.sequence)) ? Number(operation.sequence) : ''
|
|
24
|
+
].join(':');
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const claimPlannedOperation = explicitOperation => {
|
|
28
|
+
if (explicitOperation && typeof explicitOperation === 'object') {
|
|
29
|
+
const explicitKey = operationKey(explicitOperation);
|
|
30
|
+
const matchedIndex = planned.findIndex((operation, plannedIndex) =>
|
|
31
|
+
!claimedPlanned.has(plannedIndex) && operationKey(operation) === explicitKey
|
|
32
|
+
);
|
|
33
|
+
if (matchedIndex >= 0) claimedPlanned.add(matchedIndex);
|
|
34
|
+
return explicitOperation;
|
|
35
|
+
}
|
|
36
|
+
while (claimedPlanned.has(fallbackCursor)) fallbackCursor++;
|
|
37
|
+
if (fallbackCursor >= planned.length) return {};
|
|
38
|
+
const operation = planned[fallbackCursor];
|
|
39
|
+
claimedPlanned.add(fallbackCursor);
|
|
40
|
+
fallbackCursor++;
|
|
41
|
+
return operation;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const push = (entry, collection, index) => {
|
|
45
|
+
const operation = claimPlannedOperation(entry?.operation);
|
|
46
|
+
const result = entry?.result || entry || {};
|
|
47
|
+
const failure = normalizeFailure(result, operation);
|
|
48
|
+
const changedDocument = result.changedDocument === true
|
|
49
|
+
|| (collection === 'applied' && result.ok !== false);
|
|
50
|
+
const mayHaveMutated = changedDocument
|
|
51
|
+
|| result.mayHaveMutated === true
|
|
52
|
+
|| failure?.changedDocument === true;
|
|
53
|
+
entries.push({
|
|
54
|
+
operationId: normalizeText(operation.id) || `${collection}:${index}:${operation.type || 'unknown'}:${operation.path || operation.to || ''}`,
|
|
55
|
+
sequence: Number.isFinite(Number(operation.sequence)) ? Number(operation.sequence) : index,
|
|
56
|
+
path: normalizeText(operation.path || operation.from),
|
|
57
|
+
targetPath: normalizeText(operation.to || operation.destinationPath),
|
|
58
|
+
kind: normalizeText(operation.type) || 'unknown',
|
|
59
|
+
collection,
|
|
60
|
+
ok: result.ok !== false,
|
|
61
|
+
changedDocument,
|
|
62
|
+
mayHaveMutated,
|
|
63
|
+
failureCodes: failure?.code ? [failure.code] : [],
|
|
64
|
+
failures: failure ? [failure] : [],
|
|
65
|
+
trackedChanges: normalizeTrackedChanges(result.trackedChanges || entry?.trackedChanges),
|
|
66
|
+
undoIds: normalizeStringArray(result.undoIds || entry?.undoIds),
|
|
67
|
+
baseAvailable: operation.baseContent !== undefined || operation.expected !== undefined,
|
|
68
|
+
expectedAvailable: operation.expected !== undefined || result.verifiedContent !== undefined
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
(Array.isArray(applyResult?.applied) ? applyResult.applied : [])
|
|
72
|
+
.forEach((entry, index) => push(entry, 'applied', index));
|
|
73
|
+
(Array.isArray(applyResult?.skipped) ? applyResult.skipped : [])
|
|
74
|
+
.forEach((entry, index) => push(entry, 'skipped', index));
|
|
75
|
+
planned.forEach((operation, index) => {
|
|
76
|
+
if (claimedPlanned.has(index)) return;
|
|
77
|
+
const path = normalizeText(operation?.path || operation?.from || operation?.to);
|
|
78
|
+
push({
|
|
79
|
+
operation,
|
|
80
|
+
result: {
|
|
81
|
+
ok: false,
|
|
82
|
+
mayHaveMutated: false,
|
|
83
|
+
failure: {
|
|
84
|
+
code: 'write_result_missing',
|
|
85
|
+
stage: 'write',
|
|
86
|
+
severity: 'error',
|
|
87
|
+
userMessage: `No write result was returned for ${path || 'a planned operation'}.`,
|
|
88
|
+
retryable: true,
|
|
89
|
+
nextAction: 'Retry the task and review the Overleaf document before continuing.',
|
|
90
|
+
file: path,
|
|
91
|
+
operationType: normalizeText(operation?.type),
|
|
92
|
+
changedDocument: false,
|
|
93
|
+
terminalState: 'needs_review'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}, 'skipped', index);
|
|
97
|
+
});
|
|
98
|
+
return entries;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function normalizeFailure(result, operation) {
|
|
102
|
+
if (result?.failure && typeof result.failure === 'object') return cloneValue(result.failure);
|
|
103
|
+
if (!result?.code) return null;
|
|
104
|
+
return {
|
|
105
|
+
code: result.code,
|
|
106
|
+
stage: result.stage || 'write',
|
|
107
|
+
severity: result.severity || 'error',
|
|
108
|
+
userMessage: result.reason || result.message || result.code,
|
|
109
|
+
retryable: result.retryable === true,
|
|
110
|
+
file: operation?.path || operation?.to || '',
|
|
111
|
+
changedDocument: result.changedDocument === true,
|
|
112
|
+
terminalState: result.terminalState || ''
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function normalizeTrackedChanges(value) {
|
|
117
|
+
return (Array.isArray(value) ? value : []).map(item => ({
|
|
118
|
+
key: normalizeText(item?.key),
|
|
119
|
+
id: normalizeText(item?.id),
|
|
120
|
+
path: normalizeText(item?.path),
|
|
121
|
+
label: normalizeText(item?.label)
|
|
122
|
+
})).filter(item => item.key || item.id || item.path);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function normalizeStringArray(value) {
|
|
126
|
+
return (Array.isArray(value) ? value : []).map(normalizeText).filter(Boolean);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function cloneValue(value) {
|
|
130
|
+
if (value === undefined) return undefined;
|
|
131
|
+
return JSON.parse(JSON.stringify(value));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function normalizeText(value) {
|
|
135
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
normalizeFailure,
|
|
140
|
+
normalizeOperationEvidence,
|
|
141
|
+
normalizeTrackedChanges
|
|
142
|
+
};
|
|
143
|
+
});
|