Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
状态:已实现

> Viva 迁移状态(2026-11-08):本文的分类规则继续作为目标,旧客户端的页面和实现细节不代表 Viva 已迁移。当前 Viva 设置侧栏的部分分组仍是占位;页面可用性以跨平台功能矩阵为准,新增页面仍按本规则归类。
>
> Viva 更新(2026-11-14):Viva 设置侧栏在 AI 之后增加一级页面“关于”,固定在最后。Viva 的分组关系只写在 `desktop/internal/settingswindow/model.go` 的 `parents` 表一处,侧栏、面包屑和展开逻辑都从它推导,作用相当于旧客户端的 `SettingsGroup`。

## 先说结论

macOS 设置侧栏现在只有七个一级入口:外观与行为、插件、版本控制、构建/执行/部署、语言与框架、工具、AI。每个设置页必须属于其中一个分组,分组与页面的对应关系只写在 `SettingsGroup` 一处,侧栏、面包屑和“打开设置时展开所属分组”都从它推导。新增设置页前先按下面的归属规则选分组,不要再加一级入口。
macOS 设置侧栏现在有七个一级分组入口:外观与行为、插件、版本控制、构建/执行/部署、语言与框架、工具、AI;最后是一级页面“关于”,它不是设置分组。每个设置页必须属于其中一个分组,分组与页面的对应关系只写在 `SettingsGroup` 一处,侧栏、面包屑和“打开设置时展开所属分组”都从它推导。新增设置页前先按下面的归属规则选分组,不要再加一级入口。

## 问题

Expand All @@ -25,6 +27,7 @@ macOS 设置侧栏现在只有七个一级入口:外观与行为、插件、
| 语言与框架 | 语言服务(LSP)的开关,以及 Spring Boot 等框架的配置 |
| 工具 | 终端等通用工具;插件带来的专用工具(例如 `.http` 请求)可以放进对应工具页。日志与诊断不属于设置,它是独立的日志窗口,见[结构化日志窗口](2026-11-03-structured-logging-log-window.md) |
| AI | 凡是和 AI 有关的都放这里:MCP、Skill、全局指令、AI 提交信息、Agents、AI 服务商 |
| 关于 | 应用本身是什么:版本信息(版本、平台、构建、运行时)、更新卡片(与“外观与行为 › 更新”共用同一份状态和操作)、交流群和项目链接;一级页面,固定在侧栏最后,不放任何设置项 |

插件如果带来了新的设置,默认放进“插件”页;只有它新增的是上表中某个分组本来就该有的能力(例如新的版本控制系统)时,才放进那个分组。

