| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
chore: Use gpui-kit (#2929) ## Summary Zed owns the `gpui` crate names on crates.io and publishes them only occasionally. This PR adds `script/bump-gpui.ts` (Bun) to publish a snapshot of any Zed commit to crates.io under our own names, a weekly `Release GPUI` workflow that runs it, and switches the workspace, README and docs to those crates. | Zed crate | Published as | | --- | --- | | `gpui` | `gpui-pre` | | `gpui_platform` | `gpui-pre-platform` | | `gpui_macros` | `gpui-pre-macros` | | `reqwest_client` | `gpui-pre-reqwest-client` | | `gpui_<x>` / other internal crates | `gpui-pre-<x>` | What the script does: - Fetches the requested Zed revision (`--rev`, default `main`) into `target/gpui-pre/zed`, or reuses a checkout passed with `--zed`. - Walks the workspace path dependencies of the four root crates and publishes the whole closure (25 crates today) at one version, `<VERSION>.<N>` (e.g. `0.3.12`): the `VERSION` constant at the top of the script (`0.3`) plus a patch number that continues from the highest one crates.io already has (`0.3.0` first). A run that stopped part-way resumes the same number. A positional argument publishes an explicit version instead. - Keeps each crate's original name as `[lib] name`, so consumers write `gpui = { package = "gpui-pre", version = "0.3.0" }` and `use gpui::*` unchanged; `actions!` and `#[derive(Action)]` keep working. - Drops optional dependencies that come from git without a crates.io version (`proptest`, `async-tar`) together with the features that enable them, then removes optional dependencies nothing can enable any more. This keeps Zed's `util` crate (which needs Zed's git-patched `async-process`) out of the publish set. - Swaps the workspace `reqwest` dependency (Zed's git fork) for the hand-published `gpui-pre-reqwest` through `DEPENDENCY_OVERRIDES`. - Vendors the gpui source files that `gpui_apple`'s build script reads from `../gpui`, since a crate unpacked from crates.io has no such sibling. - Verifies everything with `cargo publish --workspace --dry-run`, then publishes with `cargo publish --workspace`, re-checking crates.io before each attempt and waiting out the new-crate rate limit so a run can be resumed. Workflow: - `.github/workflows/release-gpui.yml` runs the script every other Sunday (even ISO weeks, gated by a small `cadence` job since cron cannot express two weeks) at 18:00 Beijing time (`0 10 * * 0` UTC) and on `workflow_dispatch` with optional `rev` and `version` inputs, on `macos-latest` so `gpui_apple`'s Metal shader build script is verified. It uses the `CARGO_REGISTRY_TOKEN` secret and writes the published crate table to the job summary. Workspace and docs: - `Cargo.toml` now depends on `gpui-pre` 0.3.0 (`gpui`, `gpui_platform`, `gpui_web`, `gpui_macros`, `reqwest_client`, `sum-tree`) and `gpui-pre-reqwest` 0.12.15 instead of the Zed git repository, `zed-sum-tree` and Zed's reqwest fork. The `[profile.dev.package]` overrides follow the new package names. - README (en/zh-CN), the site docs (en/zh-CN), the gpui-component skill, and the crate READMEs show the `gpui-pre` dependency lines. - CONTRIBUTING documents the workflow and version scheme. ## gpui-kit `crates/kit` (published as `gpui-kit`, names already reserved on crates.io) is the one crate applications depend on. It pins the matching `gpui-pre-*` set and re-exports every layer: | Path | Crate | Feature | | --- | --- | --- | | `gpui_kit::gpui` | `gpui` | always | | `gpui_kit::platform` | `gpui_platform` | always | | `gpui_kit::base` | `gpui-base` | always | | `gpui_kit::component` | `gpui-component` | `component` (default) | | `gpui_kit::assets` | `gpui-kit-assets` | `assets` (default) | | `gpui_kit::shell` | `gpui-shell` | `shell` (default) | | `gpui_kit::webview` | `gpui-wry` | `webview` | `gpui_kit::application()` and `gpui_kit::init()` cover startup, and `gpui_kit::prelude::*` also brings the crate names into scope, so `gpui::…` paths and the `actions!` / `#[derive(Action)]` macros (which expand to `gpui::…`) work without a direct `gpui` dependency. The `gpui-component` features (`inspector`, `decimal`, `tree-sitter*`) are forwarded by name. README, the site docs, the skill, the crate READMEs and `hello_world` now show `gpui-kit = "0.6"` alone; the docs no longer link GPUI to gpui.rs. Workspace crates are bumped to 0.6.0. ## Breaking Changes `gpui-component-assets` is renamed `gpui-kit-assets`; the `links` key is unchanged so `gpui-component`'s build script still finds the icon directory. ```diff -gpui-component-assets = "0.5" +gpui-kit-assets = "0.6" ``` ```diff -use gpui_component_assets::Assets; +use gpui_kit_assets::Assets; ``` Applications that listed GPUI themselves can drop those lines: ```diff -gpui = { package = "gpui-pre", version = "0.3.0" } -gpui_platform = { package = "gpui-pre-platform", version = "0.3.0", features = ["font-kit"] } -gpui-component = "0.5" +gpui-kit = "0.6" ``` ## Release gate Before anything is uploaded, `script/bump-gpui.ts` builds and tests this repository against the staged crates (mirrored outside the checkout and injected with `--config patch.crates-io…`; `Cargo.lock` is scratch-updated and restored, and `cargo metadata` proves the patch resolved). CI's `check`, `clippy` and `test` must pass, so a Zed change that no longer fits `gpui-component` fails the release instead of reaching applications through their caret `gpui-pre` requirement on `cargo update`. `--skip-kit-check` bypasses it. The workflow installs the system dependencies for that step. The facade-aware macro rewrite now copies `#[cfg]` gates onto the wrapped bodies (the published 0.3.1 `gpui-pre-macros` breaks release builds without `inspector`; 0.3.2 fixes it) and the `actions!` rewrite is scoped to the `macro_rules!` block. `gpui-shell` is not published for now (its `llrt_*` dependencies are git-only) and is no longer part of `gpui-kit`; `gpui-fps` is. `release.yml` publishes our crates with one ordered `cargo publish -p …`. ## Verification - `./script/bump-gpui.ts --dry-run --zed <local zed checkout>`: all 25 crates package and build; `gpui-pre-reqwest` resolves from crates.io. - With a temporary `[patch.crates-io]` pointing at the staged workspace (not committed), `cargo check --workspace` passes for every crate, story, story-web and example. - A scratch consumer crate depending on the staged crates via `package = "gpui-pre"` passes `cargo check`, including `actions!`, `#[derive(Action)]` and `collections::` by its original lib name. - `gpui-kit`: `cargo check` with default, no, `base`-only, `component`-only and `webview,inspector,tree-sitter-rust` features, its doc tests, `cargo check --workspace`, the CI clippy set plus `gpui-kit` and `hello_world` with `--deny warnings`, and `cargo machete` all pass against the staged `gpui-pre`. - `tsc --strict` with `@types/bun`, `typos`, and a YAML parse of the workflow pass. `gpui-pre` 0.3.0 is not on crates.io yet, so CI cannot resolve dependencies until the `Release GPUI` workflow has run (by hand, or on the next even ISO week Sunday). A requirement of `0.3.0` accepts every later `0.3.x` as well. `Cargo.lock` is left for that first resolution. ## AI assistance The script, workflow, dependency switch and documentation were written with Claude Code and reviewed by hand. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01D2PVGzukYKuXnb3LB5s53T --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 24 天前 | |
docs: base manual UI review checks on test coverage (#3257) ## Summary Document how reviewers should decide whether a UI change needs manual verification: - Compare the behavior claimed by the PR, including relevant states and edge cases, with UI test coverage. - Describe uncovered scenarios. Request a focused manual check only when automated UI tests cannot exercise that scenario, and identify the platform or integration to check. - Avoid manual rechecking of behavior already covered by automated UI tests. - Use accessibility-driven testing as the default method when manual verification is needed. Clarify the accessibility testing guide so it no longer implies that every UI change requires a manual interaction pass. The guide still records the app, story, actions and outcomes when manual verification is warranted. ## Validation - `git diff --check` passed. - Documentation-only change; no code tests run. | 1 天前 | |
questionnaire: Add a Questionnaire component (#2878) ## Summary - Add a composable Questionnaire state model and styled parts for single and multiple choice, freeform answers, skip, validation, shortcuts, focus, progress, navigation, and submission. - Reuse Radio, Checkbox, Input, Button, Kbd, semantic theme tokens, and Size throughout the presentation layer. - Add localized strings, comprehensive Story coverage, and synchronized English and Chinese documentation. ## Validation - `cargo test -p gpui-component questionnaire --lib` (15 passed) - `cargo clippy -p gpui-component --lib --tests -- --deny warnings` - Native and nightly WASM Story checks - VitePress build and `git diff --check` Visual acceptance was intentionally not performed. This implementation was created with AI assistance and reviewed through targeted tests. Fixes #2860 --------- Co-authored-by: Floyd Wang <gassnake999@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 9 天前 | |
shell: Add gpui-shell, a scriptable application runtime on gpui-base (#2821) Adds `gpui-shell`, a JavaScript application runtime on `gpui-base` with retained render snapshots: JavaScript describes changed UI state, while GPUI owns layout, rendering, input, and native animation frames. Highlights: - QuickJS/LLRT-compatible module runtime with generated `gpui.d.ts` - `div`, text, SVG, Button, Link, Checkbox, Switch, retained Input, overlays, and fluent GPUI styles - Base-aligned, deeply read-only tokens through call-scoped `cx.theme()` - Native `transition`/`spring` tracks for opacity and pixel width/height/left/top; repainting does not re-enter JavaScript - Promise-based filesystem, store, process, fetch, TCP, and WebSocket APIs with call-site capability checks - `gpui-shell.json` identity and capability manifest; legacy `plugin.json` is ignored - Host-registered native modules, policy isolation, hot reload, and snapshot performance regressions The runtime now applies explicit resource and lifecycle boundaries outside the QuickJS heap: per-runtime host-task limits, bounded WebSocket and DNS queues, module/asset/filesystem/store limits, plugin-policy cancellation, stale-context rejection, and child-process output/time/tree isolation. Windows uses suspended process creation plus a kill-on-close Job Object, and store replacement is atomic on Windows. Network hardening includes scheme/effective-port/method/path-scoped HTTP grants, segment-safe path prefixes, per-hop redirect authorization, HTTPS downgrade rejection, Fetch method/body redirect semantics, bounded bodies and timeouts, a shared fixed-size DNS resolver pool with one end-to-end connect deadline, non-blocking raw TCP close, sensitive WebSocket header rejection, bounded command queues, connection/handshake/write deadlines, and one outstanding WebSocket read per socket. The Shell story keeps the quote-load and native-motion demonstrations separate. The motion example uses a longer track and meaningful stock card, and reads semantic tokens with `cx.theme()`. The implementation guide, README, examples, and all English/Chinese website Shell pages are synchronized with the current runtime and use call-scoped theme tokens. The embedded Longbridge application is intentionally absent; its standalone repository is developed separately. Verification run locally: - `cargo test -p gpui-shell`: 308 passed, 1 ignored; binary 12 passed; doctest 1 passed, 3 ignored - `cargo test -p gpui-component-story --lib -- --test-threads=1`: 10 passed - `cargo clippy -p gpui-shell --all-targets -- -D warnings` - `cargo fmt -p gpui-shell -- --check` - `website`: `bun run build` (224 Markdown pages) - Base showcase and unrelated scrollable files: zero diff from `main` The Base Button geometry fix remains isolated in #2835 and is not carried by this branch. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Codex <codex@openai.com> | 1 个月前 | |
base, ui: Close the pub-field seam types behind builders (#2706) A public struct with `pub` fields cannot grow. Adding a field breaks every struct literal, so each new capability of a control turns into a breaking change to the state it hands out. Adding `readonly` in #2705 hit this twice. A full sweep of `crates/base` and `crates/ui` found **100 structs with `pub` fields**. Most are exempt for good reasons; this PR closes the ones that are not, and records the rule so the next one does not reopen it. ## Closed here | Type | Role | Shape | | --- | --- | --- | | `InputContextMenuCapabilities` | capability set, passed to the menu builder | builder + readers | | `CalendarItemState` | state snapshot, passed to the item slot | builder + readers | | `ComboboxTriggerCtx` → `ComboboxTriggerContext` | render context, passed to `render_trigger` | private fields + readers | | `RenderOptions` (setting) | option set, threaded through the item renderers | `with_`-prefixed builder + readers | | `InputPresentation` | state snapshot, built only by `InputBaseState` | private fields + readers | `RenderOptions` is threaded down four nesting levels with functional update syntax, which stops compiling once fields are private. A `with_`-setter taking `self` by value replaces it exactly, and reads better. `InputPresentation` gets no public builder. It is built by `InputBaseState::presentation` and nowhere else, so private fields already close the hole, and a public builder would hand out a construction path the seam does not want. `is_editable()` (`!disabled && !readonly`) is published on both capability types, so the "may the user write" rule has one definition instead of being re-derived at each call site. ## The rules `docs/ARCHITECTURE.md` gains a **Public Data Types Across the Seam** section and a design invariant; `CLAUDE.md` gains two matching principles. **Encapsulation.** A public struct crossing the seam keeps private fields, is built with a builder, and is read through methods. Setters and readers must not collide, which decides the naming: - all-boolean types name setters after the field and readers `is_`/`has_`/`can_`, matching how elements read; - types with non-boolean fields prefix every setter with `with_`, keeping the plain field name for readers — following `Sizable::with_size`. **Naming.** Spell `Context` out — `ComboboxTriggerContext`, never `…Ctx`. In a GPUI codebase `cx` is reserved for `App`, `Context<T>`, and `AsyncApp`, so an abbreviated `ctx` for anything else reads as a second, competing context. A callback receiving both takes the GPUI one as `cx` and names the other after what it holds (`trigger`). ## Exempt, and why - **Value types** whose fields *are* the definition and cannot grow: `Point`, `Selection`, `Edges`, `IndexPath`, `FoldRange`, `Span`, `SelectIndex`, and the plot geometry (`StackPoint`, `SankeyLink`, `ArcData`). - **Serde schemas** where fields are the on-disk contract and growth is handled by `#[serde(default)]`: `DockAreaState`, `PanelState`, `ThemeConfig`, `Semantic*Config`. - **Mirrors of external schemas**: the LSP `Diagnostic`, tree-sitter's `InputEdit`, the markdown AST nodes. - **GPUI action structs**: `Confirm`, `Enter`. ## Still open, deliberately Two groups are left for follow-ups, because the right fix differs and the blast radius is larger: 1. **Token records** — `ThemeColor` (139 fields), `ThemeConfigColors` (128), `SyntaxColors` (41), `ColorTokens` (17), and the rest of `theme_tokens`. A builder with 139 setters is not the answer; these want `#[non_exhaustive]` with a construction path, and every theme in `gpui-component` constructs them. 2. **Internal state exposed as `pub`** — `TableState` (11 pub fields), `Lsp` (8), `SearchSession` (7), `InputBaseState.lsp`, `CalendarState.focus_handle`, `Root.notification`, `NativeMenu.items`. These are a *stronger* problem than a future breaking change: callers can currently violate invariants the type maintains. The fix is tightening visibility, not adding a builder. Also unconverted, lower priority: `InputEditorStyle` (12 fields), `Column` (12), `ToastMotion`, `ToastOptions`, `ToastAdvance`, `ListSettings`, `NotificationSettings`, `TextViewStyle`, `TooltipState`. ## Breaking Changes ### `InputContextMenuCapabilities` - Fields are read through methods. ```diff - capabilities.disabled - capabilities.selection - capabilities.go_to_definition - capabilities.code_actions + capabilities.is_disabled() + capabilities.has_selection() + capabilities.can_go_to_definition() + capabilities.has_code_actions() ``` - Built with `new()` instead of a struct literal. > `is_editable()` is `!disabled && !readonly`. Use it for the items that write: Cut, Paste, Show Code Actions. ```diff - InputContextMenuCapabilities { code_editor: true, selection: true, ..Default::default() } + InputContextMenuCapabilities::new().code_editor(true).selection(true) ``` ### `InputPresentation` - Fields are read through methods. ```diff - presentation.multi_line - presentation.disabled - presentation.focus_handle - presentation.placeholder.clone() - presentation.value.clone() + presentation.is_multi_line() + presentation.is_disabled() + presentation.focus_handle() + presentation.placeholder().clone() + presentation.value().to_owned() ``` ### `CalendarItemState` - Fields are read through methods. ```diff - state.kind - state.active - state.today + state.kind() + state.is_active() + state.is_today() ``` - Built with `new(kind)` instead of a struct literal. > Every flag defaults to off, so only the ones actually set need naming. ```diff - CalendarItemState { kind: CalendarItemKind::Month, active: month == current, in_range: false, muted: false, disabled: false, today: false } + CalendarItemState::new(CalendarItemKind::Month).active(month == current) ``` ### `ComboboxTriggerCtx` → `ComboboxTriggerContext` - Renamed to spell `Context` out. ```diff - use gpui_component::combobox::ComboboxTriggerCtx; + use gpui_component::combobox::ComboboxTriggerContext; ``` - Fields are read through methods. > Name the closure parameter after what it holds, so `cx` stays the GPUI context. ```diff - combobox.render_trigger(|ctx, window, cx| Caret::new(ctx.size).into_any_element()) + combobox.render_trigger(|trigger, window, cx| Caret::new(trigger.size()).into_any_element()) ``` ```diff - ctx.selection - ctx.placeholder - ctx.open - ctx.disabled + trigger.selection() + trigger.placeholder() + trigger.is_open() + trigger.is_disabled() ``` ### `RenderOptions` (setting) - Fields are read through methods. ```diff - options.page_ix - options.group_ix - options.item_ix - options.size - options.layout - options.disabled + options.page_ix() + options.group_ix() + options.item_ix() + options.size() + options.layout() + options.is_disabled() ``` - Narrowed with `with_` setters instead of functional update syntax. > The setters take `self` by value, so a nested renderer gets its own copy. ```diff - item.render_item(&RenderOptions { item_ix, ..*options }, window, cx) + item.render_item(&options.with_item_ix(item_ix), window, cx) ``` ## Testing `cargo clippy --workspace --all-targets` clean, `cargo test --workspace` green, `typos` clean. --- Written with Claude Code, reviewed and adjusted by hand. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 1 个月前 | |
theme: Add `Theme::update` to keep colors, tokens and the Base projection in step (#3122) ## Problem `Theme` holds the same colors twice: `colors` (solid `Hsla`, what `cx.theme().primary` derefs to) and `tokens` (`ThemeToken { color, background }`, so a theme file's `linear-gradient(...)` can render). The Base layer keeps a third copy, projected for the scrollbar and resize handles. `tokens` was only derived when the theme was built or a config applied, and Base only on `Theme::change` / `sync_base`. `Theme::global_mut(cx).colors = palette` therefore updated one of three. A downstream application (ai-desktop/pilot, its issue #177) hit exactly this: `Sidebar` reads `tokens.sidebar` for its background and `colors.sidebar_foreground` for text, so one sidebar painted from two palettes. The fix on their side was four steps in the right order (`colors`, `tokens = ThemeTokens::from(..)`, `sync_base`, `refresh_windows`), which nothing enforced. ## Change **`Theme::update(cx, |theme| ...) -> R`** is the recommended way to edit the theme. After the closure it: 1. reconciles `colors` and `tokens` field by field against a snapshot taken before the edit — - a field edited on `colors` wins: when its token no longer names that color, the token becomes that solid color (a gradient there is dropped — the edit asked for the solid color); - a field edited only on `tokens` (e.g. a gradient set by hand) writes its solid color back to `colors`; - a field a theme config set on both sides to one color keeps its token, so `apply_config` gradients survive; so does an untouched field. A field set to the value it already had counts as untouched, so assigning a whole palette keeps the gradient of any field whose color did not change — the docs say so; 2. loads the mode's registered theme if `mode` changed. `apply_config` inside the closure installs the file and switches to its mode in one step; `update` sees the mode change arrive with a newly registered config and does not load it a second time, so the closure can go on editing after it (`radius`, colors) and lands the same result from either mode; 3. re-resolves the default fonts if a family changed; 4. rebuilds the Base projection and refreshes every window. No per-frame cost: reconciliation runs once per `update` — two `Copy` struct snapshots and ~150 field comparisons. **`Theme::global_mut` and `Theme::sync_base` stay public** with their signatures. A raw edit works as before — the caller derives `tokens`, calls `sync_base` and refreshes the windows — and the docs now say what that path owns rather than calling it unsupported. **`Theme::change`** keeps its signature and is `update` with the mode load forced, so swapping `light_theme` / `dark_theme` and calling `change` still applies the new theme. `window` is accepted for compatibility and not read; every window is refreshed either way. `Theme::set_scrollbar_mode` goes through `update` instead of writing the Base scrollbar by hand. Elsewhere: - The web gallery restores its bundled fonts through `update` after `Theme::change`, so the Base projection (which `TextView` code blocks read for the mono family) sees them. - The gallery (`title_bar`, `themes`, `settings_story`, `notification_story`, `color_theme_story`), the kit rendering test and the docs (`coding-guides`, `fonts`, `component/theme`, `component/notification`, both locales, skill copies, `docs/STYLING-AND-MOTION.md`) move to `update`. `skills/gpui-kit/references/usage.md` loses a `theme.toggle_mode(cx)` that never existed. ## Public API ### gpui-component - `Theme::update<R>(cx: &mut App, edit: impl FnOnce(&mut Theme) -> R) -> R` — edits the global theme and keeps `colors`, `tokens` and the Base projection in step, then refreshes every window. - `impl PartialEq for ThemeColor`, `impl PartialEq for ThemeTokens` — needed by the reconcile; also lets callers compare palettes. - `Theme::change` — `window` is no longer read (`_window`); signature unchanged. No breaking changes. `Theme::global_mut`, `Theme::sync_base`, `Theme::set_scrollbar_mode`, `Theme::sync_system_appearance`, `ThemeRegistry` and `Theme::apply_config` keep their signatures and behavior. ## Migration Optional. Moving an edit to `Theme::update` drops the synchronization the caller used to be responsible for: ```diff - Theme::global_mut(cx).font_size = px(18.); - Theme::sync_base(cx); - window.refresh(); + Theme::update(cx, |theme| theme.font_size = px(18.)); ``` ```diff - let theme = Theme::global_mut(cx); - theme.colors = palette; - theme.tokens = ThemeTokens::from(&palette); - theme.radius = px(8.); - Theme::sync_base(cx); - cx.refresh_windows(); + Theme::update(cx, |theme| { + theme.colors = palette; + theme.radius = px(8.); + }); ``` ```diff - Theme::global_mut(cx).apply_config(&theme_config); - Theme::change(theme_config.mode, None, cx); + Theme::update(cx, |theme| theme.apply_config(&theme_config)); ``` ```diff - Theme::global_mut(cx).notification.placement = Anchor::BottomRight; + Theme::update(cx, |theme| theme.notification.placement = Anchor::BottomRight); ``` ## Tests `crates/component/src/theme/mod.rs` `update_tests` (7): - `editing_colors_updates_the_tokens_and_the_base_projection` - `replacing_the_palette_rewrites_every_token` - `a_gradient_survives_until_its_own_color_is_edited` - `applying_a_config_keeps_its_gradients` — a `linear-gradient` from a `ThemeConfig` survives the reconcile - `setting_the_mode_loads_that_modes_theme` — `update` with `mode = Dark` loads the dark theme and Base follows - `edits_after_applying_a_config_of_the_other_mode_survive` — `apply_config` of the other mode plus `radius` / `colors.primary` in one closure keeps the edits; fails on the second load without the fix - `update_returns_the_closure_result` ``` cargo test -p gpui-component --lib # 527 passed cargo test -p gpui-kit --features test-support,component,assets --test rendering # compiles; skipped on Linux, runs on macOS CI cargo clippy --workspace --all-targets -- --deny warnings cargo fmt --check · typos · skill copy diff ``` Portions of this PR were AI-generated and refactored to match the project's style. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 9 天前 | |
docs: Share repository instructions across coding agents (#3251) ## Description Project guidance currently lives in Claude-specific files. Make `AGENTS.md` and `.agents/` the shared sources while keeping Claude Code's existing entry points: - Import `AGENTS.md` from `CLAUDE.md`, and point the old testing-rules file to the shared copy. - Extract the release-notes workflow into `.agents/commands/release-notes.md`; preserve `/release-notes`, its metadata, and `$ARGUMENTS` in a thin Claude command. - Update internal references, replace the missing `gpui-component-dev` skill reference with links to the existing skills, and leave the `skills/` distribution unchanged. Project rules, release-note generation rules, and application code are unchanged. Follows [discussion #3250](https://github.com/longbridge/gpui-kit/discussions/3250). ## How to Test - Passed `git diff --cached --check` and `typos` on all shared instructions and Claude adapters. - Compared the testing rules byte-for-byte with the original and verified that the release-notes Gather/Write/Rules sections and command metadata are unchanged. - Checked relative links, skill paths, the `@AGENTS.md` import, and `$ARGUMENTS` forwarding. Reviewed the adapter syntax against Claude Code's [memory](https://code.claude.com/docs/en/memory) and [skills](https://code.claude.com/docs/en/skills) documentation. Rust builds and Story tests were not run because this only reorganizes agent instructions and documentation references. A live Claude session was not exercised. ## Checklist - [x] Read and followed CONTRIBUTING.md. - [x] Reviewed the AI-assisted changes; no public API or application behavior changes. | 1 天前 |
Architecture
These documents describe the current architecture implemented by gpui-base
and the crates built directly on it. They are maintained as durable references
rather than project-progress logs.
- Architecture explains the crate boundaries, ownership model, component taxonomy, state flow, overlay system, and native/WASM integration.
- Styling and Motion explains semantic tokens, typed state styles, application-owned presentation, and animation primitives.
- GPUI Shell explains the scriptable application runtime built
on
gpui-base: the engine seam, the render protocol, call scopes, the object model, capabilities and the sandbox, and the measured performance model.
For component-level APIs and runnable examples, see the gpui-base documentation.