Rework extension management for pinned profiles#37
Merged
Conversation
…profiles This ensures that pinned extensions with prerelease tags or other minor manifest warnings can be successfully verified during profile installation. By default, the profile scanner filters out extensions marked as invalid. In the context of the Conductor, which often installs custom VSIX builds with unstable version strings, this filtering causes the verification step to fail with a 'Cannot read the extension' error even if the installation succeeded on disk. This commit mirrors the behavior of non-profile installations by explicitly including invalid extensions during the verification scan.
Consolidates the definition of 'core' extensions and their parsing logic into a shared location. Previously, the Sideloader and Conductor had duplicated (and in the Conductor's case, hard-coded) definitions for core extensions. By moving the SideloadEntry types and the parseSideloadEntries utility to codexTypes.ts, we establish a single source of truth for configuration and prepare for the Conductor to dynamically derive its core extension list from product.json.
Refactors the Conductor to dynamically derive its core extension list from product.json and correctly honor VSIX-pinned sideloads in custom profiles. This commit addresses several architectural issues: 1. P2 Hard-coded Duplication: Removed CORE_EXTENSION_IDS constant. Core extensions are now read from productService.codexSideloadExtensions. 2. P1 VSIX Divergence: The backfillCoreExtensions helper now handles both gallery and VSIX-based installations. If a beta build specifies a VSIX for a core extension, the Conductor will install that exact version into the pinned profile instead of falling back to the public gallery. 3. P1 Pin Conflict Logic: enforcePins and validateProfileExtensions now explicitly skip core-version checks if the extension is already pinned to a specific version in the project metadata. This ensures project-specific pins take precedence without triggering repair/reload loops.
…rom sideloads Pinned VSIX installs were failing post-install with "Cannot read the extension from /Users/j/.codex/extensions/...". Three independent decisions interacted to cause this: 1. d9f6ee6 marked sideloaded default-profile extensions as `isApplicationScoped: true` to make them visible inside conductor profiles via VS Code's cross-profile bridge. 2. 5fd88fa added `backfillCoreExtensions`, which copies sideloaded extensions into each conductor profile explicitly. This made (1) redundant. 3. extensionManagementService.ts:1047 inherits `isApplicationScoped` from any existing extension via `||`. When the conductor installs a pinned VSIX into a custom profile, the existingExtension lookup finds the bridged Default-profile sideload (app-scoped) and the new install inherits the flag. The post-install profile scan then filters out app-scoped entries and looks for them in the Default profile — where the pinned version doesn't exist — so the find fails and "Cannot read the extension" is thrown. Even if it succeeded, dedup prefers app-scoped, so the conductor's pin would be silently shadowed by the sideload at runtime. Fix: - Sideloader: pass `isApplicationScoped: false` explicitly on every install. Add `migrateLegacyAppScope()` that runs in every window (not just default-profile) and uses `updateMetadata` to clear the flag on legacy data. Document the rationale in a top-of-file comment. - Conductor: pass `isApplicationScoped: false` explicitly in `installPinnedExtensions` and both branches of `backfillCoreExtensions`. - New patch `fix-extension-scope-inheritance.patch`: change \`||\` to \`??\` on extensionManagementService.ts:1047 so an explicit \`isApplicationScoped: false\` from options actually wins over an inherited \`true\`. - Update AGENTS.md patch-dependency table. Verified: legacy state migrates on next launch (sideloader logs "Migrated legacy app-scope on …" for each affected extension), the conductor's pinned VSIX install completes without the "Cannot read the extension" error, and the conductor profile ends up with the correct pin versions actually installed and runnable.
enforcePins() previously installed pinned VSIXs silently behind the splash screen. Mirror the toast styling used by checkForPinChanges() so first-open and repair flows surface the same "Installing pinned extension…" indeterminate progress notification while the conductor downloads and installs.
Author
|
/build |
|
Pre-release: 1.108.13064 (9c995cd) https://github.com/genesis-ai-dev/codex/releases/tag/1.108.13064-pr37-9c995cd |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Extensions management rework to address three things with pinned extension profiles:
Changes
5fd88fa). A project'smetadata.jsononly needs to pin one extension; the others come from the latest stable on the marketplace. The conductor readscodexSideloadExtensionsfromproduct.json(no more hard-coded constants) andbackfillCoreExtensionsinstalls every non-pinned core extension into the target profile (gallery for string entries, VSIX channel for object entries) afterinstallPinnedExtensions.validateProfileExtensionsandenforcePinsflag a profile missing any core extension as incomplete, andinstallPinnedExtensionsearly-skips the VSIX download when the target profile already has the pinned version.switchProfileAndReload(profile, forceReload?)adds an explicit reload param for the repair-on-current-profile path.codexTypes.ts(7562240).SideloadEntry,SideloadVsixEntry, andparseSideloadEntriesmoved out ofcodexSideloader.tsso the conductor can reuse them.patches/fix-conductor-extension-read.patch(new in7bf3034). PassesincludeInvalid: truetoscanUserExtensionsin the profile branch ofExtensionsScanner.scanLocalExtension, mirroring the non-profile branch. Without it, post-install verification of a VSIX with a pre-release version (0.24.1-pr123-abc1234) would throw "Cannot read the extension" even though the install succeeded on disk.3791314). This was the original "Cannot read the extension" bug. The sideloader used to mark its installsisApplicationScoped: true, which bridged them into conductor profiles via VS Code's cross-profile scanner. Once the conductor backfills explicitly (above), that bridge is unnecessary and actively harmful: the upstream install task atextensionManagementService.ts:1047inheritsisApplicationScopedfrom the bridged copy, so the conductor's pin would inherit the flag, get filtered out of its own profile by the scanner, and verification would fail. Fix has three parts:isApplicationScoped: falseexplicitly on every install, and a newmigrateLegacyAppScope()runs in every window (including conductor profiles) to clear the flag from existing data viaupdateMetadata. Documented in a top-of-file comment.isApplicationScoped: falseexplicitly ininstallPinnedExtensionsand both branches ofbackfillCoreExtensions.patches/fix-extension-scope-inheritance.patchchanges||to??onextensionManagementService.ts:1047so the explicitfalseactually wins over an inheritedtrue.9c995cd).enforcePinspreviously installed pinned VSIXs silently behind the splash screen. Mirrors the toast styling used bycheckForPinChangesso first-open and repair flows surface the same indeterminate "Installing pinned extension…" notification while the conductor downloads.AGENTS.mdpatch dependency table — adds the two new patches.Test plan
./dev/update_patches.shfinishes without rejectingfix-conductor-extension-read.patchorfix-extension-scope-inheritance.patch../dev/build.sh -sproducesVSCode-darwin-arm64/Codex.appwithout errors.codex-editorto a-prbuild (e.g.0.24.1-pr123-abc1234). Open a project with that pin. Install completes without "Cannot read the extension"; the conductor switches to the new profile.isApplicationScoped: true(any build before this PR). Open Codex. Sideloader logs[CodexSideloader] Migrated legacy app-scope on "<id>"for each affected extension.Default/extensions.jsonno longer hasisApplicationScoped:trueon those entries.codex-editoronly. Open a fresh project. After the conductor reload, the new profile has all four core extensions installed.codex-editor. Open project. Conductor backfills the other three but does not duplicate-installcodex-editor.extensionsfolder, then reopen. Conductor logs "already installed in profile" for the unaffected pinned ones and only the missing one downloads.codex pin syncfrom another window and trigger Frontier sync. Confirm: "Installing pinned extension…" → completion → "Reload Codex" → after click, new profile active with all extensions.open-vsx.organd open a pinned project. Error notification with "Open in Default Profile" / "Copy Error Report"; half-built profile is removed.pinnedExtensions. No profile created; sideloader handles core extensions in Default.