From d72221c4b8887748c456b32e2925c2fdd933c84e Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Mon, 21 Sep 2026 21:35:55 +0800 Subject: [PATCH 01/40] Optimize GPUI render settings reads --- nebula_app/src/gpui_shell/config.rs | 25 +++++++++++++++++++ .../terminal/ssh_connect_overlay.rs | 8 +----- .../src/gpui_shell/workspace/file_tree.rs | 8 +++--- .../workspace/file_tree/path_bar.rs | 2 +- .../src/gpui_shell/workspace/palette.rs | 4 +-- .../src/gpui_shell/workspace/remote_files.rs | 11 ++++---- .../workspace/settings_navigation.rs | 4 ++- .../gpui_shell/workspace/sidebar_resize.rs | 2 +- .../src/gpui_shell/workspace/update_dialog.rs | 2 +- 9 files changed, 44 insertions(+), 22 deletions(-) diff --git a/nebula_app/src/gpui_shell/config.rs b/nebula_app/src/gpui_shell/config.rs index 7f953c5..0ad3336 100644 --- a/nebula_app/src/gpui_shell/config.rs +++ b/nebula_app/src/gpui_shell/config.rs @@ -42,6 +42,7 @@ pub(crate) const fn effective_cursor_blink(configured: Option) -> bool { pub struct Settings { /// 已解析的界面语言。GPUI 组件只读这个内存全局,渲染路径不得重复读盘。 pub ui_language: UiLanguage, + pub panel_resize: bool, pub font_family: String, pub font_cjk: Option<[gpui::Font; 4]>, pub font_bold_family: String, @@ -117,6 +118,10 @@ pub(crate) fn ui_language(cx: &App) -> UiLanguage { cx.try_global::().map(|settings| settings.ui_language).unwrap_or(UiLanguage::EnUs) } +pub(crate) fn panel_resize(cx: &App) -> bool { + cx.try_global::().is_some_and(|settings| settings.panel_resize) +} + pub(crate) fn ai_toasts_enabled(cx: &App) -> bool { cx.try_global::().is_none_or(|settings| settings.ai_toasts) } @@ -248,6 +253,7 @@ impl Settings { Settings { ui_language, + panel_resize: runtime.panel_resize, font_bold_family: secondary(&raw.font.bold), font_italic_family: secondary(&raw.font.italic), font_bold_italic_family: secondary(&raw.font.bold_italic), @@ -792,6 +798,25 @@ mod tests { assert_eq!(resolve_ui_language(LanguagePref::EnUs), UiLanguage::EnUs); } + #[cfg(feature = "gpui-test-support")] + #[gpui::test] + fn render_preferences_read_current_settings(cx: &mut gpui::TestAppContext) { + cx.update(|cx| { + for (theme, language, panel_resize) in [ + (ThemeName::Nord, UiLanguage::ZhCn, false), + (ThemeName::Paper, UiLanguage::EnUs, true), + ] { + let mut runtime = RuntimeSettings::from_raw(&RawSettings::default()); + runtime.panel_resize = panel_resize; + let mut settings = Settings::load_with_runtime(theme, runtime); + settings.ui_language = language; + cx.set_global(settings); + assert_eq!(super::ui_language(cx), language); + assert_eq!(super::panel_resize(cx), panel_resize); + } + }); + } + #[test] fn system_theme_owns_terminal_background_while_following_system() { let custom = Some([0x0f, 0x11, 0x1a]); diff --git a/nebula_app/src/gpui_shell/terminal/ssh_connect_overlay.rs b/nebula_app/src/gpui_shell/terminal/ssh_connect_overlay.rs index 7d91955..74fb677 100644 --- a/nebula_app/src/gpui_shell/terminal/ssh_connect_overlay.rs +++ b/nebula_app/src/gpui_shell/terminal/ssh_connect_overlay.rs @@ -72,12 +72,6 @@ mod connection_state_tests { } } -/// UiLanguage 由设置折算(两壳同源)。 -pub(super) fn language() -> crate::display::UiLanguage { - let runtime = nebula_settings::RuntimeSettings::load(); - crate::display::LanguagePreference::from(runtime.language).resolved() -} - fn hsla_from_rgba(r: u8, g: u8, b: u8) -> Hsla { let (rf, gf, bf) = (f32::from(r) / 255.0, f32::from(g) / 255.0, f32::from(b) / 255.0); let max = rf.max(gf).max(bf); @@ -288,7 +282,7 @@ pub(super) fn overlay( use gpui::prelude::FluentBuilder as _; let theme = cx.theme(); - let lang = language(); + let lang = crate::gpui_shell::config::ui_language(cx); // chrome 文本锚定配置字号(旧壳 ui_font 合同),不跟终端缩放。 let ui_px = cx .try_global::() diff --git a/nebula_app/src/gpui_shell/workspace/file_tree.rs b/nebula_app/src/gpui_shell/workspace/file_tree.rs index 4528f46..bb47378 100644 --- a/nebula_app/src/gpui_shell/workspace/file_tree.rs +++ b/nebula_app/src/gpui_shell/workspace/file_tree.rs @@ -316,7 +316,7 @@ impl NebulaWorkspace { let editing_path = self.file_tree_path.is_some(); let theme = cx.theme(); let muted = theme.muted_foreground; - let language = super::workspace_ui_language(); + let language = crate::gpui_shell::config::ui_language(cx); let search_options = self.side_panel.file_search_options(); let search_active = !self.side_panel.search.trim().is_empty(); let search_pending = self.side_panel.file_search_pending(); @@ -428,7 +428,7 @@ impl NebulaWorkspace { }); let root_dir = self.side_panel.root().map(std::path::Path::to_path_buf); let row_count = self.side_panel.file_rows().len(); - let empty = self.file_tree_empty_state(); + let empty = self.file_tree_empty_state(cx); let scroll_handle = self.file_tree_scroll.clone(); v_flex() @@ -611,13 +611,13 @@ impl NebulaWorkspace { /// side_panel.rs:3112-3131 同源。判据也照旧壳:`..` 不算内容,只剩它时这个 /// 目录仍然是空的;"读不到"和"确实是空的"必须分开说,否则用户没法判断该 /// 重试还是该换目录。 - fn file_tree_empty_state(&self) -> Option { + fn file_tree_empty_state(&self, cx: &gpui::App) -> Option { if self.side_panel.file_rows().iter().any(|row| !row.is_parent) { return None; } if !self.side_panel.search.trim().is_empty() { use crate::i18n::Message; - let language = super::workspace_ui_language(); + let language = crate::gpui_shell::config::ui_language(cx); return Some(if let Some(error) = self.side_panel.file_search_error() { crate::ux::EmptyState::new( language.text(Message::FilesSearchFailed), diff --git a/nebula_app/src/gpui_shell/workspace/file_tree/path_bar.rs b/nebula_app/src/gpui_shell/workspace/file_tree/path_bar.rs index 149ab4a..7de022a 100644 --- a/nebula_app/src/gpui_shell/workspace/file_tree/path_bar.rs +++ b/nebula_app/src/gpui_shell/workspace/file_tree/path_bar.rs @@ -210,7 +210,7 @@ impl NebulaWorkspace { if self.file_tree_path.as_ref().is_some_and(|edit| edit.origin != origin) { self.file_tree_path = None; } - let language = super::super::workspace_ui_language(); + let language = crate::gpui_shell::config::ui_language(cx); let Some(edit) = self.file_tree_path.as_ref() else { let value = origin .wsl diff --git a/nebula_app/src/gpui_shell/workspace/palette.rs b/nebula_app/src/gpui_shell/workspace/palette.rs index 6fe7e0d..a44244e 100644 --- a/nebula_app/src/gpui_shell/workspace/palette.rs +++ b/nebula_app/src/gpui_shell/workspace/palette.rs @@ -68,7 +68,7 @@ impl NebulaWorkspace { .get(self.active) .and_then(WorkspaceTab::focused_view) .is_some_and(|view| view.read(cx).working_directory().is_some()); - let language = workspace_ui_language(); + let language = crate::gpui_shell::config::ui_language(cx); let rows = self.palette_override.clone().unwrap_or_else(|| { let mut rows: Vec = crate::display::command_palette::catalog() .iter() @@ -171,7 +171,7 @@ impl NebulaWorkspace { let muted = theme.muted_foreground; let overlay = theme.overlay; let mono_family = theme.mono_font_family.clone(); - let language = workspace_ui_language(); + let language = crate::gpui_shell::config::ui_language(cx); let palette_filters = if self.shell_picker_open { Some(( WorkspacePaletteFilter::Launcher(self.launcher_filter), diff --git a/nebula_app/src/gpui_shell/workspace/remote_files.rs b/nebula_app/src/gpui_shell/workspace/remote_files.rs index eb07878..49b22ec 100644 --- a/nebula_app/src/gpui_shell/workspace/remote_files.rs +++ b/nebula_app/src/gpui_shell/workspace/remote_files.rs @@ -458,6 +458,7 @@ impl NebulaWorkspace { let muted = theme.muted_foreground; let foreground = theme.foreground; let drop_highlight = theme.accent.opacity(0.18); + let language = crate::gpui_shell::config::ui_language(cx); let rows = self.remote_rows(); let row_count = rows.len(); let destination = self.remote_browser.destination.clone(); @@ -467,7 +468,7 @@ impl NebulaWorkspace { self.remote_browser.path.clone() }; let at_root = self.remote_browser.path == "/" || self.remote_browser.path.is_empty(); - let notice = self.remote_notice(); + let notice = self.remote_notice(language); v_flex() .h_full() @@ -488,7 +489,7 @@ impl NebulaWorkspace { this.drop_upload_paths(vec![file.local_path.clone()], None, window, cx); })) .child(div().px(px(TEXT_INSET)).text_xs().text_color(muted) - .child(workspace_ui_language().text(if crate::platform::file_drag::supported() { + .child(language.text(if crate::platform::file_drag::supported() { crate::i18n::Message::TransferDragHint } else { crate::i18n::Message::TransferUploadHint }))) // 主机名单独一行:远端浏览器最危险的误操作是"以为在另一台机器上", @@ -849,13 +850,13 @@ impl NebulaWorkspace { /// /// 三种情况必须分开说。"读不到"和"是空的"混为一谈,用户就不知道该重试 /// 还是该换目录——这是空态里最常见也最误导人的一处偷懒。 - fn remote_notice(&self) -> Option { + fn remote_notice(&self, language: crate::display::UiLanguage) -> Option { if let Some(error) = self.remote_browser.error.as_deref() { return Some(format!("{error}(点右上角重新读取)")); } if self.remote_browser.preflighting { return Some( - workspace_ui_language().text(crate::i18n::Message::TransferChecking).to_owned(), + language.text(crate::i18n::Message::TransferChecking).to_owned(), ); } if let Some(snapshot) = self.remote_transfer_snapshot() @@ -868,7 +869,7 @@ impl NebulaWorkspace { return Some("正在读取远端目录…".to_owned()); } if let Some(outcome) = self.remote_browser.last_outcome { - return Some(workspace_ui_language().text(outcome).to_owned()); + return Some(language.text(outcome).to_owned()); } self.remote_browser.entries.is_empty().then(|| "此目录为空。".to_owned()) } diff --git a/nebula_app/src/gpui_shell/workspace/settings_navigation.rs b/nebula_app/src/gpui_shell/workspace/settings_navigation.rs index 8436707..f18ee29 100644 --- a/nebula_app/src/gpui_shell/workspace/settings_navigation.rs +++ b/nebula_app/src/gpui_shell/workspace/settings_navigation.rs @@ -132,7 +132,9 @@ impl NebulaWorkspace { return self.tab_presentation(index, cx, dark); } TabPresentation { - title: super::workspace_ui_language().text(crate::i18n::Message::CommonSettings).into(), + title: crate::gpui_shell::config::ui_language(cx) + .text(crate::i18n::Message::CommonSettings) + .into(), tooltip: None, is_settings: true, activity: SidebarActivity::Idle, diff --git a/nebula_app/src/gpui_shell/workspace/sidebar_resize.rs b/nebula_app/src/gpui_shell/workspace/sidebar_resize.rs index 852a6a8..7e9ffeb 100644 --- a/nebula_app/src/gpui_shell/workspace/sidebar_resize.rs +++ b/nebula_app/src/gpui_shell/workspace/sidebar_resize.rs @@ -61,7 +61,7 @@ impl NebulaWorkspace { || self.settings_open || self.reader_focus_active(cx) || self.tabs_position == nebula_settings::TabsPositionName::Top - || !nebula_settings::RuntimeSettings::load().panel_resize + || !crate::gpui_shell::config::panel_resize(cx) { return None; } diff --git a/nebula_app/src/gpui_shell/workspace/update_dialog.rs b/nebula_app/src/gpui_shell/workspace/update_dialog.rs index 1703c91..3eac282 100644 --- a/nebula_app/src/gpui_shell/workspace/update_dialog.rs +++ b/nebula_app/src/gpui_shell/workspace/update_dialog.rs @@ -195,7 +195,7 @@ pub(crate) fn open_update_dialog( let dialog_result = result.clone(); window.open_dialog(cx, move |dialog, window, cx| { - let language = workspace_ui_language(); + let language = crate::gpui_shell::config::ui_language(cx); let title: SharedString = language.pick("Pebrel 更新", "Pebrel Update").into(); let current_label: SharedString = language.pick("当前版本", "Current").into(); let latest_label: SharedString = language.pick("最新版本", "Latest").into(); From 522b3381efb9836af91403509abe4ba137a1d911 Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Mon, 21 Sep 2026 22:08:17 +0800 Subject: [PATCH 02/40] Fix generic agent test fixture path collision --- nebula_app/src/platform/agent_integrations.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nebula_app/src/platform/agent_integrations.rs b/nebula_app/src/platform/agent_integrations.rs index 01d5f92..0a3fee6 100644 --- a/nebula_app/src/platform/agent_integrations.rs +++ b/nebula_app/src/platform/agent_integrations.rs @@ -197,8 +197,9 @@ mod tests { executable(dir.path(), "agent"); executable(dir.path(), "cursor"); assert_eq!(find_executable(AgentKind::Cursor, &[dir.path().to_path_buf()]), None); - let cli = executable(dir.path(), "cursor-agent"); - assert_eq!(find_executable(AgentKind::Cursor, &[dir.path().to_path_buf()]), Some(cli)); + let cli_dir = tempfile::tempdir().unwrap(); + let cli = executable(cli_dir.path(), "cursor-agent"); + assert_eq!(find_executable(AgentKind::Cursor, &[cli_dir.path().to_path_buf()]), Some(cli)); } #[test] From 6dc10e1aa538b409c5b630e529cb59bdf84140b0 Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Mon, 21 Sep 2026 22:08:20 +0800 Subject: [PATCH 03/40] Synchronize file path test background checks --- nebula_app/src/gpui_shell/workspace/details_panel_tests.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nebula_app/src/gpui_shell/workspace/details_panel_tests.rs b/nebula_app/src/gpui_shell/workspace/details_panel_tests.rs index c679fe2..3a0eb74 100644 --- a/nebula_app/src/gpui_shell/workspace/details_panel_tests.rs +++ b/nebula_app/src/gpui_shell/workspace/details_panel_tests.rs @@ -73,6 +73,7 @@ fn file_path_edit_navigates_and_keeps_the_last_directory_on_error_or_escape( cx.simulate_keystrokes("ctrl-a"); cx.simulate_input("中文 folder"); cx.simulate_keystrokes("enter"); + cx.background_executor.run_until_parked(); cx.run_until_parked(); workspace.read_with(&cx, |view, _| { assert!(view.file_tree_path.is_none()); @@ -92,6 +93,7 @@ fn file_path_edit_navigates_and_keeps_the_last_directory_on_error_or_escape( cx.update(|window, cx| window.draw(cx).clear(cx)); assert!(cx.debug_bounds("file-tree-path-editor").is_some()); cx.simulate_keystrokes("enter"); + cx.background_executor.run_until_parked(); cx.run_until_parked(); workspace.read_with(&cx, |view, _| { assert!( @@ -106,6 +108,7 @@ fn file_path_edit_navigates_and_keeps_the_last_directory_on_error_or_escape( cx.simulate_keystrokes("ctrl-a"); cx.simulate_input("missing-directory"); cx.simulate_keystrokes("enter"); + cx.background_executor.run_until_parked(); cx.run_until_parked(); workspace.read_with(&cx, |view, _| { assert!(view.file_tree_path_error().is_some()); From b0caec9dcbe32b1b3ab39de88137c7ebb461362f Mon Sep 17 00:00:00 2001 From: kuddev Date: Wed, 23 Sep 2026 12:18:02 +0800 Subject: [PATCH 04/40] ci: gate merges on all platforms and structure issue intake Pull requests: `lint (fmt, clippy)` and `pr-size` join the required checks together with all five `Tests ()` jobs and both `Release workspace` jobs, so a PR can no longer merge with a red platform. Draft PRs run the three fast platforms on every push; marking ready for review adds Intel Mac and Windows ARM64. `pr-size` labels size/S-XL and fails above 1500 changed source lines unless a maintainer adds `size-exempt`. Issues: the bug form now asks for OS version, shell, program in the pane, connection type, non-default settings and mandatory logs/screenshots, with log paths per platform. `issue-labels` turns the dropdowns into os:/area: labels, flags regressions, and parks reports without usable steps, evidence or a version as needs-info with a checklist comment; an edit that fills the gaps clears the label. config.yml pointed at the old nebula repository. --- .github/ISSUE_TEMPLATE/bug_report.yml | 179 ++++++++++++++++----- .github/ISSUE_TEMPLATE/config.yml | 15 +- .github/ISSUE_TEMPLATE/feature_request.yml | 65 +++++--- .github/workflows/issue-labels.yml | 154 ++++++++++++++++++ .github/workflows/linux-lua.yml | 85 ++++++++-- .github/workflows/pr-size.yml | 81 ++++++++++ CONTRIBUTING.md | 15 +- 7 files changed, 510 insertions(+), 84 deletions(-) create mode 100644 .github/workflows/issue-labels.yml create mode 100644 .github/workflows/pr-size.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3796169..cc77e86 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,114 +1,215 @@ -name: Bug Report -description: Report a reproducible problem in Nebula +name: Bug Report / 问题反馈 +description: Report a reproducible problem in Pebrel / 反馈一个可复现的问题 title: "[Bug] " labels: ["bug", "triage"] body: - type: markdown attributes: value: | - Thanks for taking the time to report a bug. Please search existing issues first and include enough detail for someone else to reproduce the problem. + Thanks for taking the time to report a bug. A report we can reproduce gets fixed in the next release; one we cannot reproduce is asked for details and waits. + 感谢反馈。**能复现的问题会进下个版本;说不清的问题只能先挂起等补充。** 下拉选项会自动转成标签。 - type: dropdown id: platform attributes: - label: Operating system + label: Operating system / 操作系统 options: - Windows + - Windows (WSL) - macOS - Linux - - Other + - Other / 其他 + validations: + required: true + + - type: input + id: os_version + attributes: + label: OS version and display / 系统版本与显示 + description: Windows 11 23H2 / macOS 26.0 / Ubuntu 24.04; DPI scaling and monitor count if display-related. / 系统版本;渲染问题请附缩放比例与显示器数量。 + placeholder: "Windows 11 23H2, 150% scaling, 2 monitors" validations: required: true - type: input id: version attributes: - label: Nebula version - description: Find it in Settings > Home, or on the latest release page. - placeholder: "e.g. 1.0.0" + label: Pebrel version / 版本号 + description: Settings > Home, or the release page. / 设置 > 主页,或发布页。 + placeholder: "e.g. 1.9.0" validations: required: true - type: dropdown id: install_source attributes: - label: How did you install Nebula? + label: How did you install Pebrel? / 安装方式 options: - - GitHub Release (.msi / .exe / portable archive) - - Built from source (cargo build / cargo run) - - Other + - GitHub Release (.exe / .zip / .dmg / .AppImage / .deb) + - Built from source / 源码构建 (cargo build) + - Other / 其他 + validations: + required: true + + - type: dropdown + id: shell + attributes: + label: Shell in the affected pane / 出问题的面板用的 Shell + multiple: true + options: + - PowerShell 7 (pwsh) + - Windows PowerShell 5.1 + - cmd + - WSL (bash / zsh inside WSL) + - Git Bash / MSYS2 + - zsh + - bash + - fish + - nushell + - Not sure / 不确定 + validations: + required: true + + - type: dropdown + id: program + attributes: + label: Program running in the pane / 面板里正在跑的程序 + description: What was running when it happened? / 出问题时面板里跑着什么? + multiple: true + options: + - Nothing, plain shell prompt / 什么都没跑 + - Claude Code + - Codex CLI + - Pi + - Gemini CLI / other AI agent — 其他 AI agent + - Terminal multiplexer (screen etc.) — 终端复用器 + - vim / nvim / other full-screen TUI — 全屏 TUI + - ssh client / remote shell — 远程 shell + - A long-running command (build, ping, adb…) — 长时间运行的命令 + - Other / 其他 + validations: + required: true + + - type: dropdown + id: connection + attributes: + label: Connection type / 连接方式 + options: + - Local terminal / 本地终端 + - SSH via Pebrel host list / Pebrel 内 SSH 主机 + - SSH via command line (ssh user@host) / 手动 ssh 命令 + - WSL + - Other / 其他 validations: required: true - type: dropdown id: area attributes: - label: Affected area + label: Affected area / 影响范围 + description: Pick every area that applies. / 可多选。 multiple: true options: - - Local terminal / shell - - SSH connection / authentication - - SFTP / file tree - - Tabs / splits / sessions - - AI assistant / providers - - Settings / backup / sync - - UI / layout / rendering - - Startup / crash - - Other + - Terminal rendering / scrolling / selection / garbled text — 终端渲染、滚动、选区、乱码 + - Shell startup / PATH / start directory / context menu — Shell 启动、环境变量、起始目录、右键菜单 + - SSH / proxy / jump host — SSH、代理、跳板 + - File tree / drag-and-drop upload — 文件树、拖拽上传 + - Tabs / splits / session restore / window size — 标签页、分屏、会话恢复、窗口尺寸 + - AI agent (Claude Code / Codex / Pi / OMP) — AI Agent 集成与状态 + - Markdown / LaTeX / image reader — 阅读页与内联渲染 + - Settings / theme / layout / blur — 设置页、主题、布局、模糊背景 + - Keyboard / IME / mouse / shortcuts / clipboard — 键盘、输入法、鼠标、快捷键、剪贴板 + - Git / SVN + - Startup crash / hang / cannot exit — 启动崩溃、卡死、无法退出 + - Performance / lag — 性能、卡顿 + - Installer / update / packaging — 安装包、更新、打包 + - Other / 其他 + validations: + required: true + + - type: dropdown + id: regression + attributes: + label: Did it work in a previous version? / 旧版本是否正常? + options: + - Not sure / 不确定 + - Yes, it worked before / 旧版本正常,新版本坏了 + - No, it never worked / 一直如此 validations: required: true - type: dropdown id: reproducibility attributes: - label: Can you reproduce it? + label: Can you reproduce it? / 复现概率 options: - - Always (100%) - - Often (>50%) - - Sometimes - - Once / not sure + - Always (100%) / 必现 + - Often (>50%) / 经常 + - Sometimes / 偶尔 + - Once / not sure / 仅一次 validations: required: true - type: textarea id: steps attributes: - label: Steps to reproduce - description: Use numbered steps and include the shell or connection type when relevant. + label: Steps to reproduce / 复现步骤 + description: | + Numbered, from a fresh launch, ending at the exact moment it goes wrong. "It's laggy" or "it doesn't work" cannot be acted on. + 从启动开始按序编号,写到出错的那一步为止。"很卡"、"不好用"这种一句话我们没法处理。 placeholder: | - 1. Open Nebula - 2. Create or connect to ... - 3. ... + 1. Launch Pebrel, open a new PowerShell 7 tab + 2. Run `codex` and ask it to ... + 3. Split the pane with Ctrl+Shift+D + 4. Output overlaps the input box at the bottom (see screenshot) validations: required: true - type: textarea id: expected attributes: - label: Expected behavior + label: Expected behavior / 期望结果 validations: required: true - type: textarea id: actual attributes: - label: Actual behavior + label: Actual behavior / 实际结果 + description: What you see instead, including any error text verbatim. / 实际看到什么,错误文字原样贴。 validations: required: true - type: textarea id: logs attributes: - label: Logs / screenshots - description: Include relevant lines or screenshots. Remove passwords, private keys, tokens, host addresses, and other secrets. + label: Logs / screenshots / 日志或截图 + description: | + Required. Screenshot or short recording for anything visual; log lines for crashes, hangs and connection problems. Remove passwords, keys, tokens and host addresses first. + 必填。显示类问题贴截图或短录屏;崩溃、卡死、连接类问题贴日志。请先删掉密码、私钥、token、主机地址。 + Logs / 日志位置: + - Windows: `%APPDATA%\Pebrel\pebrel_debug.log` and `%TEMP%\Pebrel-.log` + - macOS: `~/Library/Application Support/Pebrel/pebrel_debug.log` and `$TMPDIR/Pebrel-.log` + - Linux: `~/.config/pebrel/pebrel_debug.log` and `/tmp/Pebrel-.log` placeholder: Paste redacted logs or drag screenshots here. + validations: + required: true + + - type: textarea + id: settings + attributes: + label: Non-default settings / 改过的设置 + description: Theme, font, transparency/blur, GPU, shell profile, hooks — anything changed from defaults. Attach settings.txt if unsure. / 改过的主题、字体、透明/模糊、GPU、Shell 配置、hooks;不确定就贴 settings.txt。 + placeholder: "Acrylic blur on, opacity 85%, font JetBrains Mono 13" - type: checkboxes id: checklist attributes: - label: Before submitting + label: Before submitting / 提交前确认 options: - - label: I searched existing issues and did not find a duplicate + - label: I searched existing issues and did not find a duplicate / 已搜索,无重复 required: true - - label: I removed passwords, private keys, tokens, and other secrets from this report + - label: I tested with the latest release / 已用最新版本试过 + required: true + - label: I removed passwords, private keys, tokens and other secrets / 已删除敏感信息 required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 78ab859..71de4e8 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,11 @@ blank_issues_enabled: false contact_links: - - name: Existing issues - url: https://github.com/Kuddev/nebula/issues - about: Search existing reports before opening a new issue. - - name: Latest release - url: https://github.com/Kuddev/nebula/releases/latest - about: Check whether the problem is already fixed in the latest version. + - name: Existing issues / 已有 issue + url: https://github.com/Kuddev/pebrel/issues + about: Search existing reports before opening a new issue. / 先搜一下是否已有人反馈。 + - name: Latest release / 最新版本 + url: https://github.com/Kuddev/pebrel/releases/latest + about: Check whether the problem is already fixed in the latest version. / 看看最新版是否已修复。 + - name: Discord + url: https://discord.gg/VFn4rcxmhn + about: Quick questions and discussion. / 快速提问与交流。 diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 736a5a2..d231b6c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,5 +1,5 @@ -name: Feature Request -description: Suggest an improvement or new capability for Nebula +name: Feature Request / 功能建议 +description: Suggest an improvement or new capability for Pebrel / 提出改进或新功能 title: "[Feature] " labels: ["enhancement", "triage"] body: @@ -7,12 +7,13 @@ body: attributes: value: | Describe the workflow problem first, then the change you want. Concrete examples make the request easier to evaluate. + 先说现在哪里不顺手,再说希望怎么改。具体的使用场景最有说服力。 - type: textarea id: problem attributes: - label: Problem / pain point - description: What is hard, missing, or repetitive today? + label: Problem / pain point — 现在的痛点 + description: What is hard, missing, or repetitive today? / 什么事难做、缺失、或者每天重复? placeholder: When I work with multiple terminals or hosts, I cannot ... validations: required: true @@ -20,50 +21,66 @@ body: - type: textarea id: solution attributes: - label: Proposed solution - description: What would you like Nebula to do? + label: Proposed solution — 希望的做法 + description: What would you like Pebrel to do? / 希望 Pebrel 怎么做? validations: required: true - type: textarea id: alternatives attributes: - label: Alternatives considered - description: List workarounds, other tools, or designs you considered. - validations: - required: true + label: Alternatives considered — 现在的替代办法 + description: Workarounds, other tools, or designs you considered. / 目前怎么绕过去的,别的终端怎么做的。 + + - type: dropdown + id: platform + attributes: + label: Platform / 平台 + description: Leave empty if it applies everywhere. / 全平台通用可不选。 + multiple: true + options: + - Windows + - Windows (WSL) + - macOS + - Linux - type: dropdown id: area attributes: - label: Related area + label: Related area / 相关范围 multiple: true options: - - Local terminal / shell - - SSH / SFTP - - Tabs / splits / sessions - - AI assistant / providers - - Settings / backup / sync - - UI / UX - - Other + - Terminal rendering / scrolling / selection — 终端渲染、滚动、选区 + - Shell startup / PATH / start directory / context menu — Shell 启动、环境变量、起始目录、右键菜单 + - SSH / proxy / jump host — SSH、代理、跳板 + - File tree / drag-and-drop upload — 文件树、拖拽上传 + - Tabs / splits / session restore / window size — 标签页、分屏、会话恢复、窗口尺寸 + - AI agent (Claude Code / Codex / Pi / OMP) — AI Agent 集成与状态 + - Markdown / LaTeX / image reader — 阅读页与内联渲染 + - Settings / theme / layout / blur — 设置页、主题、布局、模糊背景 + - Keyboard / IME / mouse / shortcuts / clipboard — 键盘、输入法、鼠标、快捷键、剪贴板 + - Git / SVN + - Performance / lag — 性能、卡顿 + - Installer / update / packaging — 安装包、更新、打包 + - Other / 其他 validations: required: true - type: dropdown id: priority attributes: - label: How important is this to you? + label: How important is this to you? / 对你有多重要 options: - - Nice to have - - Would improve my daily workflow - - Blocking / critical for my use case + - Nice to have / 有更好 + - Would improve my daily workflow / 每天都会用到 + - Blocking / critical for my use case / 没有就没法用 validations: required: true - type: checkboxes id: checklist attributes: - label: Before submitting + label: Before submitting / 提交前确认 options: - - label: I searched existing issues for similar requests + - label: I searched existing issues for similar requests / 已搜索,无重复 required: true diff --git a/.github/workflows/issue-labels.yml b/.github/workflows/issue-labels.yml new file mode 100644 index 0000000..2b4c412 --- /dev/null +++ b/.github/workflows/issue-labels.yml @@ -0,0 +1,154 @@ +name: Issue labels + +# Turns the dropdown answers of the issue forms (.github/ISSUE_TEMPLATE/*.yml) +# into labels and flags bug reports that are too thin to act on. Labels are +# only added; maintainers' manual labels are never removed. + +on: + issues: + types: [opened, edited] + +permissions: + issues: write + +concurrency: + group: issue-labels-${{ github.event.issue.number }} + cancel-in-progress: true + +jobs: + label-from-form: + name: label-from-form + runs-on: ubuntu-24.04 + timeout-minutes: 5 + steps: + - name: Map form answers to labels + uses: actions/github-script@v7 + with: + script: | + const issue = context.payload.issue; + const body = issue.body || ""; + + // Issue forms render every field as "###