From 91e02352a2a38fe6a935a1e24de55b2e355b4638 Mon Sep 17 00:00:00 2001 From: Geoff Johnson Date: Fri, 31 Jul 2026 21:51:26 -0700 Subject: [PATCH 1/2] doc: add screenshot plugin plan --- docs/knowledgebase/index.md | 1 + docs/knowledgebase/log.md | 1 + docs/knowledgebase/plans/index.md | 1 + .../plans/screenshot-as-plugin.md | 256 ++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 docs/knowledgebase/plans/screenshot-as-plugin.md diff --git a/docs/knowledgebase/index.md b/docs/knowledgebase/index.md index afabdc3..b9092f0 100644 --- a/docs/knowledgebase/index.md +++ b/docs/knowledgebase/index.md @@ -80,6 +80,7 @@ to touch the KB on every edit. * [Roadmap](plans/roadmap.md) - current capabilities, phase-2 status, remaining roadmap items, and pointers to full planning docs. * [Declarative children over JSON-string properties](plans/declarative-children-migration.md) - migrate collection components from JSON-string attributes to nested child elements, piloted on accordion. * [Headless renderer and screenshots](plans/headless-screenshots.md) - `nemo screenshot` implemented on macOS via gpui's offscreen `Window::render_to_image`; Linux capture remains open. +* [Screenshot as a plugin](plans/screenshot-as-plugin.md) - move `nemo screenshot` off the feature-gated host build onto a stock release binary via an OS-native capture plugin; needs `Capability::Command` (plugin-contributed CLI subcommands) + a host `capture_app_window` bootstrap primitive. **Planned.** * [Devtools inspector](plans/devtools-inspector.md) - what a nemo-devtools crate would take; the introspection surfaces already exist, in-process panel recommended over an external client. * [Design tokens and active redesign](plans/design-tokens.md) - centralized spacing/radius/typography/semantic-color tokens (gpui-free `nemo-tokens` crate); full chrome migration with screenshot verification. * [Design-system export](plans/design-system-export.md) - `cargo xtask design-export` emits tokens + themes + component structure as a pencil.dev-friendly JSON intermediate. diff --git a/docs/knowledgebase/log.md b/docs/knowledgebase/log.md index c1ce31e..06df638 100644 --- a/docs/knowledgebase/log.md +++ b/docs/knowledgebase/log.md @@ -1,6 +1,7 @@ # Knowledge Base Update Log ## 2026-07-31 +* **Plan**: Added [Screenshot as a plugin](/docs/knowledgebase/plans/screenshot-as-plugin.md) — a design to make `nemo screenshot` deployable on a **stock release binary** by moving it out of the feature-gated host build into an **OS-native capture plugin**. Grounded the blocker in code: capture today calls gpui's `Window::render_to_image()` (`commands/screenshot.rs:85`), gated `#[cfg(feature="test-support")]` inside gpui and kept out of release by decision; a native plugin only ever receives `PluginContext` (`nemo-plugin-api/src/lib.rs:285`) — no `&mut Window`, and it can't flip a host compile-time feature — so a plugin **must capture at the OS level** (ScreenCaptureKit / `CGWindowListCreateImage`), not through gpui. Two new host primitives designed: (1) **`Capability::Command`** + `CommandSpec`/`register_command`/`PluginCommandFn` so plugins contribute CLI subcommands — requires a two-phase parse ahead of the static clap match (`main.rs:66`, `args.rs`) with **built-ins taking precedence**; (2) a host **`capture_app_window`** `PluginContext` method (default `Unsupported`, matching the `navigate` pattern at `:327`) that owns the gpui run loop + `build_app_window`/`BootstrapParams` (`main.rs:246/265`) and returns a `CapturedFrame` of raw RGBA — recommended split is host-captures/plugin-encodes, which lets the OS-capture backend ship in the **default binary** (no `test-support`) while the plugin supplies CLI surface + PNG/permission policy. Open questions logged: TCC permission UX for CI, discovery cost, native ABI versioning (no check today, `:538`), WASM parity. Registered in both plan indexes. Planning only — nothing implemented. * **Fix**: Wired `` inside `` ([issue #83](https://github.com/geoffjay/nemo/issues/83)). The build path in `app.rs` collected only each menu item's `label` into a `Vec`, so `DropdownButton` rendered click-less `PopupMenuItem`s and every entry was a silent no-op. Now `app.rs` collects a `Vec` (new struct in `components/dropdown_button.rs`, re-exported from `components/mod.rs`), carrying each item's `handlers.get("click")`, and passes `runtime` + `entity_id` into `DropdownButton` (same as `