Skip to content

Commit 79c90e0

Browse files
committed
feat: Add ollama translator support
--story=1
1 parent e4b5fc7 commit 79c90e0

File tree

21 files changed

+1243
-78
lines changed

21 files changed

+1243
-78
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
name: OpenSpec: 实施
3+
description: 实施已批准的OpenSpec变更并保持任务同步。
4+
category: OpenSpec
5+
tags: [openspec, apply]
6+
---
7+
<!-- OPENSPEC:START -->
8+
**护栏规则**
9+
- 优先使用简单、最小的实现,仅在请求或明确需要时才添加复杂性。
10+
- 将变更紧密限制在请求的结果范围内。
11+
- 如果需要额外的OpenSpec约定或澄清,请参考`openspec/AGENTS.md`(位于`openspec/`目录中—如果看不到,请运行`ls openspec``openspec-cn update`)。
12+
13+
**步骤**
14+
将这些步骤作为TODO跟踪并逐一完成。
15+
1. 阅读`openspec/changes/<id>/proposal.md``design.md`(如果存在)和`tasks.md`以确认范围和验收标准。
16+
2. 按顺序完成任务,保持编辑最小化并专注于请求的变更。
17+
3. 在更新状态前确认完成—确保`tasks.md`中的每个项目都已完成。
18+
4. 所有工作完成后更新清单,使每个任务标记为`- [x]`并反映实际情况。
19+
5. 需要额外上下文时参考`openspec-cn list``openspec-cn show <item>`
20+
21+
**参考**
22+
- 如果在实施过程中需要提案的额外上下文,请使用`openspec-cn show <id> --json --deltas-only`
23+
<!-- OPENSPEC:END -->
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
name: OpenSpec: 归档
3+
description: 归档已部署的OpenSpec变更并更新规范。
4+
category: OpenSpec
5+
tags: [openspec, archive]
6+
---
7+
<!-- OPENSPEC:START -->
8+
**护栏规则**
9+
- 优先使用简单、最小的实现,仅在请求或明确需要时才添加复杂性。
10+
- 将变更紧密限制在请求的结果范围内。
11+
- 如果需要额外的OpenSpec约定或澄清,请参考`openspec/AGENTS.md`(位于`openspec/`目录中—如果看不到,请运行`ls openspec``openspec-cn update`)。
12+
13+
**步骤**
14+
1. 确定要归档的变更ID:
15+
- 如果此提示已包含特定变更ID(例如在由斜杠命令参数填充的`<ChangeId>`块内),在修剪空格后使用该值。
16+
- 如果对话松散地引用变更(例如通过标题或摘要),运行`openspec-cn list`以显示可能的ID,分享相关候选者,并确认用户意图归档哪一个。
17+
- 否则,查看对话,运行`openspec-cn list`,并询问用户要归档哪个变更;在继续前等待确认的变更ID。
18+
- 如果仍然无法识别单个变更ID,停止并告诉用户您还无法归档任何内容。
19+
2. 通过运行`openspec-cn list`(或`openspec-cn show <id>`)验证变更ID,如果变更缺失、已归档或尚未准备好归档,则停止。
20+
3. 运行`openspec-cn archive <id> --yes`,以便CLI在没有提示的情况下移动变更并应用规范更新(仅对仅工具工作使用`--skip-specs`)。
21+
4. 查看命令输出以确认目标规范已更新且变更已放入`openspec/changes/archive/`
22+
5. 使用`openspec-cn validate --strict`验证,如果出现异常,使用`openspec-cn show <id>`检查。
23+
24+
**参考**
25+
- 在归档前使用`openspec-cn list`确认变更ID。
26+
- 使用`openspec-cn list --specs`检查刷新的规范,并在交前解决任何验证问题。
27+
<!-- OPENSPEC:END -->
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
name: OpenSpec: 提案
3+
description: 搭建新的OpenSpec变更提案并进行严格验证。
4+
category: OpenSpec
5+
tags: [openspec, change]
6+
---
7+
<!-- OPENSPEC:START -->
8+
**护栏规则**
9+
- 优先使用简单、最小的实现,仅在请求或明确需要时才添加复杂性。
10+
- 将变更紧密限制在请求的结果范围内。
11+
- 如果需要额外的OpenSpec约定或澄清,请参考`openspec/AGENTS.md`(位于`openspec/`目录中—如果看不到,请运行`ls openspec``openspec-cn update`)。
12+
- 识别任何模糊或不明确的细节,并在编辑文件前询问必要的后续问题。
13+
- 在提案阶段不要编写任何代码。仅创建设计文档(proposal.md、tasks.md、design.md和规范增量)。实施在批准后的apply阶段进行。
14+
15+
**步骤**
16+
1. 查看`openspec/project.md`,运行`openspec-cn list``openspec-cn list --specs`,并检查相关代码或文档(例如通过`rg`/`ls`)以使提案基于当前行为;注意任何需要澄清的空白。
17+
2. 选择唯一的动词开头`change-id`并在`openspec/changes/<id>/`下创建`proposal.md``tasks.md``design.md`(需要时)。
18+
3. 将变更映射为具体功能或需求,将多范围工作分解为具有明确关系和顺序的独立规范增量。
19+
4. 当解决方案跨越多个系统、引入新模式或在提交规范前需要权衡讨论时,在`design.md`中记录架构推理。
20+
5.`openspec/changes/<id>/specs/<capability>/spec.md`中起草规范增量(每个功能一个文件夹),使用`## 新增需求|修改需求|移除需求|重命名需求`,每个需求至少有一个`#### 场景:`,并在相关时交叉引用相关功能。
21+
6.`tasks.md`起草为有序的小型可验证工作项列表,这些项提供用户可见的进展,包括验证(测试、工具),并突出显示依赖关系或可并行工作。
22+
7. 使用`openspec-cn validate <id> --strict`验证并在分享提案前解决每个问题。
23+
24+
**参考**
25+
- 当验证失败时,使用`openspec-cn show <id> --json --deltas-only``openspec-cn show <spec> --type spec`检查详情。
26+
- 在编写新需求前,使用`rg -n "需求:|场景:" openspec/specs`搜索现有需求。
27+
- 使用`rg <keyword>``ls`或直接文件读取探索代码库,以便提案与当前实现现实保持一致。
28+
<!-- OPENSPEC:END -->

