Files
pebrel/docs/architecture.md
kuddev bb2dc13956 Merge main and scope terminal design records
Move the pending activity, input and SSH authentication decisions into their
module-owned notes under the current governance contract. Import the shutdown
draft type directly after the incoming drag-preview cleanup removes its parent
import.
2026-09-19 21:01:03 +08:00

106 lines
7.0 KiB
Markdown

# Pebrel architecture / 架构地图
## Shape: modular desktop application
Keep a modular monolith: domain rules and adapters communicate inside the desktop
application unless a current lifecycle or isolation requirement justifies another
process. Existing mux, CLI hook and acceptance-lab processes have concrete roles;
they are not a reason to introduce generic microservices or a service locator.
The dependency direction is **composition/UI → application capabilities → shared
domain rules**. Platform and I/O details adapt domain inputs/results. They must not
make a domain crate depend on a view. This is a responsibility model, not a demand
to rename all existing directories or create abstract interfaces everywhere.
## Current ownership map
| Area | Owns | Must not become |
| --- | --- | --- |
| `nebula_settings` | Runtime settings, language registry, shared preference contracts | A UI/widget library |
| `nebula_split` | Split tree, geometry, navigation rules | Window management or rendering |
| `nebula_terminal` | Grid, VT processing, terminal/PTY behavior | Product panels or GPUI state |
| `nebula_config`, `nebula_config_derive` | Configuration abstractions and derives | Application orchestration |
| `nebula-completions` | Completion matching and presentation-independent results | Terminal view ownership |
| `nebula_hook` | Small process/lifecycle hook bridge | An application dependency container |
| `nebula_app/src/i18n` | Static lookup, locale resolution and formatting | Runtime catalog parsing or UI ownership |
| `nebula_app/src/math` | Parse, validate, layout, compile and cache responsibilities | A duplicated per-shell math engine |
| `nebula_app/src/platform` | Explicit platform capabilities and native adapters | A dumping ground for unrelated logic |
| `nebula_app/src/ai_hook` | Normalized provider facts, bounded ordering, one shared pane lifecycle and owned installation policy; Windows adapters | Screen keyword rules or a separate state machine per UI shell |
| `nebula_app/src/platform/ssh_agent.rs` | Native agent endpoints, transport connection and bounded identity discovery | Host authentication policy or private key selection |
| `nebula_app/src/ssh_session/agent.rs` | SSH agent identity selection, signing outcomes and total discovery budget; fresh scope per host | A second authentication plan, credential store or agent forwarding service |
| `nebula_app/src/ssh_session/integration.rs` | Authenticated exec/PTY orchestration for remote hook installation and shell startup | Provider policy or a second Agent state machine |
| `nebula_app/src/ai_agents` | Agent identity and structurally constrained screen observations | Authority to overwrite hook results or infer remote completion from silence |
| `nebula_app/src/gpui_shell` | GPUI views, UI state, commands and subscriptions | A second settings/domain implementation |
| `nebula_app/src/product_ui` | Feature-selected shared presentation facade | A route to legacy rendering dependencies |
| `nebula_app/src/display`, `renderer` | Legacy rendering and still-shared extracted models | A source of new undifferentiated functionality |
| `nebula_gpui` | Component acceptance lab | A dependency of the product |
| `nebula_app/build`, `tools/i18n-contract` | Generation and independent contract verification | Runtime configuration loading |
The map records current responsibilities; it does not assert that every legacy
file has already reached the target shape. Eleven oversized legacy files remain
under [ratcheted budgets](project-constraints.md). Move their independent rules
when working on the relevant capability; do not mix a whole-app rewrite into a fix.
## Rust module names are not file locations
`main.rs` selects `product_ui/mod.rs` as the `display` module when the legacy shell
is disabled. It likewise selects product adapters for several legacy-looking paths.
The product facade currently reuses extracted models via `#[path]` declarations.
`i18n/outcomes.rs` is compiled as the separate root module `localized_status`.
Consequently, neither an import containing `display` nor a file beneath that folder
proves that the product loads the legacy renderer. Keep semantic boundaries tested
with the actual feature configuration. Avoid relocating code merely to satisfy a
string-matching architecture tool.
## Feature modules and lifecycle
For a capability that grows, prefer a small entry/facade plus cohesive child modules:
```text
capability/
mod.rs exposed operations and orchestration
model.rs owned state and transitions, when substantial
adapter.rs I/O/platform conversion, when needed
view.rs renderer-specific presentation, when needed
tests.rs behavior contracts/fixtures, when substantial
```
This is a possible shape, not a mandatory directory scaffold. Name children after
their real responsibility (`navigation`, `shell_picker`, `parser`, `layout`), not
`part1`, `common2` or `misc`. A short cohesive module can stay a single file. Keep
orchestration readable; it should not absorb every callback, parser and widget.
Cross-feature calls should use deliberately exposed commands/results rather than
mutating another feature's internal collections. Prefer concrete types and plain
functions until a second real implementation, testing seam or native boundary
justifies a trait. Do not make fields public simply to make extraction compile.
Background work carries an owning scope and cancellation/staleness policy. Results
must be applied only to a still-valid view/session. Renderer callbacks should use
prepared state, not synchronously reload preferences, scan disks or wait for a child
process. Measure hot-path effects instead of extrapolating a tiny benchmark to the
whole product.
## Extension checklist
- New setting: shared registry/model → persistence contract → shell adapter → tests.
- New language: one registry row + catalog; reuse static generation and fallback.
- New panel: put presentation under the shell, reuse existing domain operations.
- New platform support: model the capability, then implement a native adapter;
unsupported behavior must be explicit, not a silently successful stub.
- New dependency/crate/long-lived service: first document its responsibility,
direction, cost, ownership and why an existing module is insufficient.
See [CONTRIBUTING](../CONTRIBUTING.md), [enforced contracts](project-constraints.md),
the [causal note policy](../architecture/notes/AGENTS.md), and the
[legacy decision archive](architecture-decisions.md). Architectural review evaluates
cohesion and knowledge shared across boundaries; CI provides narrower mechanical
checks, not a guarantee against every future design mistake.
## 中文摘要
坚持模块化桌面应用:界面负责呈现与编排,领域规则有唯一权威实现,平台和 I/O 放在明确适配边界。
按能力、状态归属和生命周期分组,不为了“可扩展”先造微服务、全局容器或层层 trait。
拆文件必须减少跨模块知识,不以文件数增加作为解耦证明;旧大文件按相关功能逐步治理。