codex-overleaf-link 2.3.1 → 2.3.2
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 +23 -23
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/src/content/assetTransferBroker.js +169 -0
- package/extension/src/content/contentRuntime.js +27 -1
- package/extension/src/content/generated/content.bundle.js +551 -65
- package/extension/src/content/generated/content.bundle.meta.json +6 -3
- package/extension/src/content/legacyGlobalRegistry.js +3 -0
- package/extension/src/content/modelPicker.js +2 -2
- package/extension/src/content/modelPickerSupport.js +3 -3
- package/extension/src/content/pageBridgeClient.js +1 -0
- package/extension/src/content/runResultActions.js +114 -0
- package/extension/src/content/runTimelineView.js +17 -0
- package/extension/src/content/sessionForkController.js +120 -0
- package/extension/src/content/writebackController.js +3 -0
- package/extension/src/content/writebackOrchestrator.js +3 -1
- package/extension/src/page/binaryAssetUploader.js +343 -0
- package/extension/src/page/trackedChangesLifecycle.js +2 -0
- package/extension/src/pageBridge.js +30 -1
- package/extension/src/shared/compatibility.js +4 -2
- package/extension/src/shared/i18n.js +16 -0
- package/extension/src/shared/models.js +13 -2
- package/extension/src/shared/pageRpcContract.js +5 -1
- package/extension/src/shared/sessionState.js +12 -4
- package/extension/src/shared/storageDb.js +1 -1
- package/extension/src/shared/storageRunActions.js +11 -1
- package/extension/styles/panel.css +61 -0
- package/native-host/src/codexModels.js +6 -2
- package/native-host/src/codexSessionRunner.js +5 -1
- package/native-host/src/codexThreadFork.js +103 -0
- package/native-host/src/mirrorWorkspace.js +5 -19
- package/native-host/src/nativeAssetTransfer.js +183 -0
- package/native-host/src/taskRunnerRuntime.js +22 -0
- package/package.json +1 -1
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"entry": "extension/entries/content-entry.mjs",
|
|
4
4
|
"output": "extension/src/content/generated/content.bundle.js",
|
|
5
|
-
"sourceDigest": "
|
|
6
|
-
"outputDigest": "
|
|
7
|
-
"byteLength":
|
|
5
|
+
"sourceDigest": "d2167fca49721d0ef5e477dc76b11a0cedb33c9f51b920b55ea666ab4668dc4c",
|
|
6
|
+
"outputDigest": "87cbcf7d9877860b7c1d047cd3fa6e985e28812c8df81c9105ec9312a5e45ea6",
|
|
7
|
+
"byteLength": 2309285,
|
|
8
8
|
"inputs": [
|
|
9
9
|
"extension/entries/content-entry.mjs",
|
|
10
10
|
"extension/src/content/activeTurnControl.js",
|
|
11
11
|
"extension/src/content/applyResultFormatters.js",
|
|
12
|
+
"extension/src/content/assetTransferBroker.js",
|
|
12
13
|
"extension/src/content/composerAttachments.js",
|
|
13
14
|
"extension/src/content/composerPanel.js",
|
|
14
15
|
"extension/src/content/contentRuntime.js",
|
|
@@ -45,11 +46,13 @@
|
|
|
45
46
|
"extension/src/content/runGuidanceController.js",
|
|
46
47
|
"extension/src/content/runGuidanceView.js",
|
|
47
48
|
"extension/src/content/runQueueScheduler.js",
|
|
49
|
+
"extension/src/content/runResultActions.js",
|
|
48
50
|
"extension/src/content/runSettlementPersistence.js",
|
|
49
51
|
"extension/src/content/runTimelineView.js",
|
|
50
52
|
"extension/src/content/scopedPersistenceCoordinator.js",
|
|
51
53
|
"extension/src/content/scopedPersistenceDetachedCommit.js",
|
|
52
54
|
"extension/src/content/scopedPersistencePanelState.js",
|
|
55
|
+
"extension/src/content/sessionForkController.js",
|
|
53
56
|
"extension/src/content/sessionManager.js",
|
|
54
57
|
"extension/src/content/sessionMenuView.js",
|
|
55
58
|
"extension/src/content/sessionPanel.js",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
'ActiveTurnControl',
|
|
16
16
|
'AgentTranscript',
|
|
17
17
|
'ApplyResultFormatters',
|
|
18
|
+
'AssetTransferBroker',
|
|
18
19
|
'AuditRecords',
|
|
19
20
|
'Compatibility',
|
|
20
21
|
'ComposerAttachments',
|
|
@@ -53,12 +54,14 @@
|
|
|
53
54
|
'RunGuidanceController',
|
|
54
55
|
'RunInputQueue',
|
|
55
56
|
'RunQueueScheduler',
|
|
57
|
+
'RunResultActions',
|
|
56
58
|
'RunSettlementPersistence',
|
|
57
59
|
'RunTimelineView',
|
|
58
60
|
'ScopedPersistenceCoordinator',
|
|
59
61
|
'ScopedPersistenceTransaction',
|
|
60
62
|
'SensitiveScan',
|
|
61
63
|
'SessionManager',
|
|
64
|
+
'SessionForkController',
|
|
62
65
|
'SessionPanel',
|
|
63
66
|
'SessionPersistence',
|
|
64
67
|
'SessionState',
|
|
@@ -452,8 +452,8 @@
|
|
|
452
452
|
if (effort === 'xhigh') return 'Max';
|
|
453
453
|
}
|
|
454
454
|
const labels = getLocale() === 'zh'
|
|
455
|
-
? { none: '关闭', minimal: '最小', low: '低', medium: '中', high: '高', xhigh: '超高' }
|
|
456
|
-
: { none: 'Off', minimal: 'Minimal', low: 'Low', medium: 'Medium', high: 'High', xhigh: 'XHigh' };
|
|
455
|
+
? { none: '关闭', minimal: '最小', low: '低', medium: '中', high: '高', xhigh: '超高', max: '最大', ultra: '极限' }
|
|
456
|
+
: { none: 'Off', minimal: 'Minimal', low: 'Low', medium: 'Medium', high: 'High', xhigh: 'XHigh', max: 'Max', ultra: 'Ultra' };
|
|
457
457
|
return labels[effort] || effort || '';
|
|
458
458
|
}
|
|
459
459
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function normalizeReasoningEffortsForSelect(efforts) {
|
|
22
|
-
const allowed = new Set(['none', 'minimal', 'low', 'medium', 'high', 'xhigh']);
|
|
22
|
+
const allowed = new Set(['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra']);
|
|
23
23
|
return Array.from(new Set((Array.isArray(efforts) ? efforts : [])
|
|
24
24
|
.map(effort => normalizeModelOptionId(effort))
|
|
25
25
|
.filter(effort => allowed.has(effort))));
|
|
@@ -92,12 +92,12 @@
|
|
|
92
92
|
const normalized = {
|
|
93
93
|
id,
|
|
94
94
|
label: typeof model?.label === 'string' && model.label.length > 0 ? model.label : id,
|
|
95
|
-
reasoningEfforts:
|
|
95
|
+
reasoningEfforts: normalizeReasoningEffortsForSelect(model?.reasoningEfforts),
|
|
96
96
|
reasoningPresentation: typeof model?.reasoningPresentation === 'string' ? model.reasoningPresentation : '',
|
|
97
97
|
speedTiers: normalizeSpeedTiersForSelect(model?.speedTiers)
|
|
98
98
|
};
|
|
99
99
|
if (Object.prototype.hasOwnProperty.call(Object(model), 'defaultReasoningEffort')) {
|
|
100
|
-
normalized.defaultReasoningEffort = model.defaultReasoningEffort;
|
|
100
|
+
normalized.defaultReasoningEffort = normalizeModelOptionId(model.defaultReasoningEffort);
|
|
101
101
|
}
|
|
102
102
|
if (Object.prototype.hasOwnProperty.call(Object(model), 'defaultSpeedTier')) {
|
|
103
103
|
normalized.defaultSpeedTier = model.defaultSpeedTier;
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
['src/page/overleafProjectSnapshot.js', 'codex-overleaf-project-snapshot-script'],
|
|
22
22
|
['src/page/pageBridgeCapability.js', 'codex-overleaf-page-bridge-capability-script'],
|
|
23
23
|
['src/page/treeOperations.js', 'codex-overleaf-tree-operations-script', true],
|
|
24
|
+
['src/page/binaryAssetUploader.js', 'codex-overleaf-binary-asset-uploader-script', true],
|
|
24
25
|
['src/page/snapshotRouter.js', 'codex-overleaf-snapshot-router-script'],
|
|
25
26
|
['src/page/writeGuard.js', 'codex-overleaf-write-guard-script', true],
|
|
26
27
|
['src/page/trackedChangesLifecycle.js', 'codex-overleaf-tracked-changes-lifecycle-script', true],
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
(function initCodexOverleafRunResultActions(root, factory) {
|
|
2
|
+
const api = factory();
|
|
3
|
+
if (typeof module === 'object' && module.exports) module.exports = api;
|
|
4
|
+
if (root) root.CodexOverleafRunResultActions = api;
|
|
5
|
+
})(typeof window !== 'undefined' ? window : globalThis, function runResultActionsFactory() {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function create(deps = {}) {
|
|
9
|
+
const {
|
|
10
|
+
tr,
|
|
11
|
+
getLocale,
|
|
12
|
+
forkRunFromNode,
|
|
13
|
+
document: documentRef = globalThis.document,
|
|
14
|
+
navigator: navigatorRef = globalThis.navigator
|
|
15
|
+
} = deps;
|
|
16
|
+
|
|
17
|
+
function configureResultActions(root, run) {
|
|
18
|
+
const actions = root.querySelector('.run-result-actions');
|
|
19
|
+
const reports = root.querySelectorAll('.run-completion-report');
|
|
20
|
+
const report = reports[reports.length - 1];
|
|
21
|
+
if (!actions || !report) return;
|
|
22
|
+
report.append(actions);
|
|
23
|
+
actions.hidden = false;
|
|
24
|
+
configureCopyButton(root);
|
|
25
|
+
configureForkButton(root, run);
|
|
26
|
+
configureCompletedTime(actions, run);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function configureForkButton(root, run) {
|
|
30
|
+
const existing = root.querySelector('[data-run-fork]');
|
|
31
|
+
const button = existing.cloneNode(true);
|
|
32
|
+
existing.replaceWith(button);
|
|
33
|
+
const available = run.forkSnapshot !== true
|
|
34
|
+
&& run.status !== 'running'
|
|
35
|
+
&& Boolean(run.codexTurnId)
|
|
36
|
+
&& typeof forkRunFromNode === 'function';
|
|
37
|
+
button.hidden = false;
|
|
38
|
+
button.disabled = !available;
|
|
39
|
+
button.title = tr(available ? 'forkRunTitle' : 'forkRunUnavailable');
|
|
40
|
+
button.setAttribute('aria-label', button.title);
|
|
41
|
+
button.innerHTML = '<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M3 10h3.5c3.5 0 4.2-4 7.5-4h2m-2.5-2.5L16 6l-2.5 2.5M6.5 10c3.5 0 4.2 4 7.5 4h2m-2.5-2.5L16 14l-2.5 2.5"/></svg>';
|
|
42
|
+
if (!available) return;
|
|
43
|
+
button.addEventListener('click', async event => {
|
|
44
|
+
event.stopPropagation();
|
|
45
|
+
button.disabled = true;
|
|
46
|
+
button.classList.add('is-running');
|
|
47
|
+
try {
|
|
48
|
+
await forkRunFromNode(run.id);
|
|
49
|
+
} catch (_error) {
|
|
50
|
+
button.disabled = false;
|
|
51
|
+
button.classList.remove('is-running');
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function configureCompletedTime(actions, run) {
|
|
57
|
+
const target = actions.querySelector('[data-run-completed-time]');
|
|
58
|
+
const finishedAt = String(run.finishedAt || '').trim();
|
|
59
|
+
const date = finishedAt ? new Date(finishedAt) : null;
|
|
60
|
+
if (!target || !date || !Number.isFinite(date.getTime())) return;
|
|
61
|
+
target.hidden = false;
|
|
62
|
+
target.textContent = new Intl.DateTimeFormat(getLocale(), {
|
|
63
|
+
hour: '2-digit',
|
|
64
|
+
minute: '2-digit'
|
|
65
|
+
}).format(date);
|
|
66
|
+
target.title = date.toLocaleString(getLocale());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function configureCopyButton(root) {
|
|
70
|
+
const existing = root.querySelector('[data-run-copy]');
|
|
71
|
+
const button = existing.cloneNode(true);
|
|
72
|
+
existing.replaceWith(button);
|
|
73
|
+
const finalAnswer = root.querySelector('.run-completion-report .run-final-answer');
|
|
74
|
+
const copyText = String(finalAnswer?.innerText || finalAnswer?.textContent || '').trim();
|
|
75
|
+
button.hidden = false;
|
|
76
|
+
button.disabled = !copyText;
|
|
77
|
+
button.title = tr('copyConclusionTitle');
|
|
78
|
+
button.setAttribute('aria-label', button.title);
|
|
79
|
+
button.innerHTML = '<svg viewBox="0 0 20 20" aria-hidden="true"><rect x="6.5" y="6.5" width="9" height="9" rx="2"/><path d="M13.5 6.5V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6.5a2 2 0 0 0 2 2h1.5"/></svg>';
|
|
80
|
+
if (!copyText) return;
|
|
81
|
+
button.addEventListener('click', async event => {
|
|
82
|
+
event.stopPropagation();
|
|
83
|
+
try {
|
|
84
|
+
await writeClipboardText(copyText);
|
|
85
|
+
button.title = tr('copyConclusionDone');
|
|
86
|
+
} catch (_error) {
|
|
87
|
+
button.title = tr('copyConclusionFailed');
|
|
88
|
+
}
|
|
89
|
+
button.setAttribute('aria-label', button.title);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function writeClipboardText(text) {
|
|
94
|
+
if (navigatorRef?.clipboard?.writeText) {
|
|
95
|
+
await navigatorRef.clipboard.writeText(text);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const textarea = documentRef.createElement('textarea');
|
|
99
|
+
textarea.value = text;
|
|
100
|
+
textarea.setAttribute('readonly', '');
|
|
101
|
+
textarea.style.position = 'fixed';
|
|
102
|
+
textarea.style.opacity = '0';
|
|
103
|
+
documentRef.body.append(textarea);
|
|
104
|
+
textarea.select();
|
|
105
|
+
const copied = documentRef.execCommand('copy');
|
|
106
|
+
textarea.remove();
|
|
107
|
+
if (!copied) throw new Error('clipboard_copy_failed');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return Object.freeze({ configureResultActions });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return Object.freeze({ create });
|
|
114
|
+
});
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
function create(deps = {}) {
|
|
14
14
|
const {
|
|
15
15
|
RunGuidanceView,
|
|
16
|
+
RunResultActions,
|
|
16
17
|
tr,
|
|
17
18
|
tx,
|
|
18
19
|
getLocale,
|
|
@@ -346,6 +347,11 @@
|
|
|
346
347
|
</summary>
|
|
347
348
|
</details>
|
|
348
349
|
<div class="run-activity-list" data-run-events></div>
|
|
350
|
+
<div class="run-result-actions" hidden>
|
|
351
|
+
<button type="button" class="run-copy-action" data-run-copy hidden></button>
|
|
352
|
+
<button type="button" class="run-fork-action" data-run-fork hidden></button>
|
|
353
|
+
<span class="run-completed-time" data-run-completed-time hidden></span>
|
|
354
|
+
</div>
|
|
349
355
|
<div class="run-report" data-run-report aria-live="polite" hidden></div>
|
|
350
356
|
</div>
|
|
351
357
|
`;
|
|
@@ -399,6 +405,7 @@
|
|
|
399
405
|
}
|
|
400
406
|
}
|
|
401
407
|
|
|
408
|
+
RunResultActions.configureResultActions(root, run);
|
|
402
409
|
configureAcceptButton(root, run);
|
|
403
410
|
configureUndoButton(root, run);
|
|
404
411
|
return root;
|
|
@@ -886,6 +893,11 @@
|
|
|
886
893
|
const button = existing.cloneNode(true);
|
|
887
894
|
existing.replaceWith(button);
|
|
888
895
|
|
|
896
|
+
if (run.forkSnapshot === true) {
|
|
897
|
+
button.hidden = true;
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
|
|
889
901
|
if (isTrackedChangeLifecycleRun(run)) {
|
|
890
902
|
configureLifecycleUndoButton(button, run);
|
|
891
903
|
return;
|
|
@@ -982,6 +994,11 @@
|
|
|
982
994
|
const button = existing.cloneNode(true);
|
|
983
995
|
existing.replaceWith(button);
|
|
984
996
|
|
|
997
|
+
if (run.forkSnapshot === true) {
|
|
998
|
+
button.hidden = true;
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
985
1002
|
if (!isTrackedChangeLifecycleRun(run)) {
|
|
986
1003
|
button.hidden = true;
|
|
987
1004
|
return;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
(function initCodexOverleafSessionForkController(root, factory) {
|
|
2
|
+
const api = factory();
|
|
3
|
+
if (typeof module === 'object' && module.exports) module.exports = api;
|
|
4
|
+
if (root) root.CodexOverleafSessionForkController = api;
|
|
5
|
+
})(typeof window !== 'undefined' ? window : globalThis, function sessionForkControllerFactory() {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function create(deps = {}) {
|
|
9
|
+
const {
|
|
10
|
+
SessionState, getState, setState, sendBackgroundNative, saveState,
|
|
11
|
+
applyStateToPanel, showPluginToast, tr
|
|
12
|
+
} = deps;
|
|
13
|
+
|
|
14
|
+
async function forkRunFromNode(runId) {
|
|
15
|
+
const previousState = getState();
|
|
16
|
+
const source = findSource(previousState, runId);
|
|
17
|
+
if (!source) return failFork('session_fork_source_missing', tr('forkRunUnavailable'));
|
|
18
|
+
const { session, run, runIndex } = source;
|
|
19
|
+
if (run.status === 'running' || !session.codexThreadId || !run.codexTurnId) {
|
|
20
|
+
return failFork('session_fork_unavailable', tr('forkRunUnavailable'));
|
|
21
|
+
}
|
|
22
|
+
const response = await sendBackgroundNative({
|
|
23
|
+
method: 'codex.thread.fork',
|
|
24
|
+
params: {
|
|
25
|
+
threadId: session.codexThreadId,
|
|
26
|
+
lastTurnId: run.codexTurnId,
|
|
27
|
+
speedTier: session.speedTier,
|
|
28
|
+
loadCodexLocalSkills: previousState.loadCodexLocalSkills !== false,
|
|
29
|
+
loadCodexOverleafSkills: previousState.loadCodexOverleafSkills !== false
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
if (!response?.ok || !response.result?.threadId) {
|
|
33
|
+
return failFork(response?.error?.code || 'session_fork_failed', response?.error?.message || tr('forkRunFailed'));
|
|
34
|
+
}
|
|
35
|
+
const copiedRuns = session.runs.slice(0, runIndex + 1).map(copyRunSnapshot);
|
|
36
|
+
const titleBase = String(session.title || copiedRuns[0]?.task || tr('newSessionFallback')).trim();
|
|
37
|
+
const forkTitle = buildUniqueForkTitle(previousState.sessions, titleBase);
|
|
38
|
+
const forked = SessionState.createSession({
|
|
39
|
+
title: forkTitle,
|
|
40
|
+
titleSource: 'manual',
|
|
41
|
+
runs: copiedRuns,
|
|
42
|
+
task: '',
|
|
43
|
+
mode: session.mode,
|
|
44
|
+
providerId: session.providerId,
|
|
45
|
+
model: session.model,
|
|
46
|
+
reasoningEffort: session.reasoningEffort,
|
|
47
|
+
speedTier: session.speedTier,
|
|
48
|
+
requireReviewing: session.requireReviewing,
|
|
49
|
+
focusFiles: session.focusFiles,
|
|
50
|
+
projectReferenceFiles: session.projectReferenceFiles,
|
|
51
|
+
codexThreadId: response.result.threadId,
|
|
52
|
+
pendingInputs: [],
|
|
53
|
+
forkedFromSessionId: session.id,
|
|
54
|
+
forkedFromRunId: run.id
|
|
55
|
+
});
|
|
56
|
+
setState(SessionState.normalizePanelState({
|
|
57
|
+
...previousState,
|
|
58
|
+
sessions: [...(previousState.sessions || []), forked],
|
|
59
|
+
activeSessionId: forked.id
|
|
60
|
+
}));
|
|
61
|
+
try {
|
|
62
|
+
await saveState();
|
|
63
|
+
} catch (error) {
|
|
64
|
+
setState(previousState);
|
|
65
|
+
await sendBackgroundNative({
|
|
66
|
+
method: 'codex.history.clearPlugin',
|
|
67
|
+
params: { sessionId: forked.id, threadId: response.result.threadId }
|
|
68
|
+
}).catch(() => null);
|
|
69
|
+
showPluginToast(error.message || tr('forkRunFailed'), { status: 'failed', sticky: true });
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
applyStateToPanel();
|
|
73
|
+
showPluginToast(tr('forkRunDone'), { status: 'completed' });
|
|
74
|
+
return forked;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function failFork(code, message) {
|
|
78
|
+
showPluginToast(message, { status: 'failed', sticky: true });
|
|
79
|
+
throw codedError(code, message);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return { forkRunFromNode };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function buildUniqueForkTitle(sessions = [], sourceTitle = '') {
|
|
86
|
+
const fallback = String(sourceTitle || 'New Session').trim() || 'New Session';
|
|
87
|
+
const baseTitle = fallback
|
|
88
|
+
.replace(/\s+\(fork\)$/i, '')
|
|
89
|
+
.replace(/\s+\(\d+\)$/, '')
|
|
90
|
+
.trim() || fallback;
|
|
91
|
+
const usedTitles = new Set((sessions || []).map(session => String(session?.title || '').trim()));
|
|
92
|
+
let index = 1;
|
|
93
|
+
while (usedTitles.has(`${baseTitle} (${index})`)) index += 1;
|
|
94
|
+
return `${baseTitle} (${index})`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function findSource(state, runId) {
|
|
98
|
+
for (const session of state?.sessions || []) {
|
|
99
|
+
const runIndex = (session.runs || []).findIndex(run => run.id === runId);
|
|
100
|
+
if (runIndex >= 0) return { session, run: session.runs[runIndex], runIndex };
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function copyRunSnapshot(run) {
|
|
106
|
+
const copy = JSON.parse(JSON.stringify(run || {}));
|
|
107
|
+
return {
|
|
108
|
+
...copy,
|
|
109
|
+
id: `fork_${String(copy.id || 'run')}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`,
|
|
110
|
+
forkSnapshot: true,
|
|
111
|
+
forkSourceRunId: String(copy.id || ''),
|
|
112
|
+
attachments: [], appliedOperations: [], undoOperations: [], undoBaseFiles: [],
|
|
113
|
+
undoTrackedChanges: [], undoExpectedFiles: [], undoStatus: '',
|
|
114
|
+
trackedChangeStatus: '', nativeRequestId: '', queueItemId: '', interruptedDraft: undefined
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function codedError(code, message) { const error = new Error(message); error.code = code; return error; }
|
|
119
|
+
return { copyRunSnapshot, create };
|
|
120
|
+
});
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
type: change.type,
|
|
16
16
|
path: change.path,
|
|
17
17
|
contentBase64: change.contentBase64 || '',
|
|
18
|
+
assetRef: change.assetRef && typeof change.assetRef === 'object' ? { ...change.assetRef } : undefined,
|
|
19
|
+
sha256: change.sha256 || change.assetRef?.sha256 || '',
|
|
20
|
+
mimeType: change.mimeType || change.assetRef?.mimeType || '',
|
|
18
21
|
size: Number.isFinite(Number(change.size)) ? Number(change.size) : undefined,
|
|
19
22
|
previousExists: change.previousExists === true,
|
|
20
23
|
previousKind: change.previousKind || '',
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
let onMirrorRefreshSettled;
|
|
62
62
|
let writebackSettlement;
|
|
63
63
|
let injectedWritebackSettlement;
|
|
64
|
+
let assetTransferBroker;
|
|
64
65
|
|
|
65
66
|
function buildSettlement(input = {}) {
|
|
66
67
|
return writebackSettlement?.settle instanceof Function
|
|
@@ -283,7 +284,7 @@
|
|
|
283
284
|
};
|
|
284
285
|
}
|
|
285
286
|
const applied = operations.length
|
|
286
|
-
? mergeApplyResultSkipped(await
|
|
287
|
+
? mergeApplyResultSkipped(await assetTransferBroker.applyOperations({
|
|
287
288
|
operations,
|
|
288
289
|
baseFiles: project?.files || [],
|
|
289
290
|
requireReviewing: runRequireReviewing,
|
|
@@ -859,6 +860,7 @@
|
|
|
859
860
|
getState,
|
|
860
861
|
getCurrentRunView,
|
|
861
862
|
} = deps);
|
|
863
|
+
assetTransferBroker = deps.assetTransferBroker;
|
|
862
864
|
onMirrorRefreshSettled = deps.onMirrorRefreshSettled;
|
|
863
865
|
writebackSettlement = deps.writebackSettlement;
|
|
864
866
|
compileAdapter = deps.compileAdapter;
|