Extension registry foundation#1545
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR lays the groundwork for a registry-backed extension system: extensions are tracked in extensions.json, can be installed via markedit://install-extension, are injected into the editor in an explicit order, and can be updated on a configured cadence/strategy. It introduces a new ExtensionCore package to encapsulate registry/config/downloading logic and wires it into the macOS app lifecycle and deep-link handling.
Changes:
- Add
ExtensionCore(config model + registry cache/refresh + downloader + environment seam) with unit tests. - Add app-layer install/update flows (
ExtensionInstaller,ExtensionUpdater) and integrate them into launch + URL scheme handling. - Switch script injection to use
extensions.jsonorder/enabled state instead of scanning the entirescripts/folder.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| MarkEditMac/Sources/Main/Application/Application.swift | Reconcile extensions.json against on-disk scripts at startup. |
| MarkEditMac/Sources/Main/Application/AppDelegate.swift | Trigger extension update checks and handle markedit://install-extension deep links. |
| MarkEditMac/Sources/Main/AppCustomization.swift | Seed extensions.json and support loading scripts by explicit filenames. |
| MarkEditMac/Sources/Extension/ExtensionUpdater.swift | New: update-check + prompt/automatic application flow (UI layer). |
| MarkEditMac/Sources/Extension/ExtensionInstaller.swift | New: deep-link install flow with confirmation UI and relaunch prompts. |
| MarkEditMac/Sources/Editor/Controllers/EditorViewController.swift | Inject enabled scripts in configured order from extensions.json. |
| MarkEditMac/Resources/Localizable.xcstrings | Add localized strings for extension install/update alerts. |
| MarkEditMac/Modules/Tests/ExtensionCoreTests.swift | New: unit tests for core extension config/registry behaviors. |
| MarkEditMac/Modules/Sources/ExtensionCore/Internal/ExtensionEnvironment.swift | New: injectable filesystem/app-version environment seam for ExtensionCore. |
| MarkEditMac/Modules/Sources/ExtensionCore/ExtensionRegistry.swift | New: registry index types + refresh/caching + update detection logic. |
| MarkEditMac/Modules/Sources/ExtensionCore/ExtensionDownloader.swift | New: HTTPS download + sha256 verification/pinning + atomic install into scripts/. |
| MarkEditMac/Modules/Sources/ExtensionCore/ExtensionConfig.swift | New: extensions.json encoding/decoding + reconcile/upsert + enabled order. |
| MarkEditMac/Modules/Package.swift | Add ExtensionCore as a new SwiftPM library target and dependency. |
| MarkEdit.xcodeproj/project.pbxproj | Wire new app source files and link ExtensionCore product. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
Extension registry foundation
Adds the foundation for installing and updating editor extensions from a registry. Extensions are now tracked in
extensions.json, can be installed via amarkedit://deep link, and are kept up to date on a configurable cadence. This is a standalone, self-contained slice — a management UI and migration of pre-registry scripts will come in follow-ups.What's new
extensions.json— app-side state for editor extensions (which are installed, in what order, and update preferences). The filesystem remains the source of truth: scripts added or removed underscripts/are reconciled into the list on launch.markedit://install-extension?id=<registry-id>(reviewed) or?url=<https-url>(unreviewed, extra warning). Both always confirm, verify/pin the sha256, and offer a relaunch. Never a silent install.onLaunch/daily/weekly) and acted on perregistry.updateStrategy(manual/prompt/automatic). Only registry-installed (version-tracked) extensions are eligible.extensions.jsonin declared order, skipping disabled ones, instead of scanning the wholescripts/directory.Configuration
extensions.json(defaults shown):{ "$schema": "https://raw.githubusercontent.com/MarkEdit-app/schemas/main/extensions.json", "registry.url": "https://raw.githubusercontent.com/MarkEdit-app/extensions/main/index.json", "registry.updateCheck": "weekly", "registry.updateStrategy": "prompt", "installed": [] }registry.url— overridable to a mirror.registry.updateCheck—never/onLaunch/daily/weekly.registry.updateStrategy—manual(surface later in the manager UI) /prompt/automatic. Defaults topromptsince injected code is arbitrary JavaScript.Architecture
New
ExtensionCoreSwift package (pure logic, unit-tested, no AppKit UI):ExtensionConfig— localextensions.jsonstate:installed[], prefs,reconcileInstalled,upsertInstalled.ExtensionRegistry— remote index:refresh(conditional GET),cachedIndex, cadence (isCheckDue),availableUpdates.ExtensionDownloader— download over HTTPS + 200, verify/pin sha256, atomic write toscripts/<id>.js.ExtensionEnvironment— injectable filesystem paths and app version (test seam).App layer (
NSAlertflows):ExtensionInstaller— themarkedit://install-extensiondeep link.ExtensionUpdater— cadence check ->availableUpdates->updateStrategy, with a failure alert that names each failed extension and its reason.Integration points: reconcile at launch (
Application), ordered/enabled injection (EditorViewController), deep link + update checks (AppDelegate), default file seed (AppCustomization).Out of scope (follow-ups)
Testing
ExtensionCoreTestscoversavailableUpdates, compatibility checks, schema-version support,reconcile/upsert, andInstalledadoption/merging.#if DEBUGdebug/mock-index.jsonhook lets you exercise the update flow locally without hitting the network (compiled out of release).