Icons were previously hand-added, so their provenance and licensing lived in folklore and a mis-painted asset was invisible at runtime: GPUI's `svg()` reduces a file to an alpha mask, and `img()` keeps its pixels, but nothing complains when the two are swapped. Assets are now described by `scripts/icons.manifest` and vendored by `scripts/sync-icons.sh` from pinned upstream releases, keeping the tree reproducible and reviewable. `icons/**` stays monochrome and `color/**` full colour; `scripts/check-icon-references.sh` fails the build when a referenced asset is missing or painted through the wrong element, and runs in CI. The lookup tables move out of `formatting/` into a dedicated `features/icons` module so a ~1000-line brand table is not rebuilt inside a render closure, and saved connections gain `icon_auto_detect`, which fills in a blank icon from the detected remote system without ever overwriting a deliberate choice.
7.9 KiB
Repository Guidelines
Project Status
NyaTerm is being migrated from the legacy Tauri/WebView implementation to a native GPUI application. The migration is incomplete, and some current boundaries are transitional rather than final.
Preserve compatibility with existing NyaTerm configuration, credential, backup, and session data unless a change explicitly includes a tested migration path.
Workspace Structure
This is a Rust 2024 Cargo workspace.
crates/nyaterm-app: executable entry point, bundled assets, logging setup, and root window creation.crates/nyaterm-core: UI-independent domain models, compatibility formats, parsing, policies, and shared pure logic. Do not add GPUI dependencies here.crates/nyaterm-desktop: GPUI application composition, feature state, views, platform adapters, and background-job coordination.crates/nyaterm-terminal: terminal state machine, snapshots, control-sequence handling, encoding, and graphics protocols. It must remain UI-framework independent.crates/nyaterm-terminal-gpui: GPUI-specific terminal layout, input, highlighting, and painting.crates/nyaterm-transport: local PTY, SSH, Telnet, Serial, SFTP, tunnels, remote operations, and transfer-protocol runtime.crates/nyaterm-ui: shared GPUI theme tokens and reusable presentation widgets.crates/nyaterm-store: transitional persistence façade. The implementation currently remains innyaterm-core; do not expand the re-export-only boundary without either moving the implementation or updating consumers to use this crate.crates/nyaterm-legacy: migration and legacy-source compatibility only. Do not add new product features here.crates/nyaterm-otp: bundled OTP implementation used for HOTP/TOTP compatibility.crates/nyaterm-app/assets: bundled icon assets.icons/**is monochrome and painted withsvg();color/**is full color and painted withimg(). The two are not interchangeable — seedocs/third-party-icons.md. Assets are vendored byscripts/sync-icons.shfromscripts/icons.manifestand committed, so add or change icons through the manifest rather than by hand.vendor/: modified or pinned third-party dependencies such asrussh,russh-sftp, andzmodem2.
Architectural Rules
The current NyaTermApp type is a transitional monolithic state owner. Do not increase its scope unnecessarily.
For new or substantially changed features:
- Prefer a focused feature-state struct or GPUI Entity over new top-level
NyaTermAppfields. - Keep one authoritative owner for each piece of state.
- Do not create independently mutable state in both
NyaTermAppand an Entity Store. - Treat existing Entity snapshots as projections until the corresponding feature has explicitly migrated ownership to the Entity.
- Use typed events for communication from background jobs to GPUI state.
- Never perform filesystem, database, network, SSH, SFTP, subprocess, image-decoding, or other blocking work in a render path or long-running GPUI update callback.
- Keep terminal parsing and snapshots in
nyaterm-terminal; keep GPUI layout and painting innyaterm-terminal-gpui. - Keep transport code independent of GPUI and desktop presentation types.
- Keep persistence compatibility logic out of GPUI views.
Do not add new #[path = "..."] module declarations or new use super::* imports. Existing occurrences are migration debt and should be replaced with normal module declarations and explicit imports when the surrounding code is substantially edited.
Avoid adding broad exports to crate roots. Expose the smallest API required by consumers.
Persistence and Compatibility
Changes involving redb, credentials, known hosts, OTP, cloud sync, portable snapshots, or settings are compatibility-sensitive.
Before changing these areas:
- Preserve existing table names, keys, serialized field names, encryption prefixes, and fallback decryption behavior unless a migration is included.
- Test both new-data round trips and loading representative legacy data.
- Do not silently discard unknown or unsupported fields.
- Do not overwrite existing user data until validation succeeds.
- Keep secret-bearing values masked when returning settings to the UI.
The .nya backup format, master-key wrapping, legacy Dragonfly fallback, and existing redb data must be treated as public compatibility contracts.
Security Rules
Never log or commit:
- passwords or decrypted saved credentials;
- private-key contents or passphrases;
- OTP secrets or generated codes;
- AI, cloud-sync, OAuth, snippet, or translation API secrets;
- unredacted diagnostic payloads containing terminal or command context.
Implement custom redacted Debug output for secret-bearing structs when debugging output is required.
Changes under vendor/ must document the upstream project/version or commit, the reason for the local modification, and the validation performed.
Build and Development Commands
Use package-specific checks while iterating:
cargo check -p nyaterm-appcargo test -p <crate-name>cargo run -p nyaterm-app --bin nyaterm
Before review, run the relevant broader checks:
cargo check --workspacecargo test --workspacecargo fmt --all -- --checkcargo clippy --workspace --all-targets
Use cargo fmt --all only when intentionally applying formatting changes.
Platform-specific GPUI, PTY, Serial, SSH, clipboard, window, and path behavior must be verified on the affected operating system.
Coding Style
Use standard rustfmt formatting and Rust 2024 idioms.
snake_casefor modules, functions, fields, and variables.PascalCasefor structs, enums, and traits.SCREAMING_SNAKE_CASEfor constants.- Explicit imports instead of shared wildcard preludes.
- Typed models and errors instead of loosely structured strings.
- Small adapters at crate boundaries instead of importing application-wide models into low-level crates.
- Comments should explain invariants, compatibility constraints, ownership, or non-obvious performance decisions rather than restating code.
When splitting a large file, preserve the existing public façade where practical so structural changes do not require unrelated call-site churn.
Testing Guidelines
Add tests beside the behavior being changed.
- Terminal parsing, snapshots, graphics, selection, input, and rendering changes belong in
nyaterm-terminalornyaterm-terminal-gpui. - SSH, SFTP, Telnet, Serial, tunnel, transfer, and session lifecycle changes belong in
nyaterm-transport. - Storage changes require round-trip and legacy-compatibility tests.
- Credential and encryption changes require success, invalid-password, corrupted-data, and legacy-format tests.
- GPUI state changes should test state transitions separately from visual rendering where possible.
- Visible GPUI changes should include screenshots or recordings in the pull request.
Use descriptive behavior-oriented test names.
Migration-Only Code
The legacy source inventory, migration dashboard, compatibility façades, and temporary aliases must not become permanent homes for new functionality.
Migration-only code should be feature-gated or excluded from production builds when it depends on local source-tree paths such as ./temp/nyaterm-tauri.
When a migration boundary is completed:
- move consumers to the new authoritative API;
- remove mirrored state or compatibility re-exports;
- remove unused legacy code and dependencies;
- update this file and the migration documentation.
Commits and Pull Requests
Use Conventional Commit-style subjects:
type(scope): imperative summary
Common scopes include terminal, transport, desktop, storage, ui, ai, and sync.
Pull requests should include:
- a concise description of the behavior and architectural impact;
- linked issues where applicable;
- commands and platforms tested;
- screenshots or recordings for visible GPUI changes;
- explicit notes for persistence, credential, migration, or vendored-dependency changes.