codex-overleaf-link 2.5.1 → 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.
- package/README.md +149 -398
- package/README.zh-CN.md +153 -404
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/src/background.js +78 -3
- package/extension/src/backgroundSharedSessions.js +55 -2
- package/extension/src/backgroundUpdateCoordinator.js +128 -12
- package/extension/src/content/activeTurnControl.js +164 -7
- package/extension/src/content/composerAttachments.js +11 -2
- package/extension/src/content/composerPanel.js +92 -12
- package/extension/src/content/contentRuntime.js +920 -276
- package/extension/src/content/contextTray.js +8 -2
- package/extension/src/content/contextUsageView.js +267 -0
- package/extension/src/content/diagnosticsPanel.js +18 -0
- package/extension/src/content/generated/content.bundle.js +4496 -924
- package/extension/src/content/generated/content.bundle.meta.json +6 -3
- package/extension/src/content/legacyGlobalRegistry.js +4 -0
- package/extension/src/content/localSkillsPanel.js +2 -2
- package/extension/src/content/markdownDomRenderer.js +5 -3
- package/extension/src/content/markdownText.js +42 -5
- package/extension/src/content/modelPicker.js +1 -0
- package/extension/src/content/nativeCompatibilityController.js +29 -10
- package/extension/src/content/otWarmMirror.js +1 -1
- package/extension/src/content/pageBridgeClient.js +2 -2
- package/extension/src/content/panelMaintenance.js +6 -2
- package/extension/src/content/panelRenderer.js +51 -27
- package/extension/src/content/pendingInputView.js +1 -1
- package/extension/src/content/projectSettingsCoordinator.js +30 -6
- package/extension/src/content/providerSettingsDialog.js +2 -1
- package/extension/src/content/recentProjects.js +4 -3
- package/extension/src/content/runActivitySummary.js +122 -14
- package/extension/src/content/runCompletionMeta.js +194 -6
- package/extension/src/content/runController.js +2 -1
- package/extension/src/content/runFailureNotice.js +8 -1
- package/extension/src/content/runPresence.js +18 -8
- package/extension/src/content/runQueueScheduler.js +9 -5
- package/extension/src/content/runRecoveryActions.js +2 -1
- package/extension/src/content/runResultActions.js +22 -20
- package/extension/src/content/runReviewController.js +94 -35
- package/extension/src/content/runTimelineView.js +224 -25
- package/extension/src/content/scopedPersistencePanelState.js +92 -23
- package/extension/src/content/sensitivePreflight.js +14 -1
- package/extension/src/content/sessionManager.js +49 -3
- package/extension/src/content/sessionMenuView.js +54 -18
- package/extension/src/content/sessionPersistence.js +25 -5
- package/extension/src/content/settingsPanel.js +15 -2
- package/extension/src/content/settingsWorkbench.js +127 -89
- package/extension/src/content/sharedSessionViewSync.js +4 -3
- package/extension/src/content/subagentActivityView.js +23 -7
- package/extension/src/content/updateNotice.js +60 -6
- package/extension/src/content/writebackOrchestrator.js +35 -22
- package/extension/src/page/compileBridge.js +193 -180
- package/extension/src/page/overleafCapabilities.js +4 -1
- package/extension/src/page/textCoordinates.js +17 -1
- package/extension/src/page/textFileCreator.js +9 -1
- package/extension/src/page/writebackRouter.js +24 -77
- package/extension/src/pageBridge.js +107 -66
- package/extension/src/popup.js +1 -1
- package/extension/src/shared/agentTranscript.js +350 -17
- package/extension/src/shared/auditRecords.js +2 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/compileAdapter.js +58 -17
- package/extension/src/shared/composerAttachmentDraft.js +6 -1
- package/extension/src/shared/contextUsage.js +125 -0
- package/extension/src/shared/failureReasons.js +42 -3
- package/extension/src/shared/i18n.js +299 -29
- package/extension/src/shared/lineReferences.js +38 -31
- package/extension/src/shared/pageRpcContract.js +1 -1
- package/extension/src/shared/panelIcons.js +39 -0
- package/extension/src/shared/reviewing.js +130 -1
- package/extension/src/shared/runActivityModel.js +70 -4
- package/extension/src/shared/runExecutionSnapshot.js +13 -0
- package/extension/src/shared/sessionState.js +63 -4
- package/extension/src/shared/sessionTitle.js +14 -1
- package/extension/src/shared/sharedSessionBridge.js +81 -13
- package/extension/src/shared/staleGuard.js +72 -63
- package/extension/src/shared/storageDb.js +35 -3
- package/extension/src/shared/storageMigration.js +7 -1
- package/extension/src/shared/storageRunActions.js +62 -8
- package/extension/src/shared/undoOperations.js +126 -28
- package/extension/src/shared/updateRuntimeIdentity.js +16 -2
- package/extension/src/shared/writebackSettlement.js +21 -3
- package/extension/styles/panel.css +1106 -490
- package/native-host/src/bootstrapUpdate.js +52 -16
- package/native-host/src/chatBridgeRequest.js +60 -6
- package/native-host/src/chatBridgeResponse.js +10 -1
- package/native-host/src/chatCompletionsBridge.js +29 -2
- package/native-host/src/codexPromptAssembly.js +86 -118
- package/native-host/src/codexSessionRunner.js +126 -17
- package/native-host/src/providerContextError.js +20 -0
- package/native-host/src/taskRunnerRuntime.js +18 -6
- package/native-host/src/textPatch.js +473 -377
- package/native-host/src/updateManager.js +120 -15
- package/package.json +5 -8
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
})(typeof window !== 'undefined' ? window : globalThis, function sensitivePreflightFactory() {
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
+
// Report evidence admits detector identities only, never matched text or previews.
|
|
11
|
+
const REPORT_DETECTOR_IDS = new Set(['private-key', 'bearer-token', 'api-token', 'aws-access-key',
|
|
12
|
+
'google-api-key', 'huggingface-token', 'gitlab-token', 'stripe-live-secret', 'jwt-token', 'secret-assignment']);
|
|
13
|
+
|
|
10
14
|
function create({
|
|
11
15
|
SensitiveScan, normalizeGovernanceRules, isTextSnapshotFile, sendBackgroundNative,
|
|
12
16
|
getCurrentProjectId, appendRunEvent, appendCompletionReport, showPluginConfirm, tr, tx
|
|
@@ -62,12 +66,21 @@
|
|
|
62
66
|
}
|
|
63
67
|
// Blocking an extra message must not finish the task already in progress.
|
|
64
68
|
if (guidance) return { blocked: true, findings };
|
|
65
|
-
|
|
69
|
+
const detectorIds = [...new Set(findings.map(finding => finding?.detectorId))];
|
|
70
|
+
appendCompletionReport({ conclusionKey: 'sensitive_blocked',
|
|
66
71
|
conclusion: tx(
|
|
67
72
|
'This run was blocked before Codex received project context because sensitive content was detected.',
|
|
68
73
|
'检测到敏感内容,本轮已在向 Codex 发送项目上下文前阻止。'
|
|
69
74
|
),
|
|
70
75
|
status: 'blocked',
|
|
76
|
+
unchangedReason: tx('Sensitive content was found before sending.', '发送前发现了敏感内容。'),
|
|
77
|
+
failure: { code: 'sensitive_content_blocked', stage: 'preflight', severity: 'blocked',
|
|
78
|
+
retryable: false, changedDocument: false,
|
|
79
|
+
evidence: {
|
|
80
|
+
// An unknown type makes the cause generic, even alongside one known type.
|
|
81
|
+
detectorIds: detectorIds.every(id => REPORT_DETECTOR_IDS.has(id)) ? detectorIds.slice(0, 5) : [],
|
|
82
|
+
findingCount: findings.length
|
|
83
|
+
} },
|
|
71
84
|
operations: [],
|
|
72
85
|
applyResults: [],
|
|
73
86
|
nextStep: tx(
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
const {
|
|
12
12
|
SessionPanel,
|
|
13
13
|
SessionState,
|
|
14
|
-
SessionMenuView
|
|
14
|
+
SessionMenuView,
|
|
15
|
+
PanelIcons
|
|
15
16
|
} = deps;
|
|
16
17
|
const {
|
|
17
18
|
createSession,
|
|
@@ -30,6 +31,9 @@
|
|
|
30
31
|
saveState,
|
|
31
32
|
saveStateSoon,
|
|
32
33
|
readPanelInputs,
|
|
34
|
+
flushComposerDraft,
|
|
35
|
+
setSessionTransition,
|
|
36
|
+
getDraftScope,
|
|
33
37
|
applyStateToPanel,
|
|
34
38
|
syncSessionProvider,
|
|
35
39
|
getPanel,
|
|
@@ -47,6 +51,7 @@
|
|
|
47
51
|
getActiveSession,
|
|
48
52
|
getPanel,
|
|
49
53
|
getSessionDisplayTitle,
|
|
54
|
+
icons: PanelIcons,
|
|
50
55
|
getState,
|
|
51
56
|
isDisplayableSession,
|
|
52
57
|
isSessionRunning,
|
|
@@ -60,7 +65,31 @@
|
|
|
60
65
|
closeSessionMenu
|
|
61
66
|
} = sessionMenuView;
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
let transitionToken = null;
|
|
69
|
+
|
|
70
|
+
async function withSessionTransition(change) {
|
|
71
|
+
if (transitionToken) return;
|
|
72
|
+
const token = {};
|
|
73
|
+
transitionToken = token;
|
|
74
|
+
const scope = getDraftScope?.();
|
|
75
|
+
try {
|
|
76
|
+
// Lock before the first wait, including an outstanding IME commit.
|
|
77
|
+
await setSessionTransition?.(true);
|
|
78
|
+
if (getDraftScope?.() !== scope) return;
|
|
79
|
+
return await change(scope);
|
|
80
|
+
} finally {
|
|
81
|
+
if (transitionToken === token) {
|
|
82
|
+
transitionToken = null;
|
|
83
|
+
setSessionTransition?.(false);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function startNewSession() {
|
|
89
|
+
return withSessionTransition(createNewSession);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function createNewSession(draftScope) {
|
|
64
93
|
// Leaving a still-running session is allowed but never silent: the run
|
|
65
94
|
// keeps going in the background and lands in its own session.
|
|
66
95
|
const runningActive = getActiveSession(getState());
|
|
@@ -74,7 +103,10 @@
|
|
|
74
103
|
return;
|
|
75
104
|
}
|
|
76
105
|
}
|
|
106
|
+
if (getDraftScope?.() !== draftScope) return;
|
|
77
107
|
readPanelInputs();
|
|
108
|
+
await flushComposerDraft?.();
|
|
109
|
+
if (getDraftScope?.() !== draftScope) return;
|
|
78
110
|
// Reuse an already-empty, idle active session instead of minting a ghost.
|
|
79
111
|
// Empty sessions are invisible in the list yet still consume the storage cap
|
|
80
112
|
// (slice(-20) / maxSessions), so spamming "New Session" could silently evict
|
|
@@ -99,6 +131,7 @@
|
|
|
99
131
|
if (!evictionApproved) {
|
|
100
132
|
return;
|
|
101
133
|
}
|
|
134
|
+
if (getDraftScope?.() !== draftScope) return;
|
|
102
135
|
}
|
|
103
136
|
const session = createSession({
|
|
104
137
|
mode: getState().mode,
|
|
@@ -114,15 +147,22 @@
|
|
|
114
147
|
activeSessionId: session.id
|
|
115
148
|
}));
|
|
116
149
|
applyStateToPanel();
|
|
150
|
+
const destinationScope = getDraftScope?.();
|
|
117
151
|
await syncSessionProvider?.();
|
|
152
|
+
if (getDraftScope?.() !== destinationScope) return;
|
|
118
153
|
await saveState();
|
|
154
|
+
if (getDraftScope?.() !== destinationScope) return;
|
|
119
155
|
getPanel().querySelector('[data-task]')?.focus();
|
|
120
156
|
}
|
|
121
157
|
|
|
122
|
-
|
|
158
|
+
function switchSession(sessionId) {
|
|
123
159
|
if (sessionId === getState().activeSessionId) {
|
|
124
160
|
return;
|
|
125
161
|
}
|
|
162
|
+
return withSessionTransition(scope => switchToSession(sessionId, scope));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function switchToSession(sessionId, draftScope) {
|
|
126
166
|
const runningActive = getActiveSession(getState());
|
|
127
167
|
if (runningActive && isSessionRunning(runningActive)) {
|
|
128
168
|
const approved = await showPluginConfirm({
|
|
@@ -134,10 +174,15 @@
|
|
|
134
174
|
return;
|
|
135
175
|
}
|
|
136
176
|
}
|
|
177
|
+
if (getDraftScope?.() !== draftScope) return;
|
|
137
178
|
readPanelInputs();
|
|
179
|
+
await flushComposerDraft?.();
|
|
180
|
+
if (getDraftScope?.() !== draftScope) return;
|
|
138
181
|
setState(setActiveSession(getState(), sessionId));
|
|
139
182
|
applyStateToPanel();
|
|
183
|
+
const destinationScope = getDraftScope?.();
|
|
140
184
|
await syncSessionProvider?.();
|
|
185
|
+
if (getDraftScope?.() !== destinationScope) return;
|
|
141
186
|
await saveState();
|
|
142
187
|
}
|
|
143
188
|
|
|
@@ -295,6 +340,7 @@
|
|
|
295
340
|
bindActiveSessionHeader,
|
|
296
341
|
startNewSession,
|
|
297
342
|
switchSession,
|
|
343
|
+
isTransitioning: () => transitionToken !== null,
|
|
298
344
|
deleteSessionWithConfirm,
|
|
299
345
|
renderSessionList,
|
|
300
346
|
commitSessionRename,
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
getPanel,
|
|
12
12
|
getSessionDisplayTitle,
|
|
13
13
|
getState,
|
|
14
|
+
icons = null,
|
|
14
15
|
isDisplayableSession,
|
|
15
16
|
isSessionRunning,
|
|
16
17
|
startNewSession,
|
|
@@ -20,19 +21,20 @@
|
|
|
20
21
|
|
|
21
22
|
function applySessionLabel() {
|
|
22
23
|
const trigger = getPanel().querySelector('[data-session-menu-trigger]');
|
|
23
|
-
if (trigger) {
|
|
24
|
-
trigger.title = tr('sessionMenuOpen');
|
|
25
|
-
trigger.setAttribute('aria-label', tr('sessionMenuOpen'));
|
|
26
|
-
}
|
|
27
24
|
const textNode = getPanel().querySelector('[data-session-label-text]');
|
|
28
25
|
const deleteButton = getPanel().querySelector('[data-session-delete]');
|
|
29
26
|
const renameButton = getPanel().querySelector('[data-session-rename]');
|
|
30
27
|
const renameInput = getPanel().querySelector('[data-session-rename-input]');
|
|
31
28
|
const active = getActiveSession(getState());
|
|
29
|
+
const label = active && isDisplayableSession(active)
|
|
30
|
+
? getSessionDisplayTitle(active)
|
|
31
|
+
: tr('newSessionFallback');
|
|
32
32
|
if (textNode) {
|
|
33
|
-
textNode.textContent =
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
textNode.textContent = label;
|
|
34
|
+
}
|
|
35
|
+
if (trigger) {
|
|
36
|
+
trigger.title = `${label} · ${tr('sessionMenuOpen')}`;
|
|
37
|
+
trigger.setAttribute('aria-label', `${tr('sessionMenuOpen')}: ${label}`);
|
|
36
38
|
}
|
|
37
39
|
if (deleteButton) {
|
|
38
40
|
const running = active ? isSessionRunning(active) : false;
|
|
@@ -111,11 +113,15 @@
|
|
|
111
113
|
.slice()
|
|
112
114
|
.sort((a, b) => String(b.updatedAt || b.createdAt || '').localeCompare(String(a.updatedAt || a.createdAt || '')));
|
|
113
115
|
for (const session of sessions) {
|
|
114
|
-
const row = document.createElement('
|
|
115
|
-
row.type = 'button';
|
|
116
|
+
const row = document.createElement('div');
|
|
116
117
|
row.className = 'codex-session-menu-item';
|
|
118
|
+
row.setAttribute('role', 'none');
|
|
117
119
|
row.dataset.active = session.id === state?.activeSessionId ? 'true' : 'false';
|
|
118
120
|
row.dataset.running = isSessionRunning(session) ? 'true' : 'false';
|
|
121
|
+
const switchButton = document.createElement('button');
|
|
122
|
+
switchButton.type = 'button';
|
|
123
|
+
switchButton.className = 'codex-session-menu-switch';
|
|
124
|
+
switchButton.setAttribute('role', 'menuitem');
|
|
119
125
|
const title = document.createElement('span');
|
|
120
126
|
title.className = 'codex-session-menu-item-title';
|
|
121
127
|
title.textContent = getSessionDisplayTitle(session);
|
|
@@ -127,26 +133,56 @@
|
|
|
127
133
|
if (absoluteTs) {
|
|
128
134
|
time.title = new Date(absoluteTs).toLocaleString();
|
|
129
135
|
}
|
|
130
|
-
|
|
131
|
-
|
|
136
|
+
switchButton.append(title, time);
|
|
137
|
+
switchButton.addEventListener('click', event => {
|
|
132
138
|
event.stopPropagation();
|
|
133
139
|
closeSessionMenu();
|
|
134
140
|
if (session.id !== getState()?.activeSessionId) {
|
|
135
141
|
switchSession(session.id);
|
|
136
142
|
}
|
|
137
143
|
});
|
|
144
|
+
const deleteButton = menuAction('codex-session-menu-item-delete', 'close', '',
|
|
145
|
+
row.dataset.running === 'true' ? tr('deleteRunningSession') : tr('deleteSession'),
|
|
146
|
+
() => deleteSessionWithConfirm(session.id));
|
|
147
|
+
deleteButton.setAttribute('role', 'menuitem');
|
|
148
|
+
deleteButton.disabled = row.dataset.running === 'true';
|
|
149
|
+
row.append(switchButton, deleteButton);
|
|
138
150
|
menu.append(row);
|
|
139
151
|
}
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
152
|
+
const footer = document.createElement('div');
|
|
153
|
+
footer.className = 'codex-session-menu-footer';
|
|
154
|
+
const active = getActiveSession(state);
|
|
155
|
+
const running = active ? isSessionRunning(active) : false;
|
|
156
|
+
const soleEmpty = Boolean(active) && !isDisplayableSession(active) && (state?.sessions || []).length <= 1;
|
|
157
|
+
const createButton = menuAction('codex-session-menu-new', 'plus', tr('sessionMenuNewShort'), tr('newSession'), () => startNewSession());
|
|
158
|
+
const renameButton = menuAction('codex-session-menu-rename', 'pencil', tr('sessionMenuRenameShort'), tr('renameSession'), () => beginActiveSessionRename());
|
|
159
|
+
renameButton.disabled = !active;
|
|
160
|
+
const deleteButton = menuAction('codex-session-menu-delete', 'close', tr('sessionMenuDeleteShort'),
|
|
161
|
+
running ? tr('deleteRunningSession') : tr('deleteSession'), () => {
|
|
162
|
+
if (getState()?.activeSessionId) deleteSessionWithConfirm(getState().activeSessionId);
|
|
163
|
+
});
|
|
164
|
+
deleteButton.disabled = !active || running || soleEmpty;
|
|
165
|
+
footer.append(createButton, renameButton, deleteButton);
|
|
166
|
+
menu.append(footer);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function menuAction(className, iconName, label, description, onSelect) {
|
|
170
|
+
const button = document.createElement('button');
|
|
171
|
+
button.type = 'button';
|
|
172
|
+
button.className = className;
|
|
173
|
+
button.title = description;
|
|
174
|
+
button.setAttribute('aria-label', description);
|
|
175
|
+
const glyph = icons?.svg?.(iconName);
|
|
176
|
+
if (glyph) button.insertAdjacentHTML('beforeend', glyph);
|
|
177
|
+
const text = document.createElement('span');
|
|
178
|
+
text.textContent = label;
|
|
179
|
+
button.append(text);
|
|
180
|
+
button.addEventListener('click', event => {
|
|
145
181
|
event.stopPropagation();
|
|
146
182
|
closeSessionMenu();
|
|
147
|
-
|
|
183
|
+
onSelect();
|
|
148
184
|
});
|
|
149
|
-
|
|
185
|
+
return button;
|
|
150
186
|
}
|
|
151
187
|
|
|
152
188
|
function beginActiveSessionRename() {
|
|
@@ -74,20 +74,40 @@
|
|
|
74
74
|
.filter(record => !deleted.has(record.id))
|
|
75
75
|
.map(record => [record.id, record]));
|
|
76
76
|
const mergedRecords = sessionRecords.map(record => StorageDb.mergeSessionReviewState?.(
|
|
77
|
-
record, existingById.get(record.id), options.reviewRunIds
|
|
77
|
+
record, existingById.get(record.id), options.reviewRunIds, { shared: StorageDb.sharedSessionsEnabled?.() === true }
|
|
78
78
|
) || record);
|
|
79
|
+
const reviewRunIds = new Set(options.reviewRunIds || []);
|
|
80
|
+
// Shared storage merges local edits and explicitly requested Undo markers
|
|
81
|
+
// against the page baseline. Legacy and ordinary stale saves keep the age guard.
|
|
79
82
|
const writable = mergedRecords.filter(record => {
|
|
80
83
|
const existing = existingById.get(record.id);
|
|
81
84
|
if (!existing) return true;
|
|
82
|
-
return (Date.parse(record.updatedAt || '') || 0) >= (Date.parse(existing.updatedAt || '') || 0)
|
|
85
|
+
return (Date.parse(record.updatedAt || '') || 0) >= (Date.parse(existing.updatedAt || '') || 0)
|
|
86
|
+
|| (StorageDb.sharedSessionsEnabled?.() === true
|
|
87
|
+
&& (StorageDb.hasUnpersistedSharedSession?.(record) === true
|
|
88
|
+
|| (record.runs || []).some(run => reviewRunIds.has(run.id) && run.undoOwnerProtocol === 1)));
|
|
83
89
|
});
|
|
84
90
|
const cleanedExisting = existingSessions.filter((record, index) =>
|
|
85
91
|
record !== rawExistingSessions[index] && !writable.some(item => item.id === record.id)
|
|
86
92
|
);
|
|
87
93
|
if (cleanedExisting.length || writable.length) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
const reviewReceipts = [];
|
|
95
|
+
if (StorageDb.sharedSessionsEnabled?.() === true && reviewRunIds.size) {
|
|
96
|
+
for (const record of writable) {
|
|
97
|
+
const ids = (record.runs || []).filter(run => reviewRunIds.has(run.id)).map(run => run.id);
|
|
98
|
+
if (ids.length) reviewReceipts.push(await StorageDb.putSessionReviewState(record, ids));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
let written;
|
|
102
|
+
try {
|
|
103
|
+
written = await StorageDb.putRecords('sessions', [...cleanedExisting, ...writable], {
|
|
104
|
+
reviewRunIds: options.reviewRunIds, reviewReceipts
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (error.code === 'shared_session_conflict' && reviewReceipts.length)
|
|
108
|
+
Object.defineProperty(error, 'reviewReceipts', { value: reviewReceipts, configurable: true });
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
91
111
|
// Check the actual durable result, including a decision already saved
|
|
92
112
|
// from another origin, instead of acknowledging only the proposed view.
|
|
93
113
|
return written.filter(record => writable.some(candidate => candidate.id === record.id));
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
function codexIcon(name) {
|
|
11
11
|
const icons = {
|
|
12
|
+
archive: '<rect x="2.5" y="3" width="11" height="3.2" rx=".8"/><path d="M3.5 6.2v6.3a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1V6.2"/><path d="M6.5 9h3"/>',
|
|
12
13
|
appearance: '<path d="M8 2.2v1.1"/><path d="M8 12.7v1.1"/><path d="M2.2 8h1.1"/><path d="M12.7 8h1.1"/><path d="m3.9 3.9.8.8"/><path d="m11.3 11.3.8.8"/><path d="m12.1 3.9-.8.8"/><path d="m4.7 11.3-.8.8"/><circle cx="8" cy="8" r="2.4"/>',
|
|
13
14
|
bolt: '<path d="M8.9 1.8 3.8 8.8h3.3l-.5 5.4 5.5-7.5H8.8z"/>',
|
|
15
|
+
close: '<path d="m4.6 4.6 6.8 6.8M11.4 4.6l-6.8 6.8"/>',
|
|
14
16
|
database: '<ellipse cx="8" cy="4" rx="4.5" ry="1.9"/><path d="M3.5 4v4c0 1 2 1.9 4.5 1.9s4.5-.9 4.5-1.9V4"/><path d="M3.5 8v4c0 1 2 1.9 4.5 1.9s4.5-.9 4.5-1.9V8"/>',
|
|
15
17
|
flask: '<path d="M6 2.5h4"/><path d="M7 2.5v4.1l-3.4 5.3A1.4 1.4 0 0 0 4.8 14h6.4a1.4 1.4 0 0 0 1.2-2.1L9 6.6V2.5"/><path d="M5.3 10.5h5.4"/>',
|
|
16
18
|
history: '<path d="M4.2 3.4h7.6"/><path d="M4.2 8h7.6"/><path d="M4.2 12.6h4.6"/><path d="M2.2 3.4h.1"/><path d="M2.2 8h.1"/><path d="M2.2 12.6h.1"/>',
|
|
@@ -36,7 +38,9 @@
|
|
|
36
38
|
container,
|
|
37
39
|
callbacks: options.callbacks || {},
|
|
38
40
|
i18n: options.i18n || null,
|
|
39
|
-
button: options.button || null
|
|
41
|
+
button: options.button || null,
|
|
42
|
+
// Names the open project in project-page scope lines; may return ''.
|
|
43
|
+
getProjectName: typeof options.getProjectName === 'function' ? options.getProjectName : null
|
|
40
44
|
};
|
|
41
45
|
|
|
42
46
|
container.innerHTML = `
|
|
@@ -211,6 +215,7 @@
|
|
|
211
215
|
<p class="codex-set-row-help" data-update-settings-summary data-i18n="softwareUpdatesHelp">Automatically checks signed stable releases for the Extension and Native Host.</p>
|
|
212
216
|
<p class="codex-set-note" data-update-settings-state aria-live="polite" hidden></p>
|
|
213
217
|
<button type="button" class="codex-set-btn" data-check-updates data-i18n="checkForUpdates">Check for updates</button>
|
|
218
|
+
<button type="button" class="codex-set-btn" data-restore-previous-version hidden>Restore previous version</button>
|
|
214
219
|
</div>
|
|
215
220
|
</div>
|
|
216
221
|
</details>
|
|
@@ -334,6 +339,7 @@
|
|
|
334
339
|
return host || null;
|
|
335
340
|
},
|
|
336
341
|
setProviderCloseGuard: guard => instance.workbench?.setProviderCloseGuard(guard),
|
|
342
|
+
revealGroup: key => instance.workbench?.revealGroup(key) || null,
|
|
337
343
|
loadState: state => loadState(instance, state),
|
|
338
344
|
readState: () => readState(instance),
|
|
339
345
|
setStatus: (text, status) => setStatus(instance, text, status),
|
|
@@ -464,7 +470,9 @@
|
|
|
464
470
|
};
|
|
465
471
|
}
|
|
466
472
|
|
|
467
|
-
|
|
473
|
+
// options.page names the workbench page a message belongs to; the workbench
|
|
474
|
+
// shows it only while that page is active. Untagged messages show everywhere.
|
|
475
|
+
function setStatus(target, text, status = 'info', options = {}) {
|
|
468
476
|
const instance = target?._instance || target;
|
|
469
477
|
const element = instance?.container?.querySelector('[data-project-settings-status]');
|
|
470
478
|
if (!element) {
|
|
@@ -472,6 +480,9 @@
|
|
|
472
480
|
}
|
|
473
481
|
element.textContent = text || '';
|
|
474
482
|
element.dataset.status = status;
|
|
483
|
+
if (options.page) element.dataset.statusPage = options.page;
|
|
484
|
+
else delete element.dataset.statusPage;
|
|
485
|
+
instance.workbench?.refresh();
|
|
475
486
|
}
|
|
476
487
|
|
|
477
488
|
function clearStatus(target) {
|
|
@@ -482,6 +493,8 @@
|
|
|
482
493
|
}
|
|
483
494
|
element.textContent = '';
|
|
484
495
|
delete element.dataset.status;
|
|
496
|
+
delete element.dataset.statusPage;
|
|
497
|
+
instance.workbench?.refresh();
|
|
485
498
|
}
|
|
486
499
|
|
|
487
500
|
function setSkillsSummary(target, text) {
|