.codei18n/mappings.json

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@
176176
"zh-CN": "// Config 代表项目配置"
177177
},
178178
"12643a2e6591197284f266a6b70eb9a428be38d0": {
179-
"en": "// Verify the last doc comments (lines 15, 17, 18)\n// We expect them to be separate but have the same symbol"
179+
"en": "// Verify the last doc comments (lines 15, 17, 18)\n// We expect them to be separate but have the same symbol",
180+
"zh-CN": "// 验证最后的文档注释(第15、17、18行)\n// 我们希望它们是独立的但具有相同的符号"
180181
},
181182
"1311d6e062c85e73fb969ffe451e40f1630f6317": {
182183
"en": "// If I pass server.URL to NewLLMTranslator, the client will append /chat/completions?",
@@ -475,7 +476,8 @@
475476
"zh-CN": "// 块注释 /* */"
476477
},
477478
"2972276bec78563545bf4fe31350177a7bd5e811": {
478-
"en": "// Verify range logic for first comment (line 1)"
479+
"en": "// Verify range logic for first comment (line 1)",
480+
"zh-CN": "// 验证第一条注释(第1行)的范围逻辑"
479481
},
480482
"2aa5b10fd959f6d7a34647fca6b0bb705129c105": {
481483
"en": "// - If zh-CN exists but en is missing: zh-CN -\u003e en",
@@ -566,7 +568,8 @@
566568
"zh-CN": "// GenerateCommentID 为评论计算一个稳定的ID"
567569
},
568570
"32e60c112bd0efa971fb7c9196461e55d8630829": {
569-
"en": "/// This is an optimization that allows us to keep using the static precompiles"
571+
"en": "/// This is an optimization that allows us to keep using the static precompiles",
572+
"zh-CN": "/// 这是一种优化,允许我们继续使用静态预编译合约"
570573
},
571574
"338f41c80244b4be6d7a151887fbeeb46cdce772": {
572575
"en": "// Create the content to hash",
@@ -877,7 +880,8 @@
877880
"zh-CN": "// LanguageAdapter 定义了语言特定解析器的接口"
878881
},
879882
"543f716248798f3acd7c15dee782360393de062c": {
880-
"en": "// Line 17"
883+
"en": "// Line 17",
884+
"zh-CN": "// 第17行"
881885
},
882886
"55cf0f288a1869934366533f97c2e4d25d295a2a": {
883887
"en": "// Append content\n// Ensure we have a newline between them if not present in the last one",
@@ -908,7 +912,8 @@
908912
"zh-CN": "// 确定策略"
909913
},
910914
"58ec13c61728d38e31e55efd6b36342f81dfc3f2": {
911-
"en": "//! It happened on Ethereum block 1_920_000"
915+
"en": "//! It happened on Ethereum block 1_920_000",
916+
"zh-CN": "//! 这发生在以太坊区块 1_920_000"
912917
},
913918
"5a7adb029281a1a578262900b2e3858e677bf683": {
914919
"en": "// Normalize current comment text for comparison",
@@ -947,7 +952,8 @@
947952
"zh-CN": "// Version 是映射文件格式的版本号(例如:\"1.0\""
948953
},
949954
"5f25ee88be7bdce1231e3d92513b03fb6204d6f2": {
950-
"en": "// good"
955+
"en": "// good",
956+
"zh-CN": "// 好"
951957
},
952958
"5f9a3b66d0c811823df0e16c9bcfe939990b65b3": {
953959
"en": "// Mixed batch, fallback to sequential loop manually here\n// This shouldn't happen often if we sort, but safety net.",
@@ -1102,7 +1108,8 @@
11021108
"zh-CN": "// - 如果存在英文版本但缺少中文简体版本:英文 -\u003e 中文简体"
11031109
},
11041110
"724a4e4b73aeb0efed82ddce315d7e237ff59f0a": {
1105-
"en": "// Line 15"
1111+
"en": "// Line 15",
1112+
"zh-CN": "// 第15行"
11061113
},
11071114
"725c0ca4655e8edf6ff0d91fc134e2ab89da386f": {
11081115
"en": "// var result map[string]interface{}",
@@ -1361,7 +1368,8 @@
13611368
"zh-CN": "// Mapping 表示映射文件的结构"
13621369
},
13631370
"8e97132c83930a78177bb7133078f0fc7dd3cee0": {
1364-
"en": "//! DAO Fork related constants from [EIP-779](https://eips.ethereum.org/EIPS/eip-779)."
1371+
"en": "//! DAO Fork related constants from [EIP-779](https://eips.ethereum.org/EIPS/eip-779).",
1372+
"zh-CN": "//! 来自[EIP-779](https://eips.ethereum.org/EIPS/eip-779)的DAO分叉相关常量。"
13651373
},
13661374
"8ecb1b5c0b7cab6b8a3ab8cf964ffb26738ee732": {
13671375
"en": "// Check if ID exists",
@@ -1496,7 +1504,8 @@
14961504
"zh-CN": "// RustAdapter 为 Rust 语言实现了 LanguageAdapter 接口。\n// 它使用 Tree-sitter 解析 Rust 源代码,并提取注释及其上下文。"
14971505
},
14981506
"9e0769f27a5a61c5920154b1a31a031fe77f9aea": {
1499-
"en": "// luck"
1507+
"en": "// luck",
1508+
"zh-CN": "// 运气"
15001509
},
15011510
"9e9ff4ff1867057fb3508f8f3a3c7cee3e5c5ddf": {
15021511
"en": "// Comment represents a single comment extracted from AST",
@@ -1543,7 +1552,8 @@
15431552
"zh-CN": "// 它返回一个包含评论文本、位置和上下文符号的 domain.Comment 结构体列表。"
15441553
},
15451554
"a419be8974323121254abe6995f87c098872262d": {
1546-
"en": "// Expect 11 comments without merging:\n// 1. Inner doc (line 1)\n// 2. Inner doc (line 2)\n// 3. Inner doc (line 4)\n// 4. Outer doc (line 6)\n// 5. Line comment (line 8)\n// 6. Block comment (lines 9-10)\n// 7. Line comment (line 11)\n// 8. Line comment (line 12)\n// 9. Doc comment (line 15)\n// 10. Doc comment (line 17) - line 16 is empty and filtered\n// 11. Doc comment (line 18)"
1555+
"en": "// Expect 11 comments without merging:\n// 1. Inner doc (line 1)\n// 2. Inner doc (line 2)\n// 3. Inner doc (line 4)\n// 4. Outer doc (line 6)\n// 5. Line comment (line 8)\n// 6. Block comment (lines 9-10)\n// 7. Line comment (line 11)\n// 8. Line comment (line 12)\n// 9. Doc comment (line 15)\n// 10. Doc comment (line 17) - line 16 is empty and filtered\n// 11. Doc comment (line 18)",
1556+
"zh-CN": "// 预期有11条未合并的注释:\n// 1. 内部文档注释(第1行)\n// 2. 内部文档注释(第2行)\n// 3. 内部文档注释(第4行)\n// 4. 外部文档注释(第6行)\n// 5. 行注释(第8行)\n// 6. 块注释(第9-10行)\n// 7. 行注释(第11行)\n// 8. 行注释(第12行)\n// 9. 文档注释(第15行)\n// 10. 文档注释(第17行)- 第16行为空行已被过滤\n// 11. 文档注释(第18行)"
15471557
},
15481558
"a42bbc48bddf39a3604678b584e5271e273f1dea": {
15491559
"en": "// Test empty array",
@@ -1670,7 +1680,8 @@
16701680
"zh-CN": "// 但命令行界面可以扫描目录。"
16711681
},
16721682
"b0c4b4afb41326693301a70f826bbad28f563336": {
1673-
"en": "// Line 18"
1683+
"en": "// Line 18",
1684+
"zh-CN": "// 第18行"
16741685
},
16751686
"b0e8c7ede9066d54d8d0eac233cf1190b0a6e936": {
16761687
"en": "// [MOCK zh-CN-\u003een] // Remove comment markers",
@@ -2025,7 +2036,8 @@
20252036
"zh-CN": "// Tree-sitter 通常将 macro_rules! 的主体解析为令牌树或特定结构\n// 看看它是否能捕获注释。\n// 更新:这取决于语法中如何定义 'macro_rules'。\n// 如果它能提取出来,很好。如果不能,目前可以接受(根据规范)。"
20262037
},
20272038
"d10588558d7105c5b9504114eab6e27b4b342e3c": {
2028-
"en": "/// until we need to modify them, at which point we convert to the dynamic representation."
2039+
"en": "/// until we need to modify them, at which point we convert to the dynamic representation.",
2040+
"zh-CN": "/// 在需要修改之前,我们保持使用静态表示,需要修改时再转换为动态表示。"
20292041
},
20302042
"d119c66734dec806c571617b36d48bc0a2b31a0e": {
20312043
"en": "// Debug: Print mappings.json",
@@ -2132,7 +2144,8 @@
21322144
"zh-CN": "// 这是一个行注释,添加到缓冲区"
21332145
},
21342146
"d996bb683a5ad1c81f8565f44d68da8f20ca4dca": {
2135-
"en": "/// A mapping of precompile contracts that can be either static (builtin) or dynamic."
2147+
"en": "/// A mapping of precompile contracts that can be either static (builtin) or dynamic.",
2148+
"zh-CN": "/// 预编译合约的映射,可以是静态(内置)或动态的。"
21362149
},
21372150
"da486cda0e857bd7dd13c9ed12ca40a65c20030f": {
21382151
"en": "// c.SourceText is EN",

AGENTS.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!-- OPENSPEC:START -->
2+
# OpenSpec 使用说明
3+
4+
这些说明适用于在此项目中工作的AI助手。
5+
6+
## 语言偏好设置
7+
8+
**默认使用中文**:除非明确说明使用英文,否则所有输出都应使用中文,包括:
9+
- 文档内容
10+
- 代码注释
11+
- 提交信息
12+
- 规范说明
13+
14+
## 工作流程
15+
16+
当请求满足以下条件时,始终打开`@/openspec/AGENTS.md`
17+
- 提及规划或提案(如提案、规范、变更、计划等词语)
18+
- 引入新功能、重大变更、架构变更或大型性能/安全工作时
19+
- 听起来不明确,需要在编码前了解权威规范时
20+
21+
使用`@/openspec/AGENTS.md`了解:
22+
- 如何创建和应用变更提案
23+
- 规范格式和约定
24+
- 项目结构和指南
25+
26+
保持此托管块,以便'openspec-cn update'可以刷新说明。
27+
28+
<!-- OPENSPEC:END -->

CODEBUDDY.md

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
<!-- OPENSPEC:START -->
2+
# OpenSpec 使用说明
3+
4+
这些说明适用于在此项目中工作的AI助手。
5+
6+
## 语言偏好设置
7+
8+
**默认使用中文**:除非明确说明使用英文,否则所有输出都应使用中文,包括:
9+
- 文档内容
10+
- 代码注释
11+
- 提交信息
12+
- 规范说明
13+
14+
## 工作流程
15+
16+
当请求满足以下条件时,始终打开`@/openspec/AGENTS.md`
17+
- 提及规划或提案(如提案、规范、变更、计划等词语)
18+
- 引入新功能、重大变更、架构变更或大型性能/安全工作时
19+
- 听起来不明确,需要在编码前了解权威规范时
20+
21+
使用`@/openspec/AGENTS.md`了解:
22+
- 如何创建和应用变更提案
23+
- 规范格式和约定
24+
- 项目结构和指南
25+
26+
保持此托管块,以便'openspec-cn update'可以刷新说明。
27+
28+
<!-- OPENSPEC:END -->
29+
130
# CODEBUDDY.md
231

332
本文件为 CodeBuddy Code 在此仓库中工作时提供指导。
@@ -183,12 +212,17 @@ type Translator interface {
183212
```
184213

185214
### 策略
186-
- **本地缓存优先**(避免提交时实时调用 API)
187-
- 支持的后端:
188-
- DeepL
189-
- OpenAI
190-
- 自定义术语词典
191-
- 翻译失败可阻断提交(可配置)
215+
- **本地缓存优先**:优先复用已有翻译结果,避免在提交路径上频繁调用外部服务。
216+
- 支持的翻译后端(通过 `translationProvider` 选择):
217+
- 远程 LLM(`openai` / `llm`):基于 OpenAI 兼容协议的翻译服务(官方 OpenAI、DeepSeek 或自建代理),使用 `OPENAI_API_KEY` 和可选 `OPENAI_BASE_URL`
218+
- 本地 Ollama(`ollama`):调用本地 Ollama 实例的 REST API,使用本地模型(如 `llama3``qwen3` 等)。调用时默认关闭思维链(`think=false`),避免额外延迟。
219+
- Mock(`mock`):仅用于测试和集成测试,不用于生产环境。
220+
- 翻译失败可阻断提交(可配置),建议在 CI 环节或预翻译阶段完成大部分工作,在 pre-commit 仅做增量检查。
221+
222+
### 配置约定
223+
224+
- 顶层字段:`translationProvider``openai`/`llm`/`ollama`
225+
- 细节字段:`translationConfig`(如 `baseUrl``model``endpoint`
192226

193227
## 映射文件
194228

@@ -256,6 +290,11 @@ codei18n scan --file xxx.go --lang zh-CN --format json
256290
{
257291
"sourceLanguage": "en",
258292
"localLanguage": "zh-CN",
293+
"translationProvider": "openai",
294+
"translationConfig": {
295+
"baseUrl": "https://api.openai.com/v1",
296+
"model": "gpt-4.1-mini"
297+
},
259298
"ide": {
260299
"vscode": {
261300
"displayMode": "overlay"
@@ -267,6 +306,11 @@ codei18n scan --file xxx.go --lang zh-CN --format json
267306
}
268307
```
269308

309+
说明:
310+
- `translationProvider`:选择翻译后端,当前推荐 `openai`(也支持别名 `llm`)或本地 `ollama`
311+
- `translationConfig`:不同后端的细节配置,如 `baseUrl``model`(OpenAI/DeepSeek)或 `endpoint`(Ollama)。
312+
313+
270314
## 开发路线图
271315

272316
### v0.1 (MVP)

0 commit comments

Comments
 (0)