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.
- package/README.md +155 -392
- package/README.zh-CN.md +154 -393
- package/extension/bootstrap/background.js +52 -9
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/bootstrap/popup.html +1 -0
- package/extension/bootstrap/popupFallback.js +55 -0
- package/extension/bootstrap/updateStatus.js +1 -0
- package/extension/src/background.js +283 -55
- package/extension/src/backgroundBootstrapMigration.js +181 -0
- package/extension/src/backgroundSharedSessions.js +129 -16
- package/extension/src/backgroundUpdateCoordinator.js +242 -29
- package/extension/src/backgroundUpdateSafety.js +173 -0
- package/extension/src/content/activeTurnControl.js +171 -8
- package/extension/src/content/applyResultFormatters.js +46 -73
- package/extension/src/content/assetTransferBroker.js +72 -14
- package/extension/src/content/composerAttachments.js +104 -47
- package/extension/src/content/composerPanel.js +110 -12
- package/extension/src/content/contentRuntime.js +1555 -926
- package/extension/src/content/contextTray.js +8 -2
- package/extension/src/content/contextUsageView.js +267 -0
- package/extension/src/content/diagnosticsController.js +122 -96
- package/extension/src/content/diagnosticsExport.js +19 -5
- package/extension/src/content/diagnosticsPanel.js +48 -0
- package/extension/src/content/directoryCleanupRecovery.js +54 -0
- package/extension/src/content/generated/content.bundle.js +11077 -3412
- package/extension/src/content/generated/content.bundle.meta.json +14 -3
- package/extension/src/content/globalPreferencesController.js +1 -1
- package/extension/src/content/legacyGlobalRegistry.js +10 -0
- package/extension/src/content/localSkillsPanel.js +104 -14
- package/extension/src/content/markdownDomRenderer.js +5 -3
- package/extension/src/content/markdownText.js +47 -11
- package/extension/src/content/modelPicker.js +8 -4
- package/extension/src/content/nativeCompatibilityController.js +74 -30
- package/extension/src/content/otWarmMirror.js +5 -6
- package/extension/src/content/otWarmMirrorController.js +17 -20
- package/extension/src/content/pageBridgeClient.js +17 -4
- package/extension/src/content/panelMaintenance.js +46 -14
- package/extension/src/content/panelRenderer.js +57 -27
- package/extension/src/content/pendingInputView.js +1 -1
- package/extension/src/content/projectProviderSelection.js +13 -4
- package/extension/src/content/projectSessionCleanup.js +109 -62
- package/extension/src/content/projectSettingsCoordinator.js +67 -6
- package/extension/src/content/providerSettingsCoordinator.js +46 -8
- package/extension/src/content/providerSettingsDialog.js +73 -14
- package/extension/src/content/recentProjects.js +15 -8
- package/extension/src/content/runActivitySummary.js +160 -18
- package/extension/src/content/runCompletionMeta.js +532 -0
- package/extension/src/content/runController.js +39 -15
- package/extension/src/content/runFailureNotice.js +29 -13
- package/extension/src/content/runGuidanceController.js +72 -27
- package/extension/src/content/runGuidanceView.js +59 -10
- package/extension/src/content/runPresence.js +18 -8
- package/extension/src/content/runQueueScheduler.js +157 -47
- package/extension/src/content/runRecoveryActions.js +147 -0
- package/extension/src/content/runResultActions.js +28 -143
- package/extension/src/content/runReviewController.js +633 -0
- package/extension/src/content/runScrollLayout.js +21 -2
- package/extension/src/content/runTimelineView.js +367 -175
- package/extension/src/content/scopedPersistencePanelState.js +134 -20
- package/extension/src/content/selectionContextView.js +1 -1
- package/extension/src/content/sensitivePreflight.js +153 -0
- package/extension/src/content/sessionForkController.js +80 -17
- package/extension/src/content/sessionManager.js +50 -4
- package/extension/src/content/sessionMenuView.js +54 -18
- package/extension/src/content/sessionPersistence.js +25 -5
- package/extension/src/content/settingsPanel.js +22 -5
- package/extension/src/content/settingsWorkbench.js +132 -89
- package/extension/src/content/sharedSessionViewSync.js +49 -11
- package/extension/src/content/subagentActivityView.js +23 -7
- package/extension/src/content/updateIdle.js +4 -1
- package/extension/src/content/updateNotice.js +118 -12
- package/extension/src/content/updateSafetyReceiver.js +58 -0
- package/extension/src/content/writebackController.js +53 -4
- package/extension/src/content/writebackOrchestrator.js +116 -94
- package/extension/src/content/writingStyleSettings.js +35 -11
- package/extension/src/page/binaryAssetUploader.js +136 -14
- package/extension/src/page/compileBridge.js +193 -180
- package/extension/src/page/fileMover.js +256 -0
- package/extension/src/page/overleafCapabilities.js +4 -1
- package/extension/src/page/ownedDirectoryCleanup.js +94 -0
- package/extension/src/page/referenceProjects.js +1 -0
- package/extension/src/page/reviewContext.js +113 -0
- package/extension/src/page/saveState.js +6 -4
- package/extension/src/page/snapshotRouter.js +84 -39
- package/extension/src/page/textCoordinates.js +17 -1
- package/extension/src/page/textFileCreator.js +114 -26
- package/extension/src/page/trackedChangeCapture.js +12 -2
- package/extension/src/page/trackedChangeOwnership.js +19 -1
- package/extension/src/page/trackedChangeReplay.js +41 -21
- package/extension/src/page/trackedChangesLifecycle.js +217 -199
- package/extension/src/page/treeOperations.js +7 -10
- package/extension/src/page/updateSafetyProbe.js +41 -0
- package/extension/src/page/writebackReceiptJournal.js +2 -0
- package/extension/src/page/writebackRouter.js +103 -155
- package/extension/src/pageBridge.js +126 -69
- package/extension/src/popup.js +62 -10
- package/extension/src/shared/agentTranscript.js +373 -17
- package/extension/src/shared/auditRecords.js +4 -0
- package/extension/src/shared/compatibility.js +22 -6
- package/extension/src/shared/compileAdapter.js +129 -66
- package/extension/src/shared/composerAttachmentDraft.js +156 -0
- package/extension/src/shared/contextUsage.js +125 -0
- package/extension/src/shared/directoryCleanupProof.js +43 -0
- package/extension/src/shared/failureReasons.js +349 -4
- package/extension/src/shared/globalPreferences.js +30 -13
- package/extension/src/shared/governanceRules.js +4 -37
- package/extension/src/shared/i18n.js +590 -24
- package/extension/src/shared/lineReferences.js +38 -31
- package/extension/src/shared/managedUpdateProjection.js +2 -2
- package/extension/src/shared/nativeRequestIdentity.js +1 -0
- package/extension/src/shared/pageRpcContract.js +5 -4
- package/extension/src/shared/panelIcons.js +39 -0
- package/extension/src/shared/projectFiles.js +21 -44
- package/extension/src/shared/providerProfiles.js +5 -3
- 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/runInputQueue.js +48 -5
- package/extension/src/shared/selectionContext.js +12 -3
- package/extension/src/shared/sessionState.js +132 -28
- package/extension/src/shared/sessionTitle.js +14 -1
- package/extension/src/shared/settlementFacts.js +10 -2
- package/extension/src/shared/sharedSessionBridge.js +118 -27
- package/extension/src/shared/sharedSessionTransfer.js +140 -0
- package/extension/src/shared/staleGuard.js +166 -52
- package/extension/src/shared/storageDb.js +90 -26
- package/extension/src/shared/storageMigration.js +78 -112
- package/extension/src/shared/storageRunActions.js +267 -30
- package/extension/src/shared/subagentActivityModel.js +1 -1
- package/extension/src/shared/undoOperations.js +253 -32
- package/extension/src/shared/updateConsent.js +6 -4
- package/extension/src/shared/updateRuntimeIdentity.js +17 -3
- package/extension/src/shared/writebackIntent.js +16 -0
- package/extension/src/shared/writebackOperationEvidence.js +4 -15
- package/extension/src/shared/writebackSettlement.js +58 -40
- package/extension/styles/panel.css +1123 -493
- package/native-host/src/anthropicBridgeRequest.js +4 -2
- package/native-host/src/anthropicBridgeResponse.js +6 -2
- package/native-host/src/anthropicMessagesBridge.js +24 -16
- package/native-host/src/bootstrapMigration.js +296 -0
- package/native-host/src/bootstrapMigrationContract.js +101 -0
- package/native-host/src/bootstrapUpdate.js +269 -0
- package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
- package/native-host/src/chatBridgeRequest.js +60 -6
- package/native-host/src/chatBridgeResponse.js +20 -1
- package/native-host/src/chatCompletionsBridge.js +48 -15
- package/native-host/src/codexConfigPaths.js +106 -0
- package/native-host/src/codexHome.js +66 -73
- package/native-host/src/codexHomeScope.js +124 -0
- package/native-host/src/codexInheritedAuth.js +90 -0
- package/native-host/src/codexLocalSkills.js +301 -0
- package/native-host/src/codexPromptAssembly.js +114 -127
- package/native-host/src/codexProviderTest.js +24 -26
- package/native-host/src/codexSessionRunner.js +234 -198
- package/native-host/src/codexSessionTiming.js +18 -8
- package/native-host/src/codexSkillIsolation.js +170 -0
- package/native-host/src/codexThreadFork.js +19 -3
- package/native-host/src/index.js +19 -7
- package/native-host/src/managedInstall.js +110 -35
- package/native-host/src/managedInstallRecovery.js +140 -0
- package/native-host/src/managedRuntimeEvidence.js +57 -0
- package/native-host/src/mirrorWorkspace.js +92 -22
- package/native-host/src/nativeDoctor.js +15 -0
- package/native-host/src/nativeHelperLifecycle.js +21 -0
- package/native-host/src/nativeHostRegistration.js +33 -0
- package/native-host/src/nativeRunLifecycle.js +71 -0
- package/native-host/src/processStopBarrier.js +42 -7
- package/native-host/src/projectPathPlatform.js +30 -0
- package/native-host/src/providerContextError.js +20 -0
- package/native-host/src/providerHttp.js +80 -0
- package/native-host/src/providerProfile.js +4 -2
- package/native-host/src/providerReasoning.js +2 -7
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/providerStore.js +72 -14
- package/native-host/src/responsesPassthroughBridge.js +266 -52
- package/native-host/src/runtimeInstaller.js +21 -1
- package/native-host/src/selectionScope.js +36 -8
- package/native-host/src/subagentAdmission.js +26 -0
- package/native-host/src/subagentBroker.js +79 -66
- package/native-host/src/subagentTelemetry.js +19 -10
- package/native-host/src/subagentWorkspacePath.js +5 -2
- package/native-host/src/taskRunnerRuntime.js +92 -57
- package/native-host/src/textPatch.js +473 -377
- package/native-host/src/tomlStatements.js +140 -0
- package/native-host/src/updateManager.js +409 -46
- package/native-host/src/writingStyleRuntime.js +57 -29
- package/native-host/src/writingStyleStore.js +73 -0
- package/package.json +5 -8
- package/scripts/install-managed.mjs +1 -0
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const { buildCodexRuntimeEvent } = require('./codexRuntimeIdentity');
|
|
4
4
|
|
|
5
|
+
const { runOwnedNativeHelper } = require('./nativeHelperLifecycle');
|
|
6
|
+
const { stopCodexAppServer, throwIfAborted } = require('./codexSessionTiming');
|
|
5
7
|
const { spawn } = require('node:child_process');
|
|
8
|
+
const { normalizeSafeProjectPath } = require('../../extension/src/shared/projectFiles');
|
|
9
|
+
const { createHash } = require('node:crypto');
|
|
10
|
+
const NativeRequestIdentity = require('../../extension/src/shared/nativeRequestIdentity');
|
|
6
11
|
const { buildOperationSummary, splitDeletePlan } = require('../../extension/src/shared/summary');
|
|
7
12
|
const {
|
|
8
13
|
MIN_COMPATIBLE_EXTENSION_VERSION,
|
|
@@ -36,6 +41,7 @@ const {
|
|
|
36
41
|
const { version: PACKAGE_VERSION } = require('../../package.json');
|
|
37
42
|
|
|
38
43
|
const processStopBarrier = require('./processStopBarrier');
|
|
44
|
+
const runLifecycle = require('./nativeRunLifecycle');
|
|
39
45
|
const activeProjectLocks = new Map();
|
|
40
46
|
const activeRunControllers = new Map();
|
|
41
47
|
const activeRunEntries = new Map();
|
|
@@ -44,7 +50,7 @@ const activeRunEntries = new Map();
|
|
|
44
50
|
// Overleaf tab was reloaded — the requestId lived in content-side JS state
|
|
45
51
|
// and is gone, but the native-host-side controller is still running).
|
|
46
52
|
const activeRunByProject = new Map();
|
|
47
|
-
const CODEX_RUN_PASSTHROUGH_ERROR_CODES = new Set(['thread_resume_failed', 'codex_no_usable_result', 'codex_process_stop_unconfirmed', 'selected_context_unresolved']);
|
|
53
|
+
const CODEX_RUN_PASSTHROUGH_ERROR_CODES = new Set(['thread_resume_failed', 'codex_no_usable_result', 'codex_context_limit', 'codex_process_stop_unconfirmed', 'selected_context_unresolved', 'codex_local_skill_unavailable']);
|
|
48
54
|
|
|
49
55
|
async function handleRequest(request, env = process.env, emit = () => {}) {
|
|
50
56
|
if (!request || typeof request !== 'object') {
|
|
@@ -66,7 +72,7 @@ async function handleRequest(request, env = process.env, emit = () => {}) {
|
|
|
66
72
|
platform: getNativeRuntimePlatform({ env }),
|
|
67
73
|
protocolVersion: 2,
|
|
68
74
|
supportedProtocol: { ...SUPPORTED_NATIVE_PROTOCOL },
|
|
69
|
-
capabilities: Object.fromEntries(REQUIRED_CAPABILITIES.map(capability => [capability, true])),
|
|
75
|
+
capabilities: { ...Object.fromEntries(REQUIRED_CAPABILITIES.map(capability => [capability, true])), literalProjectPaths: true, threadCompact: true },
|
|
70
76
|
minExtensionVersion: MIN_COMPATIBLE_EXTENSION_VERSION,
|
|
71
77
|
version: PACKAGE_VERSION,
|
|
72
78
|
environment: summarizeNativeEnvironment(env)
|
|
@@ -204,7 +210,16 @@ function quotaErrorResponse(id, violation) {
|
|
|
204
210
|
}
|
|
205
211
|
|
|
206
212
|
async function handleCodexRun(request, env, emit) {
|
|
213
|
+
const identity = NativeRequestIdentity.validate(request.id);
|
|
214
|
+
if (!identity.ok) return errorResponse(request.id, identity.error.code, identity.error.message, identity.error.details);
|
|
207
215
|
let params = request.params || {};
|
|
216
|
+
if (params.operation === 'compact') {
|
|
217
|
+
if (typeof params.threadId !== 'string' || !params.threadId.trim() || params.threadId.length > 160
|
|
218
|
+
|| typeof params.projectId !== 'string' || !params.projectId.trim()) {
|
|
219
|
+
return errorResponse(request.id, 'codex_compact_thread_required', 'Compaction requires an existing project conversation.');
|
|
220
|
+
}
|
|
221
|
+
params = { ...params, threadId: params.threadId.trim(), mode: 'ask', writingStyleBuild: undefined };
|
|
222
|
+
}
|
|
208
223
|
if (params.writingStyleBuild != null) {
|
|
209
224
|
if (typeof params.writingStyleBuild !== 'object' || Array.isArray(params.writingStyleBuild)) {
|
|
210
225
|
return errorResponse(request.id, 'writing_style_invalid_build', 'Writing style build settings must be an object.');
|
|
@@ -215,7 +230,7 @@ async function handleCodexRun(request, env, emit) {
|
|
|
215
230
|
useExistingMirror: false,
|
|
216
231
|
fileOverlays: [],
|
|
217
232
|
writingStyle: null,
|
|
218
|
-
writingStyleBuild: { ...params.writingStyleBuild, requestId: String(request.id
|
|
233
|
+
writingStyleBuild: { ...params.writingStyleBuild, requestId: String(request.id) }
|
|
219
234
|
};
|
|
220
235
|
}
|
|
221
236
|
if (isCodexMissing(env)) {
|
|
@@ -236,17 +251,16 @@ async function handleCodexRun(request, env, emit) {
|
|
|
236
251
|
return errorResponse(request.id, 'project_locked', `Project ${projectKey} is currently in use by codex.run`);
|
|
237
252
|
}
|
|
238
253
|
const abortController = new AbortController();
|
|
254
|
+
const lifetime = runLifecycle.register({ controller: abortController, projectKey, rootDir: env.CODEX_OVERLEAF_MIRROR_ROOT });
|
|
239
255
|
const activeEntry = {
|
|
240
|
-
id: request.id
|
|
256
|
+
id: request.id,
|
|
241
257
|
projectKey,
|
|
242
258
|
controller: abortController,
|
|
243
259
|
control: null
|
|
244
260
|
};
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
activeRunByProject.set(projectKey, activeEntry);
|
|
249
|
-
}
|
|
261
|
+
activeRunControllers.set(request.id, abortController);
|
|
262
|
+
activeRunEntries.set(request.id, activeEntry);
|
|
263
|
+
activeRunByProject.set(projectKey, activeEntry);
|
|
250
264
|
let providerResolution;
|
|
251
265
|
try {
|
|
252
266
|
try {
|
|
@@ -264,7 +278,10 @@ async function handleCodexRun(request, env, emit) {
|
|
|
264
278
|
return providerErrorResponse(request.id, error);
|
|
265
279
|
}
|
|
266
280
|
|
|
267
|
-
|
|
281
|
+
abortController.signal.throwIfAborted();
|
|
282
|
+
// Compaction only updates the captured thread; it neither refreshes the
|
|
283
|
+
// project mirror nor accepts document overlays as part of this request.
|
|
284
|
+
if (params.operation !== 'compact' && params.useExistingMirror) {
|
|
268
285
|
const { getMirrorStatus, applyFileOverlays } = require('./mirrorWorkspace');
|
|
269
286
|
const rootDir = env.CODEX_OVERLEAF_MIRROR_ROOT;
|
|
270
287
|
const status = getMirrorStatus(projectKey, { rootDir });
|
|
@@ -288,10 +305,12 @@ async function handleCodexRun(request, env, emit) {
|
|
|
288
305
|
);
|
|
289
306
|
}
|
|
290
307
|
|
|
291
|
-
|
|
308
|
+
// OT overlays prove that the current page agrees with the trusted OT
|
|
309
|
+
// baseline; they must not rewrite it or supply a replacement hash.
|
|
310
|
+
if (!isOtWarmMirrorReuseRequest(params) && Array.isArray(params.fileOverlays) && params.fileOverlays.length) {
|
|
292
311
|
await applyFileOverlays({ projectId: projectKey, overlays: params.fileOverlays, rootDir });
|
|
293
312
|
}
|
|
294
|
-
} else if (!params.writingStyleBuild && !isSnapshotlessSkillInstallerRun(params) && !hasRunnableProjectSnapshotEvidence(params)) {
|
|
313
|
+
} else if (params.operation !== 'compact' && !params.writingStyleBuild && !isSnapshotlessSkillInstallerRun(params) && !hasRunnableProjectSnapshotEvidence(params)) {
|
|
295
314
|
return errorResponse(
|
|
296
315
|
request.id,
|
|
297
316
|
'codex_run_requires_snapshot_evidence',
|
|
@@ -306,6 +325,7 @@ async function handleCodexRun(request, env, emit) {
|
|
|
306
325
|
rootDir: env.CODEX_OVERLEAF_MIRROR_ROOT,
|
|
307
326
|
providerLaunch: providerResolution.providerLaunch,
|
|
308
327
|
onStopUnconfirmed: error => processStopBarrier.record(projectKey, env.CODEX_OVERLEAF_MIRROR_ROOT, error),
|
|
328
|
+
onProcessStarted: lifetime.trackProcess,
|
|
309
329
|
onControlReady: control => {
|
|
310
330
|
activeEntry.control = control;
|
|
311
331
|
},
|
|
@@ -346,16 +366,17 @@ async function handleCodexRun(request, env, emit) {
|
|
|
346
366
|
});
|
|
347
367
|
return errorResponse(request.id, 'codex_run_failed', truncateText(error.message, 12000));
|
|
348
368
|
} finally {
|
|
349
|
-
if (
|
|
369
|
+
if (activeRunControllers.get(request.id) === abortController) {
|
|
350
370
|
activeRunControllers.delete(request.id);
|
|
351
371
|
}
|
|
352
|
-
if (
|
|
372
|
+
if (activeRunEntries.get(request.id) === activeEntry) {
|
|
353
373
|
activeRunEntries.delete(request.id);
|
|
354
374
|
}
|
|
355
375
|
if (activeRunByProject.get(projectKey)?.controller === abortController) {
|
|
356
376
|
activeRunByProject.delete(projectKey);
|
|
357
377
|
}
|
|
358
378
|
releaseProjectLock(projectKey, lockToken);
|
|
379
|
+
lifetime.complete();
|
|
359
380
|
}
|
|
360
381
|
}
|
|
361
382
|
|
|
@@ -365,6 +386,9 @@ async function handleCodexSteer(request) {
|
|
|
365
386
|
if (!entry?.control) {
|
|
366
387
|
return errorResponse(request.id, 'codex_turn_not_ready', 'The active Codex turn is not ready for guidance.');
|
|
367
388
|
}
|
|
389
|
+
if (entry.control.operation === 'compact') {
|
|
390
|
+
return errorResponse(request.id, 'codex_compact_not_steerable', 'Wait for context compaction to finish before sending a message.');
|
|
391
|
+
}
|
|
368
392
|
const expectedThreadId = String(params.threadId || '');
|
|
369
393
|
const expectedTurnId = String(params.expectedTurnId || params.turnId || '');
|
|
370
394
|
if ((expectedThreadId && expectedThreadId !== entry.control.threadId)
|
|
@@ -400,8 +424,8 @@ async function handleCodexSteer(request) {
|
|
|
400
424
|
}
|
|
401
425
|
|
|
402
426
|
function findActiveRunEntry(params = {}) {
|
|
403
|
-
const targetId =
|
|
404
|
-
if (
|
|
427
|
+
const targetId = params.requestId ?? params.id;
|
|
428
|
+
if (activeRunEntries.has(targetId)) {
|
|
405
429
|
return activeRunEntries.get(targetId);
|
|
406
430
|
}
|
|
407
431
|
const projectKey = String(params.projectKey || '');
|
|
@@ -420,11 +444,11 @@ function findActiveRunEntry(params = {}) {
|
|
|
420
444
|
// can't punch through a real live run.
|
|
421
445
|
function handleCodexCancel(request, env = process.env) {
|
|
422
446
|
const params = request.params || {};
|
|
423
|
-
const targetId = params.requestId
|
|
447
|
+
const targetId = params.requestId ?? params.id;
|
|
424
448
|
const projectKey = typeof params.projectKey === 'string' ? params.projectKey : '';
|
|
425
449
|
const force = params.force === true;
|
|
426
450
|
|
|
427
|
-
if (
|
|
451
|
+
if (activeRunControllers.has(targetId)) {
|
|
428
452
|
activeRunControllers.get(targetId).abort(createCancellationError());
|
|
429
453
|
return okResponse(request.id, {
|
|
430
454
|
cancelled: true,
|
|
@@ -439,7 +463,7 @@ function handleCodexCancel(request, env = process.env) {
|
|
|
439
463
|
return okResponse(request.id, {
|
|
440
464
|
cancelled: true,
|
|
441
465
|
projectKey,
|
|
442
|
-
requestId: entry.id
|
|
466
|
+
requestId: entry.id
|
|
443
467
|
});
|
|
444
468
|
}
|
|
445
469
|
if (processStopBarrier.isBlocked(projectKey, env.CODEX_OVERLEAF_MIRROR_ROOT)) {
|
|
@@ -473,8 +497,10 @@ function handleCodexHistoryClear(request, env) {
|
|
|
473
497
|
}
|
|
474
498
|
}
|
|
475
499
|
|
|
476
|
-
function handleSkillsList(request, env) {
|
|
500
|
+
async function handleSkillsList(request, env) {
|
|
477
501
|
try {
|
|
502
|
+
if (request.params?.scope === 'codex-local') return okResponse(request.id,
|
|
503
|
+
await require('./codexLocalSkills').listCodexLocalSkills({ env }));
|
|
478
504
|
const { CODEX_OVERLEAF_SKILL_SCOPE, listCodexOverleafSkills, listProjectSkills } = require('./localSkills');
|
|
479
505
|
if (request.params?.scope === CODEX_OVERLEAF_SKILL_SCOPE) {
|
|
480
506
|
// Install/restore official skills before listing so newly shipped ones
|
|
@@ -493,9 +519,9 @@ function handleSkillsList(request, env) {
|
|
|
493
519
|
return errorResponse(request.id, 'skills_list_failed', error.message);
|
|
494
520
|
}
|
|
495
521
|
}
|
|
496
|
-
|
|
497
522
|
function handleSkillsInstall(request, env) {
|
|
498
523
|
try {
|
|
524
|
+
if (request.params?.scope === 'codex-local') throw new Error('Local Codex skills are managed by Codex.');
|
|
499
525
|
const { CODEX_OVERLEAF_SKILL_SCOPE, installCodexOverleafSkill, installProjectSkill } = require('./localSkills');
|
|
500
526
|
if (request.params?.scope === CODEX_OVERLEAF_SKILL_SCOPE) {
|
|
501
527
|
return okResponse(request.id, installCodexOverleafSkill({
|
|
@@ -514,9 +540,9 @@ function handleSkillsInstall(request, env) {
|
|
|
514
540
|
return errorResponse(request.id, 'skills_install_failed', error.message);
|
|
515
541
|
}
|
|
516
542
|
}
|
|
517
|
-
|
|
518
543
|
function handleSkillsRemove(request, env) {
|
|
519
544
|
try {
|
|
545
|
+
if (request.params?.scope === 'codex-local') throw new Error('Local Codex skills are managed by Codex.');
|
|
520
546
|
const { CODEX_OVERLEAF_SKILL_SCOPE, removeCodexOverleafSkill, removeProjectSkill } = require('./localSkills');
|
|
521
547
|
if (request.params?.scope === CODEX_OVERLEAF_SKILL_SCOPE) {
|
|
522
548
|
return okResponse(request.id, removeCodexOverleafSkill({
|
|
@@ -544,13 +570,13 @@ function hasRunnableProjectSnapshotEvidence(params = {}) {
|
|
|
544
570
|
if (params.restrictToFocusFiles !== true) {
|
|
545
571
|
return false;
|
|
546
572
|
}
|
|
547
|
-
const normalizedFocusFiles = normalizeSnapshotEvidencePaths(params.focusFiles);
|
|
573
|
+
const normalizedFocusFiles = normalizeSnapshotEvidencePaths(params.focusFiles, params.focusFilesAreLiteral === true);
|
|
548
574
|
if (!normalizedFocusFiles.length || !Array.isArray(params.project?.files)) {
|
|
549
575
|
return false;
|
|
550
576
|
}
|
|
551
577
|
const evidenceFiles = new Map();
|
|
552
578
|
for (const file of params.project.files) {
|
|
553
|
-
const filePath =
|
|
579
|
+
const filePath = normalizeSafeProjectPath(file?.path);
|
|
554
580
|
if (!filePath || !isUsableSnapshotEvidenceContent(file?.content)) {
|
|
555
581
|
continue;
|
|
556
582
|
}
|
|
@@ -561,19 +587,14 @@ function hasRunnableProjectSnapshotEvidence(params = {}) {
|
|
|
561
587
|
|
|
562
588
|
function isSnapshotlessSkillInstallerRun(params = {}) {
|
|
563
589
|
return params.skipMirrorSync === true
|
|
564
|
-
&& String(params.skillInvocation?.id || '').trim() === 'skill-installer'
|
|
590
|
+
&& String(params.skillInvocation?.id || '').trim() === 'skill-installer'
|
|
591
|
+
&& (!params.skillInvocation?.scope || params.skillInvocation.scope === 'builtin');
|
|
565
592
|
}
|
|
566
593
|
|
|
567
594
|
function validateOtFocusedWarmMirrorReuse(params = {}, status = {}) {
|
|
568
595
|
if (!isOtWarmMirrorReuseRequest(params)) {
|
|
569
596
|
return { ok: false };
|
|
570
597
|
}
|
|
571
|
-
if (Array.isArray(params.fileOverlays) && params.fileOverlays.length) {
|
|
572
|
-
return {
|
|
573
|
-
ok: false,
|
|
574
|
-
message: 'OT warm mirror reuse does not accept file overlays'
|
|
575
|
-
};
|
|
576
|
-
}
|
|
577
598
|
if (status?.exists !== true) {
|
|
578
599
|
return {
|
|
579
600
|
ok: false,
|
|
@@ -586,7 +607,7 @@ function validateOtFocusedWarmMirrorReuse(params = {}, status = {}) {
|
|
|
586
607
|
message: 'OT warm mirror reuse requires restrictToFocusFiles=true'
|
|
587
608
|
};
|
|
588
609
|
}
|
|
589
|
-
const normalizedFocusFiles = normalizeSnapshotEvidencePaths(params.focusFiles);
|
|
610
|
+
const normalizedFocusFiles = normalizeSnapshotEvidencePaths(params.focusFiles, params.focusFilesAreLiteral === true);
|
|
590
611
|
if (!normalizedFocusFiles.length) {
|
|
591
612
|
return {
|
|
592
613
|
ok: false,
|
|
@@ -594,14 +615,14 @@ function validateOtFocusedWarmMirrorReuse(params = {}, status = {}) {
|
|
|
594
615
|
};
|
|
595
616
|
}
|
|
596
617
|
|
|
597
|
-
const freshFiles = new
|
|
618
|
+
const freshFiles = new Map();
|
|
598
619
|
for (const file of Array.isArray(status.otFreshFiles) ? status.otFreshFiles : []) {
|
|
599
620
|
if (file?.state !== 'fresh') {
|
|
600
621
|
continue;
|
|
601
622
|
}
|
|
602
|
-
const filePath =
|
|
623
|
+
const filePath = normalizeSafeProjectPath(file.path);
|
|
603
624
|
if (filePath) {
|
|
604
|
-
freshFiles.
|
|
625
|
+
freshFiles.set(filePath, file);
|
|
605
626
|
}
|
|
606
627
|
}
|
|
607
628
|
const missingFiles = normalizedFocusFiles.filter(filePath => !freshFiles.has(filePath));
|
|
@@ -612,6 +633,22 @@ function validateOtFocusedWarmMirrorReuse(params = {}, status = {}) {
|
|
|
612
633
|
};
|
|
613
634
|
}
|
|
614
635
|
|
|
636
|
+
if (Array.isArray(params.fileOverlays) && params.fileOverlays.length) {
|
|
637
|
+
const overlays = new Set();
|
|
638
|
+
for (const overlay of params.fileOverlays) {
|
|
639
|
+
const filePath = normalizeSafeProjectPath(overlay?.path);
|
|
640
|
+
if (!normalizedFocusFiles.includes(filePath) || overlays.has(filePath)
|
|
641
|
+
|| typeof overlay?.content !== 'string' || !/^[a-f0-9]{64}$/i.test(freshFiles.get(filePath)?.sha256 || '')
|
|
642
|
+
|| createHash('sha256').update(overlay.content).digest('hex') !== freshFiles.get(filePath).sha256.toLowerCase()) {
|
|
643
|
+
return { ok: false, message: 'OT warm mirror overlay does not match the current focused OT baseline' };
|
|
644
|
+
}
|
|
645
|
+
overlays.add(filePath);
|
|
646
|
+
}
|
|
647
|
+
if (normalizedFocusFiles.some(filePath => !overlays.has(filePath))) {
|
|
648
|
+
return { ok: false, message: 'OT warm mirror overlays do not cover all focused files' };
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
615
652
|
return { ok: true };
|
|
616
653
|
}
|
|
617
654
|
|
|
@@ -627,11 +664,11 @@ function isUsableSnapshotEvidenceContent(content) {
|
|
|
627
664
|
return Boolean(text) && !/^(loading|loading\.{3}|loading…)$/i.test(text);
|
|
628
665
|
}
|
|
629
666
|
|
|
630
|
-
function normalizeSnapshotEvidencePaths(value) {
|
|
667
|
+
function normalizeSnapshotEvidencePaths(value, literal = false) {
|
|
631
668
|
const seen = new Set();
|
|
632
669
|
const paths = [];
|
|
633
670
|
for (const item of Array.isArray(value) ? value : []) {
|
|
634
|
-
const filePath = normalizeSnapshotEvidencePath(item);
|
|
671
|
+
const filePath = literal ? normalizeSafeProjectPath(item) : normalizeSnapshotEvidencePath(item);
|
|
635
672
|
if (!filePath || seen.has(filePath)) {
|
|
636
673
|
continue;
|
|
637
674
|
}
|
|
@@ -656,13 +693,14 @@ function createCancellationError() {
|
|
|
656
693
|
}
|
|
657
694
|
|
|
658
695
|
function isCancellationError(error = {}) {
|
|
696
|
+
if (['codex_turn_failed', 'codex_turn_status_invalid', 'codex_context_limit'].includes(error.code)) return false;
|
|
659
697
|
return error.code === 'codex_cancelled'
|
|
660
698
|
|| error.name === 'AbortError'
|
|
661
699
|
|| /cancelled by the user|was cancelled/i.test(error.message || '');
|
|
662
700
|
}
|
|
663
701
|
|
|
664
702
|
function shouldPassthroughCodexRunError(error = {}) {
|
|
665
|
-
return CODEX_RUN_PASSTHROUGH_ERROR_CODES.has(error.code);
|
|
703
|
+
return CODEX_RUN_PASSTHROUGH_ERROR_CODES.has(error.code) || String(error.code || '').startsWith('codex_compact_');
|
|
666
704
|
}
|
|
667
705
|
|
|
668
706
|
function isCodexMissing(env = process.env) {
|
|
@@ -753,6 +791,7 @@ async function handleMirrorConfirmWriteback(request, env) {
|
|
|
753
791
|
const result = await confirmWritebackFiles({
|
|
754
792
|
projectId,
|
|
755
793
|
paths: params.paths,
|
|
794
|
+
expectedFiles: params.expectedFiles,
|
|
756
795
|
rootDir
|
|
757
796
|
});
|
|
758
797
|
return okResponse(request.id, result);
|
|
@@ -1127,10 +1166,12 @@ function parseAgentArgsJson(value) {
|
|
|
1127
1166
|
}
|
|
1128
1167
|
|
|
1129
1168
|
function runExternalAgent(agentSpec, params, emit = () => {}, options = {}) {
|
|
1130
|
-
return new Promise((resolve, reject) => {
|
|
1169
|
+
return runOwnedNativeHelper(signal => new Promise((resolve, reject) => {
|
|
1170
|
+
throwIfAborted(signal);
|
|
1131
1171
|
const child = spawn(agentSpec.file, agentSpec.args || [], {
|
|
1132
1172
|
env: options.env || process.env,
|
|
1133
1173
|
shell: false,
|
|
1174
|
+
detached: process.platform !== 'win32',
|
|
1134
1175
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
1135
1176
|
});
|
|
1136
1177
|
const timeoutMs = parseOptionalPositiveInteger(options.timeoutMs);
|
|
@@ -1140,6 +1181,8 @@ function runExternalAgent(agentSpec, params, emit = () => {}, options = {}) {
|
|
|
1140
1181
|
let stderrRemainder = '';
|
|
1141
1182
|
let outputBytes = 0;
|
|
1142
1183
|
let settled = false;
|
|
1184
|
+
const onAbort = () => fail(signal.reason);
|
|
1185
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
1143
1186
|
|
|
1144
1187
|
const timeout = timeoutMs
|
|
1145
1188
|
? setTimeout(() => {
|
|
@@ -1164,10 +1207,8 @@ function runExternalAgent(agentSpec, params, emit = () => {}, options = {}) {
|
|
|
1164
1207
|
if (timeout) {
|
|
1165
1208
|
clearTimeout(timeout);
|
|
1166
1209
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
}
|
|
1170
|
-
reject(error);
|
|
1210
|
+
signal.removeEventListener('abort', onAbort);
|
|
1211
|
+
stopCodexAppServer(child, { processGroup: process.platform !== 'win32', reason: error }).then(() => reject(error), reject);
|
|
1171
1212
|
}
|
|
1172
1213
|
|
|
1173
1214
|
function succeed(result) {
|
|
@@ -1178,7 +1219,8 @@ function runExternalAgent(agentSpec, params, emit = () => {}, options = {}) {
|
|
|
1178
1219
|
if (timeout) {
|
|
1179
1220
|
clearTimeout(timeout);
|
|
1180
1221
|
}
|
|
1181
|
-
|
|
1222
|
+
signal.removeEventListener('abort', onAbort);
|
|
1223
|
+
stopCodexAppServer(child, { processGroup: process.platform !== 'win32' }).then(() => resolve(result), reject);
|
|
1182
1224
|
}
|
|
1183
1225
|
|
|
1184
1226
|
child.stdout.setEncoding('utf8');
|
|
@@ -1200,6 +1242,7 @@ function runExternalAgent(agentSpec, params, emit = () => {}, options = {}) {
|
|
|
1200
1242
|
emitTaskEvent(emit, event.type || 'agent.progress', event.title || event.type || 'Agent progress', event.detail || {}, event.status || 'running');
|
|
1201
1243
|
}
|
|
1202
1244
|
});
|
|
1245
|
+
child.stdin.on('error', fail);
|
|
1203
1246
|
child.on('error', fail);
|
|
1204
1247
|
child.on('close', code => {
|
|
1205
1248
|
if (settled) {
|
|
@@ -1226,7 +1269,7 @@ function runExternalAgent(agentSpec, params, emit = () => {}, options = {}) {
|
|
|
1226
1269
|
});
|
|
1227
1270
|
|
|
1228
1271
|
child.stdin.end(JSON.stringify(params));
|
|
1229
|
-
});
|
|
1272
|
+
}));
|
|
1230
1273
|
}
|
|
1231
1274
|
|
|
1232
1275
|
function parsePositiveInteger(value, fallback) {
|
|
@@ -1299,27 +1342,19 @@ function errorResponse(id, code, message, details = {}) {
|
|
|
1299
1342
|
};
|
|
1300
1343
|
}
|
|
1301
1344
|
|
|
1302
|
-
function getActiveNativeWorkState() {
|
|
1345
|
+
function getActiveNativeWorkState(env = process.env) {
|
|
1303
1346
|
return {
|
|
1304
1347
|
projectLocks: activeProjectLocks.size,
|
|
1348
|
+
processStopBarriers: processStopBarrier.getBlockedProjectCount(env.CODEX_OVERLEAF_MIRROR_ROOT, { env }),
|
|
1305
1349
|
runControllers: activeRunControllers.size,
|
|
1306
1350
|
activeTurnControls: Array.from(activeRunEntries.values()).filter(entry => entry.control).length
|
|
1307
1351
|
};
|
|
1308
1352
|
}
|
|
1309
1353
|
|
|
1310
|
-
function abortAllActiveOperations(reason = 'Native messaging transport disconnected.') {
|
|
1311
|
-
const error = new Error(String(reason || 'Native messaging transport disconnected.'));
|
|
1312
|
-
error.code = 'native_transport_closed';
|
|
1313
|
-
for (const controller of activeRunControllers.values()) {
|
|
1314
|
-
if (controller && !controller.signal?.aborted) {
|
|
1315
|
-
controller.abort(error);
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
1354
|
module.exports = {
|
|
1321
1355
|
NATIVE_REQUEST_QUOTAS,
|
|
1322
|
-
abortAllActiveOperations,
|
|
1356
|
+
abortAllActiveOperations: runLifecycle.abortAllActiveOperations,
|
|
1357
|
+
quarantineActiveOperations: runLifecycle.quarantineActiveOperations,
|
|
1323
1358
|
buildDefaultTaskResult,
|
|
1324
1359
|
getActiveNativeWorkState,
|
|
1325
1360
|
handleRequest,
|