Skip to content
Closed
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
26 changes: 26 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# EditorConfig - https://editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.swift]
indent_size = 4
trim_trailing_whitespace = true

[*.{yml,yaml}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[*.{json,plist}]
indent_size = 2

[Makefile]
indent_style = tab
52 changes: 52 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
name: Bug 报告
about: 发现了一个 Bug
title: '[Bug] '
labels: 'type/bug, status/triage'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Issue template labels is a single string and will likely not apply multiple labels as intended.

labels is currently a single string ('type/bug, status/triage'), so GitHub will treat it as one label. To apply both labels, use a YAML list instead:

labels:
  - type/bug
  - status/triage

This way both labels are added when the template is used.

assignees: ''
---

## Bug 描述

<!-- 简要描述你遇到的问题。 -->


## 复现步骤

1. 进入 '...'
2. 点击 '...'
3. 滚动到 '...'
4. 看到错误

## 预期行为

<!-- 描述你期望的正确行为。 -->


## 实际行为

<!-- 描述实际发生了什么。 -->


## 截图 / 录屏

<!-- 如果可能,请附上截图或录屏帮助说明问题。 -->


## 环境信息

- **平台**: [iOS / watchOS / macOS]
- **App 版本**: [例如 1.7.0 (Build 328)]
- **分发通道**: [App Store / TestFlight / 自编译]
- **设备型号**: [例如 iPhone 13, Apple Watch Series 9]
- **系统版本**: [例如 iOS 26.1 / watchOS 26.1]
- **语言设置**: [例如 zh-Hans]

## 日志

<!-- 如果有错误日志或崩溃报告,请粘贴在此处。 -->


## 补充说明

<!-- 其他你认为有助于诊断问题的信息。 -->
37 changes: 37 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: 功能建议
about: 有一个新功能的想法
title: '[Feature] '
labels: 'type/feature, status/triage'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Feature request template labels field likely needs to be a list rather than a single comma-separated string.

labels: 'type/feature, status/triage' will be parsed as a single label. To apply both type/feature and status/triage, define them as a list:

labels:
  - type/feature
  - status/triage

assignees: ''
---

## 功能描述

<!-- 简要描述你想要的功能。 -->


## 使用场景

<!-- 描述你在什么场景下需要这个功能,解决什么问题。 -->


## 期望的交互方式

<!-- 描述你想象中这个功能应该如何工作。 -->


## 替代方案

<!-- 你是否考虑过其他替代方案?请描述。 -->


## 影响平台

- [ ] iOS
- [ ] watchOS
- [ ] macOS(Catalyst)

## 补充说明

<!-- 其他你认为有助于理解这个需求的信息、参考截图或链接。 -->
48 changes: 48 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## 变更说明

<!-- 简要描述这个 PR 做了什么,解决什么问题或实现什么功能。 -->


## 关联 Issue

<!-- 如果此 PR 关联某个 Issue,请在此链接,例如:Fixes #80 -->


## 变更类型

- [ ] Bug 修复
- [ ] 新功能
- [ ] 重构
- [ ] 性能优化
- [ ] 文档更新
- [ ] 其他(请说明)

## 影响范围

- [ ] iOS App
- [ ] watchOS App
- [ ] ETOSCore 框架
- [ ] MCP / 工具中心
- [ ] 本地模型 (llama.cpp)
- [ ] 记忆 / RAG
- [ ] 同步引擎
- [ ] 其他(请说明)

## 测试情况

- [ ] 已在 iOS 模拟器/真机测试
- [ ] 已在 watchOS 模拟器/真机测试
- [ ] 已通过 CI 编译检查
- [ ] 已新增/修改单元测试

## 截图(UI 变更时必填)

<!-- 如果修改了 UI,请附上修改前后的截图或录屏。 -->


## Checklist

- [ ] 代码遵循项目的代码规范
- [ ] 提交信息遵循语义化格式
- [ ] 已自测通过,不会引入新的 Bug
- [ ] 文档已同步更新(如有必要)
2 changes: 2 additions & 0 deletions .github/workflows/pr-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
steps:
- name: 检出代码
uses: actions/checkout@v4
with:
submodules: recursive

- name: 显示 Xcode 版本
run: xcodebuild -version
Expand Down
93 changes: 93 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# SwiftLint Configuration
# https://github.com/realm/SwiftLint

# 排除第三方依赖和构建产物
excluded:
- Dependencies
- .build
- DerivedData
- docs
- assets
- ci_scripts
- scripts

# 禁用的规则(根据项目风格调整)
disabled_rules:
- trailing_comma # 允许尾随逗号
- force_cast # 项目中部分 force cast 为已知安全
- force_try # 项目中部分 force try 用于编译期已知正则
- type_body_length # 大型 ViewModel 需要更多行数
- file_length # 部分文件较大但结构清晰
- function_body_length # 部分函数逻辑较长
- cyclomatic_complexity # 部分函数分支较多
- nesting # 允许嵌套类型

# 启用的规则
opt_in_rules:
- empty_count # 使用 isEmpty 而非 count == 0
- closure_spacing # 闭包内空格
- contains_over_filter_count # 使用 contains 而非 filter().count > 0
- contains_over_filter_is_empty # 使用 contains 而非 filter().isEmpty
- contains_over_first_not_nil # 使用 contains 而非 first != nil
- empty_string # 使用 isEmpty 而非 == ""
- fallthrough # 避免无注释的 fallthrough
- fatal_error_message # fatalError 应有消息
- first_where # 使用 first(where:) 而非 filter().first
- last_where # 使用 last(where:) 而非 filter().last
- modifier_order # 修饰符顺序
- overridden_super_call # 重写方法应调用 super
- private_action # IBAction 应为 private
- private_outlet # IBOutlet 应为 private
- redundant_nil_coalescing # 避免冗余的 nil 合并
- sorted_first_last # 使用 min/max 而非 sorted().first/last
- toggle_bool # 使用 toggle() 而非 = !value
- unavailable_function # 避免调用不可用函数
- unowned_variable_capture # 避免 unowned 捕获
- vertical_whitespace_closing_braces # 闭合大括号前无空行
- yoda_condition # 避免 Yoda 条件

# 命名规则
identifier_name:
min_length:
warning: 2
error: 1
max_length:
warning: 60
error: 80
excluded:
- id
- i
- x
- y
- z

# 行长度
line_length:
warning: 120
error: 160
ignores_urls: true
ignores_comments: true
ignores_interpolated_strings: true

# 类型名长度
type_name:
min_length:
warning: 3
error: 2
max_length:
warning: 60
error: 80

# 缩进
indentation:
width: 4
conditional: 4

# 垂直间距
vertical_whitespace:
max_empty_lines: 2

# 强制换行
wrap:
mode: soft
line_length: 120
109 changes: 109 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# 贡献指南

感谢你对 ETOS LLM Studio 的兴趣!无论是修 Bug、加功能、改善文档还是提建议,我们都非常欢迎。

## 快速开始

1. **Fork** 本仓库并克隆到本地:
```bash
git clone --recurse-submodules https://github.com/<你的用户名>/ETOS-LLM-Studio.git
cd ETOS-LLM-Studio
```
2. 确保你已安装 **Xcode 26.0+** 以及 **CMake + Ninja**(`brew install cmake ninja`)。
3. 创建功能分支:
```bash
git checkout -b fix/你的分支名
```
4. 进行修改、测试、提交。
5. 向 `main` 分支发起 Pull Request。

## 编译指南

详细的编译步骤请参考 [README.md](README.md#-编译指南)。

简要流程:
1. 先编译 llama.cpp 静态库(运行 `scripts/build-llama-static-library.sh`)。
2. 打开 `ETOS LLM Studio.xcworkspace`(注意是 **workspace**,不是 xcodeproj)。
3. 选择对应的 Scheme(iOS App 或 Watch App),Command + R 运行。

## 代码规范

- **语言**:Swift 6,请遵循 Swift API Design Guidelines。
- **架构**:MVVM + Protocol Oriented Programming。
- **平台逻辑**:业务逻辑放在 `ETOSCore/ETOSCore/`,视图层分别放在 iOS App 或 Watch App 目录。
- **文件头**:每个文件顶部使用标准三行注释格式说明文件职责:
```swift
// ============================================================================
// FileName.swift
// ============================================================================
// 简要描述本文件的职责与归属模块。
// ============================================================================
```
- **命名**:类型用 `PascalCase`,属性和方法用 `camelCase`,常量用 `camelCase`。
- **注释**:关键逻辑使用中文注释;公开 API 使用 `///` 文档注释。
- **@AppStorage**:已全面替代为 `AppConfigStore`,新增配置项请走 `AppConfigStore`。
- **数据库**:数据持久化使用 GRDB + SQLite,新增存储请走 GRDB Migration。

## 提交规范

使用语义化提交信息,格式如下:

```
<type>(<scope>): <描述>

[可选正文]
[可选脚注]
```

**type** 类型:
| 类型 | 说明 |
|------|------|
| `feat` | 新功能 |
| `fix` | Bug 修复 |
| `refactor` | 重构(不新增功能、不修 Bug) |
| `perf` | 性能优化 |
| `style` | 代码格式调整(不影响逻辑) |
| `docs` | 文档变更 |
| `test` | 新增或修改测试 |
| `chore` | 构建、工具、CI 等变更 |

**scope** 示例:`聊天`, `Watch`, `MCP`, `记忆`, `同步`, `UI`, `配置`, `安全`, `LLM` 等。

示例:
```
fix(语音输入): 修复 iPhone 端停止录音后缺少预览确认流程
feat(Watch): 支持语音识别结果预览后再填入输入框
refactor(ChatService): 将会话标签管理拆分到独立 extension
```

## 报告 Bug

请使用 [Issue 模板](https://github.com/Eric-Terminal/ETOS-LLM-Studio/issues/new?template=bug_report.md),并包含以下信息:

- 平台(iOS / watchOS / macOS)
- App 版本与 Build 号
- 设备型号与系统版本
- 复现步骤
- 预期行为 vs 实际行为
- 日志(如有)

## 功能建议

请使用 [Feature Request 模板](https://github.com/Eric-Terminal/ETOS-LLM-Studio/issues/new?template=feature_request.md) 描述你的想法。如果你打算自己实现,请先开 Issue 讨论方案,避免重复劳动。

## Pull Request 流程

1. 确保你的分支基于最新的 `main`。
2. PR 标题遵循提交规范格式。
3. 填写 PR 模板中的所有必填项。
4. 确保 CI 编译检查通过(iOS + watchOS 均可编译)。
5. 如果修改了 UI,请附上截图或录屏。
6. 等待 Review,根据反馈进行修改。

## 行为准则

请尊重每一位参与者。我们不接受任何形式的骚扰、歧视或人身攻击。

## 许可证

本项目使用 [GPL-3.0](LICENSE) 协议。提交代码即表示你同意你的贡献在 GPL-3.0 下授权。
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class ChatViewModel: ObservableObject {
@Published var isRecordingSpeech: Bool = false
@Published var speechTranscriptionInProgress: Bool = false
@Published var speechStreamingTranscript: String = ""
@Published var isShowingTranscriptPreview: Bool = false
@Published var speechErrorMessage: String?
@Published var showSpeechErrorAlert: Bool = false
@Published var showDimensionMismatchAlert: Bool = false
Expand Down
Loading
Loading