Expand Down Expand Up @@ -56,7 +59,8 @@ AI 分组里,Agent 可加载的资源(指令、技能、Hooks、MCP 配置

### 不要这样做

- 不要把页面直接加到 `SettingsSidebarItem.layout` 来绕开分组;一级页面只留给插件。
- 不要把页面直接加到 `SettingsSidebarItem.layout` 来绕开分组;一级页面只留给插件和“关于”。
- 不要把设置项放进“关于”。它只说明当前副本是什么、怎样更新、去哪里交流;更新的开关仍在“外观与行为 › 更新”。
- 不要在 `SettingsView` 里再写按页面分支的分组 `switch`,这正是本次删除的重复来源。
- 不要为某个语言或构建工具新增 `SettingsCategory`;让对应插件在清单里用 `page` 注册。

Expand All @@ -81,7 +85,7 @@ Issue 希望“构建工具 → Maven”“服务运行”“框架支持”也
- `SettingsSidebarLayoutTests` 保证每个页面恰好属于一个分组或是一级页面,并固定本表的分组内容与 AI 页面顺序。
- `SettingsSearchVocabularyTests` 保证每个页面仍能被检索到。
- 旧客户端的 [macOS 测试入口(历史版本)](https://github.com/1lck/Lithe-IDEA/blob/5a54c41aa37a4e6e6b68918a4b05765b9dd07a36/scripts/macos/test/test-macos.sh) 曾运行 `SettingsSidebarLayoutTests`;该检查不能证明 Viva 设置页已经对齐。
- `scripts/desktop/desktop-go.sh test ./internal/settingswindow` 验证当前 Viva 已实现的侧栏和设置窗口行为,不能替代尚未迁移页面的验收。
- `scripts/desktop/desktop-go.sh test ./internal/settingswindow` 验证当前 Viva 已实现的侧栏和设置窗口行为,包括“关于”排在 AI 之后、面包屑只有“关于”一级,不能替代尚未迁移页面的验收。
- 实机查看设置窗口的侧栏、面包屑、搜索展开和从其他入口跳转到某一页时展开所属分组。

## 适用范围
Expand Down
8 changes: 8 additions & 0 deletions .agents/skills/release-lithe/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ Apply these rules to every version number:
a release as a prerelease when no stable host can use it yet, whatever its
number. Keep the plain number and the plain tag (`v<version>`, or
`desktop-v<version>` for the desktop app), with no `-beta` or similar suffix.
- The desktop app shows its version without the preview label only when the
Desktop Release built it for the commit of its `desktop-v<version>` tag:
`scripts/ci/desktop-release/package-release.sh` packages with
`package-desktop.sh --stable`, which adds the `lithe_stable` build tag, and
fails when a packaged program lacks it. Every other build, including the
daily `desktop-AutoBuild` and local packages, shows the version with the
preview label. This label is independent of the GitHub prerelease flag. Pass
`--stable` nowhere else.
- Never reuse a published version or publish a lower one. A published package
is never modified; every change ships as a new version. The only exception
is a version reset that the user explicitly requests for one artifact:
Expand Down
10 changes: 9 additions & 1 deletion desktop/internal/buildinfo/buildinfo.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
// Package buildinfo tells a development build from a release one.
// Package buildinfo tells a development build from a packaged one, and a stable release from
// a preview.
package buildinfo

// Development reports whether this binary has the dev build tag. The build
// target in desktop/Makefile supplies the tag; packaged releases omit it.
const Development = development

// Stable reports whether this binary is a stable release: one packaged from the commit that
// carries its release tag, desktop-v<version> with the version in desktop/viva.toml.
// scripts/desktop/package-desktop.sh adds the lithe_stable build tag only then. Every other
// build, the daily AutoBuild, a local package or a development build, is a preview, and Lithe
// says so next to the version.
const Stable = stable
6 changes: 6 additions & 0 deletions desktop/internal/buildinfo/preview.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build !lithe_stable

package buildinfo

// stable is false in a build that was not packaged from its release tag.
const stable = false
6 changes: 6 additions & 0 deletions desktop/internal/buildinfo/stable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build lithe_stable

package buildinfo

// stable is true in a build packaged from its release tag.
const stable = true
10 changes: 5 additions & 5 deletions desktop/internal/i18n/app_messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ package i18n
func appMessages(language Language) AppMessages {
return AppMessages{
Name: Shared(language, "native.lithe"),
Version: func(version string) string {
return SharedFormat(language, "desktop.app.version", map[string]string{"version": version})
},
Core: func(version string) string {
return SharedFormat(language, "desktop.app.coreVersion", map[string]string{"version": version})
Version: func(version string, stable bool) string {
if stable {
return version
}
return SharedFormat(language, "desktop.app.previewVersion", map[string]string{"version": version})
},
DevBadge: Shared(language, "desktop.app.devBadge"),
}
Expand Down
12 changes: 7 additions & 5 deletions desktop/internal/i18n/i18n_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,13 @@ func TestSharedTemplateFormatsOnceAndPreservesUnknownPlaceholders(t *testing.T)
func TestApplicationVersionUsesSharedLanguage(t *testing.T) {
for _, test := range []struct {
language Language
version string
core string
preview string
}{
{English, "Version 1.2.3", "Core 1.2.3"},
{Chinese, "版本 1.2.3", "内核 1.2.3"},
{English, "1.2.3 Preview"},
{Chinese, "1.2.3 预览版"},
} {
messages := For(test.language).App
if messages.Name != "Lithe" || messages.DevBadge != "Dev" || messages.Version("1.2.3") != test.version || messages.Core("1.2.3") != test.core {
if messages.Name != "Lithe" || messages.DevBadge != "Dev" || messages.Version("1.2.3", false) != test.preview || messages.Version("1.2.3", true) != "1.2.3" {
t.Fatalf("language %s: application messages do not match the expected wording", test.language.Code())
}
}
Expand Down Expand Up @@ -327,6 +326,9 @@ func checkComplete(t *testing.T, path string, value reflect.Value) {
args[index] = reflect.ValueOf("x")
case reflect.Int:
args[index] = reflect.ValueOf(2)
case reflect.Bool:
// false is the side a translation is made for, as Version's preview label.
args[index] = reflect.ValueOf(false)
default:
t.Fatalf("%s takes an unsupported parameter type", path)
}
Expand Down
7 changes: 3 additions & 4 deletions desktop/internal/i18n/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ type Messages struct {
// AppMessages names the application.
type AppMessages struct {
Name string
// Version is the version line under the name, for example "Version 0.1.0".
Version func(version string) string
// Core is the core library line in the settings, for example "Core 0.1.0".
Core func(version string) string
// Version is the version as Lithe shows it: the plain version for a stable build, which
// was packaged from its desktop-v release tag, and "0.7.0 Preview" for any other.
Version func(version string, stable bool) string
// DevBadge is the mark a development build puts on the application's Dock icon.
DevBadge string
}
Expand Down
Loading
Loading