## What changed
- Add nullable `installedAt` metadata to `PluginSummary` and its generated schemas, expressed as a Unix timestamp in seconds.
- Preserve the backend installation time for remote plugins across plugin list, installed, read, and share-list responses. Return `null` when the timestamp is unavailable, including for local or uninstalled plugins and older backend responses.
## Testing
- Cover timestamp conversion in the remote plugin list integration test and the field's serialization and backward-compatible default in protocol tests.
GitOrigin-RevId: 8a1640320adb298874e1074e9891d1017ad06937
## What changed
- Add nullable `disabledReason` and `eligiblePlanTypes` fields to v2
`PluginSummary` responses and generated schemas.
- Preserve the remote catalog values across discovered, installed, and cached
plugin summary paths while returning `null` for local plugins and older
remote responses.
- Treat unrecognized disabled reasons as `unknown` for forward compatibility.
## Testing
- Cover protocol round trips, remote summary propagation, unknown disabled
reasons, and app-server responses for admin-disabled and plan-ineligible
plugins.
GitOrigin-RevId: 657a7ea6f838a6ff8bd1769ebcca0f3432684437
## What changed
- Add nullable `canPublishToWorkspace` metadata to plugin share contexts and `plugin/share/save` responses.
- Preserve the remote capability through catalog parsing and app-server responses so clients can decide whether to offer workspace-directory publishing.
- Document that clients should fail closed when the capability is unavailable.
## Testing
- Cover remote catalog parsing, share-save response propagation, and protocol serialization.
GitOrigin-RevId: b0346b3b330169838f800dfdf21dfa5db1a47f4d
## What changed
- Add nullable `mustShowInstallationInterstitial` metadata to app-server
`PluginSummary` responses.
- Preserve the remote service value through catalog, installed-plugin cache,
list, read, and share-list paths.
- Return `null` for local plugins and remote responses that omit the field so
clients can fail closed when the policy is unavailable.
## Testing
- Cover `true`, `false`, and missing values across remote summary paths and
app-server plugin endpoints.
GitOrigin-RevId: db79702ee2bfa800a9910d64d933bcabecb3ce70
## Summary
- Add `PluginInstallPolicySource` to the app-server v2 `PluginSummary`
payload.
- Propagate remote `installation_policy_source` through plugin
summaries, details, installed-plugin caching, and app-server responses.
- Preserve the supported source values and map unrecognized backend
values to `null`.
- Return `null` for local plugins and expose the field in generated JSON
and TypeScript schemas.
- Update app-server API documentation and plugin list/read coverage.
## Testing
- `just test -p codex-app-server-protocol` (251 passed)
- Targeted `codex-app-server` plugin list, installed, and read tests (4
passed)
- Targeted `codex-core-plugins` known and unknown policy source tests (2
passed)
- `just fmt`
- `git diff --check`
## Why
Marketplace source deserialization treated `{"source":"npm", ...}` as
unsupported. The loader logged and skipped the entry, so npm-backed
plugins never appeared in `plugin list --available` and `plugin add`
returned "plugin not found".
Codex plugins are installed from a plugin root, not from an npm
dependency tree. For npm-backed marketplace entries, Codex should fetch
the published package contents without running package scripts or
installing unrelated dependencies.
## What changed
- Add `npm` marketplace plugin sources with `package`, optional semver
`version` or version range, and optional HTTPS `registry`.
- Reject unsafe npm source fields before materialization, including
invalid package names, non-semver version selectors, plaintext or
credential-bearing registry URLs, and registry query/fragment data.
- Materialize npm plugins with `npm pack --ignore-scripts`, then unpack
the resulting tarball through the existing hardened plugin bundle
extractor.
- Enforce npm archive and extracted-size limits, require the standard
npm `package/` archive root, and verify the extracted `package.json`
name matches the requested package before installing.
- Keep plugin listings, install-source descriptions, CLI JSON/human
output, app-server v2 `PluginSource`, TUI source summaries, regenerated
schema fixtures, and app-server documentation in sync.
## Impact
Marketplaces can distribute Codex plugins from public or configured
private HTTPS npm registries using the same install flow as existing
materialized plugin sources. `npm` must be available on `PATH` when an
npm-backed plugin is installed.
Fixes#27831
## Validation
- `just write-app-server-schema`
- `just test -p codex-core-plugins -p codex-app-server-protocol -p
codex-app-server -p codex-cli`
- npm/schema/core-plugin coverage passed in the run.
- The full focused command finished with `1739 passed`, `11 failed`, and
`6 timed out`; the failures were unrelated local app-server environment
failures from `sandbox-exec: sandbox_apply: Operation not permitted`
plus one missing `test_stdio_server` helper binary.
- Installed an npm-published Codex plugin package through a throwaway
local marketplace and throwaway `CODEX_HOME` to exercise the real npm
materialization path end to end.
Adds additive dark-mode plugin logo metadata across manifests, remote
catalogs, and the app-server protocol while keeping uninstalled Git
listings free of synthetic local paths.
Supersedes #28945. This replacement uses an upstream branch so trusted
CI can use the repository-provided remote Bazel configuration.
## Current state
Plugin interfaces expose only the default logo asset. Clients therefore
cannot select a dedicated dark-mode logo even when a plugin provides
one.
## What this PR changes
- Adds nullable `logoDark` and `logoUrlDark` fields to
`PluginInterface`.
- Resolves local `interface.logoDark` assets and maps remote
`logo_url_dark` values.
- Removes path-backed interface assets, including `logoDark`, from
uninstalled Git fallback listings until the plugin has a real local
root.
- Updates the bundled plugin validator and manifest reference.
- Regenerates the app-server JSON schemas and TypeScript types.
Local manifests expose `interface.logoDark` as a package-relative asset
path. Remote catalog responses expose `logo_url_dark`. These values map
into separate app-server fields so clients can preserve local-path and
remote-URL handling.
## Risk
The fields are additive and nullable, so existing clients retain their
current logo behavior. The main risks are an incomplete mapping path or
exposing a synthetic local path for an uninstalled Git plugin.
Local-manifest, remote-catalog, fallback-listing, protocol
serialization, and app-server integration tests cover those paths.
Spiciness: 2/5
## Testing
- `just write-app-server-schema`
- `just fmt`
- Regression test first failed with `logo_dark` resolved to
`/assets/logo-dark.png`, then passed after the fallback-listing fix.
- `just test -p codex-core-plugins` (267 tests passed)
- `just test -p codex-app-server 'suite::v2::plugin'` (114 tests passed)
- `just test -p codex-app-server-protocol -p codex-core-plugins -p
codex-plugin -p codex-skills` (517 tests passed before the follow-up)
- `just test -p codex-tui plugin` (47 tests passed)
- Validated a local plugin manifest containing `interface.logoDark` with
the bundled validator.
## Manual verification
Create a local plugin with both `interface.logo` and
`interface.logoDark`, then call `plugin/list` or `plugin/read`. Confirm
the response contains separate `logo` and `logoDark` paths. For a remote
catalog entry, confirm `logoUrlDark` is populated from `logo_url_dark`.
For an uninstalled Git marketplace entry, confirm path-backed interface
assets remain absent until installation.
Issue: N/A - coordinated maintainer change.
- Adds localVersion to plugin summaries and remoteVersion to share
context, including generated API schemas.
- Hydrates local and remote plugin versions from manifests and remote
release metadata.
- Adds default-on plugin_sharing gate for shared-with-me listing and
plugin/share/save, with disabled-path errors
and focused coverage.
Makes plugin summaries use config-style plugin@marketplace IDs while
exposing backend remote IDs separately as remotePluginId.
Also fix the consistency issue of REMOTE_SHARED_WITH_ME_MARKETPLACE_NAME
Expose discoverability and full share principals in share context, carry
roles through save/updateTargets, hydrate local shared plugin reads, and
keep share URLs only under plugin.shareContext.
Adds marketplaceKinds to plugin/list for local, workspace-directory, and
shared-with-me; omitted params keep default local plus gated global
behavior, while explicit kinds are exact.
Exposes shareContext on plugin summaries from local share mappings and
remote workspace/shared responses, including remotePluginId and nullable
creator metadata.
Adds shared-with-me listing through /ps/plugins/workspace/shared,
renames the workspace remote namespace to workspace-directory, and keeps
direct remote read/share/install/update/delete paths gated by plugins
rather than remote_plugin.
## Summary
- Add plugin manifest keywords to core plugin marketplace/detail models
- Expose keywords on app-server v2 PluginSummary and generated
schema/types
- Populate keywords in plugin/list and plugin/read responses for local
plugins
Depends on https://github.com/openai/openai/pull/891087
## Validation
- just fmt
- just write-app-server-schema
- cargo test -p codex-app-server-protocol
- cargo test -p codex-core-plugins
- cargo test -p codex-app-server
plugin_list_keeps_valid_marketplaces_when_another_marketplace_fails_to_load
- cargo test -p codex-app-server
plugin_read_returns_plugin_details_with_bundle_contents
When a local plugin is shared, Codex now records the local plugin path
by remote plugin id under CODEX_HOME/.tmp.
plugin/share/list includes the remote share URL and the matching local
plugin path when available, and plugin/share/delete
clears the local mapping after deleting the remote share.
Also add sharedURL to plugin/share/list.
## Summary
Remote plugin-service returns plugin availability separately from a
user's installed/enabled state. This adds `PluginAvailabilityStatus` to
the app-server protocol, propagates remote catalog `status` into
`PluginSummary`, and rejects install attempts for remote plugins marked
`DISABLED_BY_ADMIN` before downloading or caching the bundle.
This is the `openai/codex` half of the change. The companion
`openai/openai` webview PR is
https://github.com/openai/openai/pull/873269.
## Validation
- `cargo run -p codex-app-server-protocol --bin write_schema_fixtures`
- `cargo test -p codex-app-server --test all
plugin_list_marks_remote_plugin_disabled_by_admin`
- `cargo test -p codex-app-server --test all
plugin_list_includes_remote_marketplaces_when_remote_plugin_enabled`
- `cargo test -p codex-app-server --test all
plugin_install_rejects_remote_plugin_disabled_by_admin_before_download`
- `cargo test -p codex-app-server-protocol schema_fixtures`
1. Adds v2 plugin/share/save, plugin/share/list, and plugin/share/delete
RPCs.
2. Implements save by archiving a local plugin root, enforcing a size
limit, uploading through the workspace upload flow, and supporting
updates via remotePluginId.
3. Lists created workspace plugins
4. Deletes a previously uploaded/shared plugin.