@aigne/doc-smith 0.9.8-alpha.13 → 0.9.8-alpha.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +439 -0
- package/README.md +188 -30
- package/agents/bash-executor/index.mjs +8 -3
- package/agents/content-checker/ai/intent.md +187 -0
- package/agents/content-checker/clean-invalid-docs.mjs +254 -0
- package/agents/content-checker/index.mjs +41 -8
- package/agents/content-checker/validate-content.mjs +143 -22
- package/agents/generate-images/generate-summary.mjs +1 -1
- package/agents/localize/index.yaml +1 -1
- package/agents/localize/translate-documents/translate-document-to-language.mjs +1 -1
- package/agents/localize/translate-documents/translate-to-languages.yaml +1 -1
- package/agents/localize/translate-images/scan-doc-images.mjs +5 -4
- package/agents/publish/ai/intent.md +171 -0
- package/agents/publish/check.mjs +36 -8
- package/agents/publish/publish-docs.mjs +12 -9
- package/agents/publish/translate-meta.mjs +56 -50
- package/aigne.yaml +5 -3
- package/feature-design/sources-image-path/implementation-plan.md +178 -0
- package/feature-design/sources-image-path/intent.md +170 -0
- package/feature-design/update-workspace-init.md +278 -0
- package/feature-design/workspace-paths-abstraction.md +195 -0
- package/package.json +1 -1
- package/scripts/install.sh +1 -1
- package/{doc-smith → skills/doc-smith}/SKILL.md +35 -38
- package/skills/doc-smith/ai/intent/sources-improve.md +290 -0
- package/{doc-smith → skills/doc-smith}/references/document-content-guide.md +17 -19
- package/skills/doc-smith/references/workspace-initialization.md +376 -0
- package/skills/doc-smith-docs-detail/SKILL.md +365 -0
- package/skills/doc-smith-docs-detail/ai/intent.md +271 -0
- package/skills-entry/doc-smith/ai/intent/doc-smith.md +237 -0
- package/skills-entry/doc-smith/index.mjs +66 -0
- package/{prompts/doc-smith.md → skills-entry/doc-smith/prompt.md} +2 -2
- package/skills-entry/doc-smith/utils.mjs +27 -0
- package/skills-entry/doc-smith-docs-detail/batch.yaml +56 -0
- package/skills-entry/doc-smith-docs-detail/index.mjs +93 -0
- package/skills-entry/doc-smith-docs-detail/prompt.md +64 -0
- package/utils/afs-factory.mjs +183 -0
- package/utils/agent-constants.mjs +17 -13
- package/utils/config.mjs +8 -12
- package/utils/docs-converter.mjs +109 -10
- package/utils/files.mjs +2 -4
- package/utils/image-slots.mjs +1 -2
- package/utils/sources-path-resolver.mjs +76 -0
- package/utils/workspace.mjs +338 -0
- package/doc-smith/references/workspace-initialization.md +0 -320
- package/doc-smith.yaml +0 -49
- /package/{doc-smith → skills/doc-smith}/references/changeset-guide.md +0 -0
- /package/{doc-smith → skills/doc-smith}/references/document-structure-schema.md +0 -0
- /package/{doc-smith → skills/doc-smith}/references/patch-guide.md +0 -0
- /package/{doc-smith → skills/doc-smith}/references/structure-confirmation-guide.md +0 -0
- /package/{doc-smith → skills/doc-smith}/references/structure-planning-guide.md +0 -0
- /package/{doc-smith → skills/doc-smith}/references/update-workflow.md +0 -0
- /package/{doc-smith → skills/doc-smith}/references/user-intent-guide.md +0 -0
package/CLAUDE.md
CHANGED
|
@@ -41,3 +41,442 @@
|
|
|
41
41
|
|
|
42
42
|
- 具体的 Skill 开发规范、文件结构、内容要求等,请通过 `/skill-creator` 动态获取
|
|
43
43
|
- skill-creator 会提供最新的最佳实践和详细指导
|
|
44
|
+
|
|
45
|
+
## Intent 文档编写规范
|
|
46
|
+
|
|
47
|
+
### Intent 文档的作用
|
|
48
|
+
|
|
49
|
+
Intent 文档用于描述功能的意图、约束和预期结果,是任何新功能实施前的设计文档。
|
|
50
|
+
|
|
51
|
+
**适用场景**:
|
|
52
|
+
- 创建新的 Skill
|
|
53
|
+
- 开发新的 Agent 工具
|
|
54
|
+
- 添加新的功能模块
|
|
55
|
+
- 实现新的特性或能力
|
|
56
|
+
|
|
57
|
+
**文件位置**:
|
|
58
|
+
- Skill:`skills/{skill-name}/ai/intent.md`
|
|
59
|
+
- Agent:`agents/{agent-name}/ai/intent.md`
|
|
60
|
+
- 功能模块:`feature-design/{feature-name}/intent.md`
|
|
61
|
+
- 其他:在相关目录下创建 `ai/intent.md` 或 `intent.md`
|
|
62
|
+
|
|
63
|
+
**重要原则**:
|
|
64
|
+
- ✅ **描述意图**,不包含具体实现细节和伪代码
|
|
65
|
+
- ✅ **说明约束**,明确功能边界和职责
|
|
66
|
+
- ✅ **定义预期**,清晰的成功标准
|
|
67
|
+
- ❌ 不包含伪代码或具体实现步骤
|
|
68
|
+
|
|
69
|
+
### Intent 文档通用结构
|
|
70
|
+
|
|
71
|
+
```markdown
|
|
72
|
+
# {功能名称} 功能意图
|
|
73
|
+
|
|
74
|
+
## 功能概述
|
|
75
|
+
[一句话概述功能是什么]
|
|
76
|
+
|
|
77
|
+
## 功能意图
|
|
78
|
+
[为什么需要这个功能,要解决什么问题,背景是什么]
|
|
79
|
+
|
|
80
|
+
## 工作流程
|
|
81
|
+
[在整体系统中的位置,与其他组件的交互时序,调用关系]
|
|
82
|
+
|
|
83
|
+
## 核心能力
|
|
84
|
+
[功能的主要能力点,列举 3-5 个关键能力]
|
|
85
|
+
|
|
86
|
+
## 输入输出
|
|
87
|
+
### 输入
|
|
88
|
+
- 必需输入:[必须提供的信息]
|
|
89
|
+
- 可选输入:[可选提供的信息]
|
|
90
|
+
- 自动获取:[从配置或上下文自动获取的信息]
|
|
91
|
+
|
|
92
|
+
### 输出
|
|
93
|
+
- 输出内容:[功能产生的结果]
|
|
94
|
+
- 输出格式:[结果的格式或结构]
|
|
95
|
+
|
|
96
|
+
## 约束条件
|
|
97
|
+
### 必须遵循的规范
|
|
98
|
+
[格式规范、标准、协议等]
|
|
99
|
+
|
|
100
|
+
### 职责边界
|
|
101
|
+
- 必须执行:[这个功能必须做的事]
|
|
102
|
+
- 不应执行:[这个功能不应该做的事]
|
|
103
|
+
- 协作方式:[与其他组件的协作关系]
|
|
104
|
+
|
|
105
|
+
## 预期结果
|
|
106
|
+
### 成功标准
|
|
107
|
+
[如何判断功能成功,具体的标准]
|
|
108
|
+
|
|
109
|
+
## 错误处理
|
|
110
|
+
### 常见错误
|
|
111
|
+
[可能遇到的错误场景]
|
|
112
|
+
|
|
113
|
+
### 处理策略
|
|
114
|
+
[如何处理这些错误]
|
|
115
|
+
|
|
116
|
+
## 实现方式
|
|
117
|
+
[实现的技术选型、架构设计、集成方式等说明]
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
**注意**:本文档描述功能意图,不包含具体实现细节。
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 编写要点
|
|
124
|
+
|
|
125
|
+
1. **保持精简**
|
|
126
|
+
- 减少冗长的示例和解释
|
|
127
|
+
- 每个部分点到即止,突出核心要点
|
|
128
|
+
- 避免重复说明相同的内容
|
|
129
|
+
|
|
130
|
+
2. **不包含代码**
|
|
131
|
+
- ❌ 不要写伪代码或代码示例
|
|
132
|
+
- ❌ 不要写函数签名或类定义
|
|
133
|
+
- ✅ 可以用文字描述逻辑流程
|
|
134
|
+
- ✅ 可以用流程图(文本格式)展示步骤
|
|
135
|
+
- ✅ 可以用目录结构(文本格式)展示文件组织
|
|
136
|
+
|
|
137
|
+
3. **明确实现类型**
|
|
138
|
+
- 说明功能是 Skill、Agent、JS 脚本还是其他类型
|
|
139
|
+
- 对于 JS 脚本:说明它是纯 JS 实现,不依赖 LLM 能力
|
|
140
|
+
- 对于 Agent:说明它是 LLM 驱动的对话式功能
|
|
141
|
+
|
|
142
|
+
4. **框架 API 说明**
|
|
143
|
+
- 列出使用的框架 API 名称和用途,但不写代码示例
|
|
144
|
+
- 例如:使用 `options.prompts.select` 实现语言选择(单选列表)
|
|
145
|
+
- 例如:使用 `options.context.invoke()` 调用其他 agent
|
|
146
|
+
- 例如:使用 `options.context.userContext` 存储全局状态
|
|
147
|
+
|
|
148
|
+
5. **明确输入输出**
|
|
149
|
+
- 区分"必需输入"、"可选输入"和"自动获取"
|
|
150
|
+
- 必需输入:调用时必须提供的参数
|
|
151
|
+
- 可选输入:可以选择性提供的参数
|
|
152
|
+
- 自动获取:从配置文件、上下文、环境变量等自动获取的信息
|
|
153
|
+
- 输出要明确格式和内容范围
|
|
154
|
+
|
|
155
|
+
6. **清晰的职责边界**
|
|
156
|
+
- 明确功能"必须执行"的操作(核心职责)
|
|
157
|
+
- 明确功能"不应执行"的操作(边界约束)
|
|
158
|
+
- 说明与其他组件的协作方式和依赖关系
|
|
159
|
+
|
|
160
|
+
7. **节省上下文考虑**
|
|
161
|
+
- 如果功能生成大量内容,考虑返回摘要而非完整内容
|
|
162
|
+
- 在输出格式中明确说明返回内容的范围
|
|
163
|
+
- 避免在流程中传递过大的数据
|
|
164
|
+
|
|
165
|
+
8. **实现方式指导**
|
|
166
|
+
- 说明技术选型和架构设计思路
|
|
167
|
+
- 对于 Skill:说明 skills-entry 配置结构、需要注册的工具
|
|
168
|
+
- 对于 Agent:说明输入输出 schema、依赖的其他 agent
|
|
169
|
+
- 对于 JS 脚本:说明文件位置、注册方式、依赖的框架 API
|
|
170
|
+
|
|
171
|
+
### 设计与实施的关系
|
|
172
|
+
|
|
173
|
+
Intent 文档是设计阶段的产物,实施阶段会基于它创建具体的实现:
|
|
174
|
+
|
|
175
|
+
| 阶段 | 文档 | 内容 |
|
|
176
|
+
|------|------|------|
|
|
177
|
+
| **设计** | intent.md | 描述"做什么"和"为什么" |
|
|
178
|
+
| **实施** | 实现文件 | 描述"怎么做"的具体流程 |
|
|
179
|
+
|
|
180
|
+
**不同场景的实施文件**:
|
|
181
|
+
- Skill → `SKILL.md`(使用 `/skill-creator` 创建)
|
|
182
|
+
- Agent → `index.yaml` 或 `index.mjs`
|
|
183
|
+
- 模块 → 源代码文件(`.js`, `.mjs`, `.py` 等)
|
|
184
|
+
|
|
185
|
+
### 工作流程
|
|
186
|
+
|
|
187
|
+
1. **创建 intent.md**
|
|
188
|
+
- 在相应目录下创建 `ai/intent.md` 或 `intent.md`
|
|
189
|
+
- 与相关人员讨论确认设计方案
|
|
190
|
+
- 明确功能边界、输入输出、约束条件
|
|
191
|
+
|
|
192
|
+
2. **基于 intent 实施**
|
|
193
|
+
- Skill:使用 `/skill-creator` 基于 intent.md 创建 SKILL.md
|
|
194
|
+
- Agent:创建 agent 实现和配置文件
|
|
195
|
+
- 模块:编写源代码实现
|
|
196
|
+
|
|
197
|
+
3. **完善配置**
|
|
198
|
+
- 创建必要的 entry 配置(如 `skills-entry/` 中的 yaml)
|
|
199
|
+
- 注册到父级组件中
|
|
200
|
+
- 添加必要的依赖和工具
|
|
201
|
+
|
|
202
|
+
### 示例参考
|
|
203
|
+
|
|
204
|
+
- **Skill Intent**:`skills/doc-smith-docs-detail/ai/intent.md`
|
|
205
|
+
- **功能设计**:`feature-design/` 目录下的设计文档
|
|
206
|
+
|
|
207
|
+
## 代码质量规范
|
|
208
|
+
|
|
209
|
+
### 安全性
|
|
210
|
+
|
|
211
|
+
- **路径验证**:处理用户输入的路径时,必须拒绝包含 `..` 的路径遍历序列
|
|
212
|
+
- **命令执行**:优先使用 `spawn` 配合参数数组,避免 shell 字符串拼接
|
|
213
|
+
|
|
214
|
+
### 代码组织
|
|
215
|
+
|
|
216
|
+
- **单一职责**:每个模块只负责一类功能,避免混合多种职责
|
|
217
|
+
- **消除重复**:相同逻辑必须提取到共享模块(如 `utils/`),不要复制粘贴
|
|
218
|
+
- **删除死代码**:未使用的函数、变量必须删除,不要保留"以备后用"
|
|
219
|
+
|
|
220
|
+
### 共享模块位置
|
|
221
|
+
|
|
222
|
+
| 功能 | 模块 |
|
|
223
|
+
|------|------|
|
|
224
|
+
| Workspace 检测和初始化 | `utils/workspace.mjs` |
|
|
225
|
+
| AFS 模块生成 | `utils/afs-factory.mjs` |
|
|
226
|
+
| 路径常量 | `utils/agent-constants.mjs` |
|
|
227
|
+
| 配置文件操作 | `utils/config.mjs` |
|
|
228
|
+
|
|
229
|
+
### 危险操作
|
|
230
|
+
|
|
231
|
+
- **文件删除**:必须提供 `dryRun` 选项,允许预览将要删除的内容
|
|
232
|
+
- **批量操作**:在执行前应验证数据源(如 YAML 文件)的完整性
|
|
233
|
+
|
|
234
|
+
### 代码检查
|
|
235
|
+
|
|
236
|
+
- **每次修改后检查 lint**:执行 `pnpm lint:fix` 检查并自动修复问题
|
|
237
|
+
- **提交前确保通过**:不要提交带有 lint 错误的代码
|
|
238
|
+
|
|
239
|
+
## AIGNE 框架开发指南
|
|
240
|
+
|
|
241
|
+
### Function Agent 基本结构
|
|
242
|
+
|
|
243
|
+
Function Agent 是纯 JS 实现的 agent,不依赖 LLM 能力,用于执行确定性逻辑。
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
// 基本结构
|
|
247
|
+
export default async function agentName(input, options) {
|
|
248
|
+
const { prompts, context } = options;
|
|
249
|
+
|
|
250
|
+
// 业务逻辑...
|
|
251
|
+
|
|
252
|
+
return { success: true, data: result };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// 可选:描述和输入 schema
|
|
256
|
+
agentName.description = "Agent 功能描述";
|
|
257
|
+
agentName.input_schema = {
|
|
258
|
+
type: "object",
|
|
259
|
+
properties: {
|
|
260
|
+
param1: { type: "string", description: "参数说明" }
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Prompts API(用户交互)
|
|
266
|
+
|
|
267
|
+
通过 `options.prompts` 访问交互 API:
|
|
268
|
+
|
|
269
|
+
| API | 用途 | 示例 |
|
|
270
|
+
|-----|------|------|
|
|
271
|
+
| `select(config)` | 单选列表 | 语言选择、模式选择 |
|
|
272
|
+
| `checkbox(config)` | 多选列表 | 功能开关、多语言选择 |
|
|
273
|
+
| `input(config)` | 文本输入 | URL 输入、名称输入 |
|
|
274
|
+
| `search(config)` | 搜索选择 | 文件路径搜索 |
|
|
275
|
+
|
|
276
|
+
**select 配置**:
|
|
277
|
+
```javascript
|
|
278
|
+
const result = await prompts.select({
|
|
279
|
+
message: "提示信息",
|
|
280
|
+
choices: [
|
|
281
|
+
{ name: "显示名称", value: "返回值", description: "描述" }
|
|
282
|
+
],
|
|
283
|
+
default: "默认值"
|
|
284
|
+
});
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**checkbox 配置**:
|
|
288
|
+
```javascript
|
|
289
|
+
const results = await prompts.checkbox({
|
|
290
|
+
message: "提示信息",
|
|
291
|
+
choices: [...],
|
|
292
|
+
validate: (input) => input.length > 0 || "至少选择一项"
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**input 配置**:
|
|
297
|
+
```javascript
|
|
298
|
+
const text = await prompts.input({
|
|
299
|
+
message: "提示信息",
|
|
300
|
+
default: "默认值",
|
|
301
|
+
validate: (input) => input.trim() !== "" || "不能为空"
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**search 配置**:
|
|
306
|
+
```javascript
|
|
307
|
+
const selected = await prompts.search({
|
|
308
|
+
message: "提示信息",
|
|
309
|
+
source: async (input) => {
|
|
310
|
+
// 根据 input 返回选项数组
|
|
311
|
+
return [{ name: "显示", value: "值", description: "描述" }];
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Context API(上下文和调用)
|
|
317
|
+
|
|
318
|
+
通过 `options.context` 访问上下文 API:
|
|
319
|
+
|
|
320
|
+
| API | 用途 |
|
|
321
|
+
|-----|------|
|
|
322
|
+
| `context.agents` | 已注册的 agent 字典 |
|
|
323
|
+
| `context.invoke(agent, params)` | 调用其他 agent |
|
|
324
|
+
| `context.userContext` | 全局用户上下文(可读写) |
|
|
325
|
+
|
|
326
|
+
**获取 agent**:
|
|
327
|
+
```javascript
|
|
328
|
+
const agent = context.agents?.["agentName"];
|
|
329
|
+
if (!agent) {
|
|
330
|
+
throw new Error("Agent not found");
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**调用 agent**:
|
|
335
|
+
```javascript
|
|
336
|
+
const result = await context.invoke(agent, { message: "输入内容" });
|
|
337
|
+
// 或直接传入参数对象
|
|
338
|
+
const result = await context.invoke(agent, { param1: "value1" });
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**全局上下文**:
|
|
342
|
+
```javascript
|
|
343
|
+
// 写入
|
|
344
|
+
context.userContext.customField = "value";
|
|
345
|
+
|
|
346
|
+
// 读取(在其他 agent 中)
|
|
347
|
+
const value = context.userContext.customField;
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### aigne.yaml 配置结构
|
|
351
|
+
|
|
352
|
+
```yaml
|
|
353
|
+
#!/usr/bin/env aigne
|
|
354
|
+
|
|
355
|
+
model: anthropic/claude-sonnet-4-5
|
|
356
|
+
|
|
357
|
+
# 注册 agents(供 context.agents 访问)
|
|
358
|
+
agents:
|
|
359
|
+
- path/to/agent.yaml
|
|
360
|
+
- path/to/function-agent.mjs
|
|
361
|
+
|
|
362
|
+
# CLI 命令配置
|
|
363
|
+
cli:
|
|
364
|
+
agents:
|
|
365
|
+
- name: command-name # CLI 命令名
|
|
366
|
+
alias: ["alias1"] # 命令别名
|
|
367
|
+
url: path/to/entry.mjs # 入口文件
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Agent YAML 配置
|
|
371
|
+
|
|
372
|
+
```yaml
|
|
373
|
+
type: "@aigne/agent-library/agent-skill-manager"
|
|
374
|
+
name: agentName # context.agents 中的键名
|
|
375
|
+
instructions:
|
|
376
|
+
url: ./prompt.md
|
|
377
|
+
|
|
378
|
+
input_key: message # 输入参数键名
|
|
379
|
+
|
|
380
|
+
skills:
|
|
381
|
+
- path/to/skill.yaml
|
|
382
|
+
- path/to/function.mjs
|
|
383
|
+
|
|
384
|
+
afs:
|
|
385
|
+
modules:
|
|
386
|
+
- module: local-fs
|
|
387
|
+
options:
|
|
388
|
+
name: moduleName
|
|
389
|
+
localPath: ./path
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### 常见开发模式
|
|
393
|
+
|
|
394
|
+
**1. 入口 Agent 模式**
|
|
395
|
+
|
|
396
|
+
入口 agent(如 init.mjs)负责初始化,然后调用主 agent:
|
|
397
|
+
|
|
398
|
+
```javascript
|
|
399
|
+
export default async function init(input, options) {
|
|
400
|
+
// 1. 初始化逻辑
|
|
401
|
+
// 2. 设置全局上下文
|
|
402
|
+
options.context.userContext.workspace = "/path";
|
|
403
|
+
|
|
404
|
+
// 3. 调用主 agent
|
|
405
|
+
const mainAgent = options.context.agents?.["main"];
|
|
406
|
+
if (mainAgent) {
|
|
407
|
+
await options.context.invoke(mainAgent, { message: "初始化完成" });
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return { success: true };
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**2. 条件调用模式**
|
|
415
|
+
|
|
416
|
+
根据条件决定是否调用其他 agent:
|
|
417
|
+
|
|
418
|
+
```javascript
|
|
419
|
+
export default async function wrapper(input, options) {
|
|
420
|
+
if (input.skipCondition) {
|
|
421
|
+
return input; // 跳过,直接返回
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const agent = options.context.agents?.["targetAgent"];
|
|
425
|
+
const result = await options.context.invoke(agent, input);
|
|
426
|
+
return { ...input, ...result };
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**3. 任务渲染模式**
|
|
431
|
+
|
|
432
|
+
控制 agent 在 UI 中的显示方式:
|
|
433
|
+
|
|
434
|
+
```javascript
|
|
435
|
+
// 隐藏任务
|
|
436
|
+
agentName.task_render_mode = "hide";
|
|
437
|
+
|
|
438
|
+
// 折叠任务
|
|
439
|
+
agentName.task_render_mode = "collapse";
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### 参考实现
|
|
443
|
+
|
|
444
|
+
- **入口 Agent**:`skills-entry/doc-smith/index.mjs`
|
|
445
|
+
- **Function Agent**:`agents/content-checker/index.mjs`
|
|
446
|
+
- **共享模块**:`utils/workspace.mjs`、`utils/afs-factory.mjs`
|
|
447
|
+
|
|
448
|
+
## 设计决策原则
|
|
449
|
+
|
|
450
|
+
### KISS 原则应用
|
|
451
|
+
|
|
452
|
+
在设计功能时,优先考虑最简方案。复杂度不是功能强大的标志,往往是设计不成熟的表现。
|
|
453
|
+
|
|
454
|
+
**案例:Workspace 与主项目的关系**
|
|
455
|
+
|
|
456
|
+
| 方案 | 复杂度 | 问题 |
|
|
457
|
+
|------|--------|------|
|
|
458
|
+
| ❌ 自动添加 submodule | 高 | 本地路径无法共享、需要手动同步远程 |
|
|
459
|
+
| ✅ 添加到 .gitignore | 低 | 简单、无副作用、用户自主选择 |
|
|
460
|
+
|
|
461
|
+
**决策过程**:
|
|
462
|
+
1. 先问"为什么需要这个功能?"而不是"如何实现这个功能?"
|
|
463
|
+
2. 识别出 submodule 解决的是"追踪子项目版本",但 doc-smith 不需要这种强耦合
|
|
464
|
+
3. 最简方案:独立 git 仓库 + gitignore,用户需要时自行决定如何关联
|
|
465
|
+
|
|
466
|
+
### 问对的问题
|
|
467
|
+
|
|
468
|
+
遇到技术问题时,先审视问题本身是否正确:
|
|
469
|
+
|
|
470
|
+
| 错误的问题 | 正确的问题 |
|
|
471
|
+
|-----------|-----------|
|
|
472
|
+
| 如何让 submodule URL 自动同步? | 为什么需要 submodule? |
|
|
473
|
+
| 如何处理复杂的边界情况? | 这个功能是否应该存在? |
|
|
474
|
+
| 如何让用户更容易使用? | 用户真正需要什么? |
|
|
475
|
+
|
|
476
|
+
**原则**:如果一个功能需要大量边界处理,可能说明功能本身的抽象层次有问题。
|
|
477
|
+
|
|
478
|
+
### 默认行为设计
|
|
479
|
+
|
|
480
|
+
- **默认做最少的事**:不自作主张添加可能有问题的配置
|
|
481
|
+
- **复杂操作由用户显式触发**:提供可选命令而非自动执行
|
|
482
|
+
- **松耦合优于强耦合**:让组件独立存在,用户自主决定关联方式
|