openfeel 1.1.5 → 1.1.7
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/README.en.md +25 -5
- package/README.md +22 -3
- package/README.zh-CN.md +26 -5
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +66 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/flow.d.ts +8 -0
- package/dist/commands/flow.d.ts.map +1 -1
- package/dist/commands/flow.js +169 -10
- package/dist/commands/flow.js.map +1 -1
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +59 -2
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +24 -2
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/stage.d.ts.map +1 -1
- package/dist/commands/stage.js +56 -2
- package/dist/commands/stage.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +16 -4
- package/dist/commands/update.js.map +1 -1
- package/dist/core/backup.d.ts.map +1 -1
- package/dist/core/backup.js +18 -5
- package/dist/core/backup.js.map +1 -1
- package/dist/core/claude-settings.d.ts +31 -0
- package/dist/core/claude-settings.d.ts.map +1 -0
- package/dist/core/claude-settings.js +120 -0
- package/dist/core/claude-settings.js.map +1 -0
- package/dist/core/config.d.ts +17 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +21 -6
- package/dist/core/config.js.map +1 -1
- package/dist/core/flow-manager.d.ts +71 -14
- package/dist/core/flow-manager.d.ts.map +1 -1
- package/dist/core/flow-manager.js +266 -51
- package/dist/core/flow-manager.js.map +1 -1
- package/dist/core/global-paths.d.ts +10 -0
- package/dist/core/global-paths.d.ts.map +1 -1
- package/dist/core/global-paths.js +21 -0
- package/dist/core/global-paths.js.map +1 -1
- package/dist/core/i18n-data/en.d.ts.map +1 -1
- package/dist/core/i18n-data/en.js +44 -9
- package/dist/core/i18n-data/en.js.map +1 -1
- package/dist/core/i18n-data/zh-CN.d.ts.map +1 -1
- package/dist/core/i18n-data/zh-CN.js +45 -9
- package/dist/core/i18n-data/zh-CN.js.map +1 -1
- package/dist/core/pipeline-schema.d.ts +5 -0
- package/dist/core/pipeline-schema.d.ts.map +1 -1
- package/dist/core/pipeline-schema.js +5 -0
- package/dist/core/pipeline-schema.js.map +1 -1
- package/dist/core/plan/scheme.d.ts +22 -0
- package/dist/core/plan/scheme.d.ts.map +1 -1
- package/dist/core/plan/scheme.js +71 -2
- package/dist/core/plan/scheme.js.map +1 -1
- package/dist/core/plan/stage.d.ts +2 -0
- package/dist/core/plan/stage.d.ts.map +1 -1
- package/dist/core/plan/stage.js +8 -0
- package/dist/core/plan/stage.js.map +1 -1
- package/dist/core/setup.d.ts +2 -2
- package/dist/core/setup.d.ts.map +1 -1
- package/dist/core/setup.js +81 -53
- package/dist/core/setup.js.map +1 -1
- package/dist/core/template-loader.d.ts +15 -0
- package/dist/core/template-loader.d.ts.map +1 -1
- package/dist/core/template-loader.js +4218 -145
- package/dist/core/template-loader.js.map +1 -1
- package/dist/core/update.d.ts +8 -0
- package/dist/core/update.d.ts.map +1 -1
- package/dist/core/update.js +368 -141
- package/dist/core/update.js.map +1 -1
- package/package.json +1 -1
package/dist/core/update.js
CHANGED
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { existsSync, readFileSync, mkdirSync } from 'node:fs';
|
|
10
10
|
import { resolve, dirname, join, basename, isAbsolute, relative } from 'node:path';
|
|
11
|
-
import { loadAgentTemplate, listAgentIds, loadTemplate } from './template-loader.js';
|
|
11
|
+
import { loadAgentTemplate, listAgentIds, loadTemplate, loadClaudeConstraintTemplate, loadClaudeAgentTemplate, listClaudeAgentIds } from './template-loader.js';
|
|
12
12
|
import { recordProjectLang } from './workspace/identity.js';
|
|
13
13
|
import { t, getCliLang } from './i18n.js';
|
|
14
|
-
import { getOpencodeGlobalDir, getGlobalAgentsDir, getGlobalSkillsDir, getGlobalCoreMdPath, getGlobalAgentsMdPath, getGlobalOpencodeJsoncPath, getGlobalUpdateStatePath } from './global-paths.js';
|
|
14
|
+
import { getOpencodeGlobalDir, getGlobalAgentsDir, getGlobalSkillsDir, getGlobalCoreMdPath, getGlobalAgentsMdPath, getGlobalOpencodeJsoncPath, getGlobalUpdateStatePath, getClaudeAgentsDir, getClaudeSkillsDir, getClaudeMdPath, getClaudeSettingsPath } from './global-paths.js';
|
|
15
15
|
import { mergeGlobalOpencodeJsonc, buildProjectOpencodeJsoncObj } from './opencode-config.js';
|
|
16
|
+
import { applyClaudeSettings } from './claude-settings.js';
|
|
16
17
|
import { atomicWriteFileSync } from './fs/atomic-write.js';
|
|
17
18
|
import { withFileLock, globalLockPath } from './fs/file-lock.js';
|
|
18
19
|
import { detectFileType, normalize, splitFrontmatter, parseRegion, wrapRegion, replaceRegion, mergeFrontmatter, serializeFrontmatter } from './managed-region.js';
|
|
@@ -29,8 +30,13 @@ export const supportedTools = [
|
|
|
29
30
|
description: 'OpenCode AI 编码助手 — 生成 Agent 定义和 openfeel-* 技能',
|
|
30
31
|
enabled: true,
|
|
31
32
|
},
|
|
33
|
+
{
|
|
34
|
+
id: 'claude',
|
|
35
|
+
name: 'Claude Code',
|
|
36
|
+
description: 'Anthropic Claude Code CLI — 生成 CLAUDE.md、Claude subagent 定义与共享 openfeel-* 技能',
|
|
37
|
+
enabled: false,
|
|
38
|
+
},
|
|
32
39
|
// 后续扩展:
|
|
33
|
-
// { id: 'claude', name: 'Claude Code', description: 'Anthropic Claude Code CLI', enabled: false },
|
|
34
40
|
// { id: 'cursor', name: 'Cursor', description: 'Cursor IDE', enabled: false },
|
|
35
41
|
];
|
|
36
42
|
/**
|
|
@@ -55,23 +61,51 @@ export async function selectTools() {
|
|
|
55
61
|
}
|
|
56
62
|
catch {
|
|
57
63
|
// 交互不可用时(如非 TTY 环境),回退到全部启用项
|
|
58
|
-
console.log('
|
|
64
|
+
console.log(t('update.nonInteractiveToolsTmpl', getCliLang(process.cwd())));
|
|
59
65
|
return supportedTools.filter((t) => t.enabled).map((t) => t.id);
|
|
60
66
|
}
|
|
61
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* 解析 `--tools` 逗号分隔列表。
|
|
70
|
+
* @returns tools=合法 id(保序去重);invalid=非法项。空串/纯空白视为非法(触发 exit 1)。
|
|
71
|
+
*/
|
|
72
|
+
export function parseToolList(raw) {
|
|
73
|
+
if (raw.trim() === '') {
|
|
74
|
+
return { tools: [], invalid: [''] };
|
|
75
|
+
}
|
|
76
|
+
const valid = new Set(supportedTools.map((t) => t.id));
|
|
77
|
+
const tools = [];
|
|
78
|
+
const invalid = [];
|
|
79
|
+
for (const part of raw.split(',')) {
|
|
80
|
+
const v = part.trim();
|
|
81
|
+
if (v === '') {
|
|
82
|
+
continue;
|
|
83
|
+
} // 忽略尾随/空段
|
|
84
|
+
if (!valid.has(v)) {
|
|
85
|
+
invalid.push(v);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (!tools.includes(v)) {
|
|
89
|
+
tools.push(v);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { tools, invalid };
|
|
93
|
+
}
|
|
62
94
|
// ─── Agent 定义由 template-loader.ts 统一管理 ──────────────────────────
|
|
63
95
|
// ─── Skill 定义内容 ─────────────────────────────────────────────────
|
|
64
96
|
// AUTO-GENERATED-BEGIN: SKILL_DEFINITIONS
|
|
65
97
|
export const SKILL_DEFINITIONS = {
|
|
66
98
|
'openfeel-agent-model-check': `---
|
|
67
99
|
name: openfeel-agent-model-check
|
|
68
|
-
description: Agent 模型检查与修复。当 Agent 报 "Model not found" 或需要排查模型配置时使用。涵盖 auth.json 校验(opencode 适配器)、provider key 匹配、模型能力确认、openfeel-vision
|
|
100
|
+
description: Agent 模型检查与修复。当 Agent 报 "Model not found" 或需要排查模型配置时使用。涵盖 auth.json 校验(opencode 适配器)、provider key 匹配、模型能力确认、openfeel-vision 多模态专项指南、Claude Code 侧模型(\`/model\`、网关)。
|
|
69
101
|
---
|
|
70
102
|
|
|
71
103
|
# Skill: openfeel-agent-model-check
|
|
72
104
|
|
|
73
105
|
# Agent 模型检查与修复
|
|
74
106
|
|
|
107
|
+
> 正文以**能力名**叙述;平台差异见 \`### opencode 适配器\` / \`### Claude Code 适配器\` 两小节。
|
|
108
|
+
|
|
75
109
|
## 何时使用
|
|
76
110
|
|
|
77
111
|
- Agent 调度时报 \`Model not found: xxx\`
|
|
@@ -89,22 +123,6 @@ Model not found: {provider_key}/{model_id}
|
|
|
89
123
|
|
|
90
124
|
注意是否有 \`Did you mean: xxx\` 提示——如有,直接使用建议的模型名。
|
|
91
125
|
|
|
92
|
-
### 第二步:读取 auth.json 确认实际 provider key
|
|
93
|
-
|
|
94
|
-
\`\`\`bash
|
|
95
|
-
# Windows PowerShell / macOS / Linux
|
|
96
|
-
cat ~/.local/share/opencode/auth.json
|
|
97
|
-
\`\`\`
|
|
98
|
-
|
|
99
|
-
**关键点**:模型引用中的 provider 部分必须与 \`auth.json\` 中的 key 完全一致,而非 \`opencode.jsonc\` 中 \`provider.name\` 或 \`provider.id\`。
|
|
100
|
-
|
|
101
|
-
常见 provider key 示例:
|
|
102
|
-
- \`alibaba-cn\` — 阿里云中国区(DashScope)
|
|
103
|
-
- \`deepseek\` — DeepSeek
|
|
104
|
-
- \`anthropic\` — Anthropic
|
|
105
|
-
- \`openai\` — OpenAI
|
|
106
|
-
- \`zhipuai\` — 智谱 AI
|
|
107
|
-
|
|
108
126
|
### 第三步:确认模型是否支持目标能力
|
|
109
127
|
|
|
110
128
|
查阅 [Models.dev](https://models.dev) 确认模型属性:
|
|
@@ -121,7 +139,31 @@ cat ~/.local/share/opencode/auth.json
|
|
|
121
139
|
- \`deepseek-flash\` 支持多模态图像输入(openfeel-vision 现用模型)
|
|
122
140
|
- 备选视觉模型:\`qwen3-vl-plus\`(模型名中的 \`vl\` 表示 Vision-Language)
|
|
123
141
|
|
|
124
|
-
###
|
|
142
|
+
### 第六步:验证
|
|
143
|
+
|
|
144
|
+
重启后调度目标 Agent 执行简单测试任务,确认无报错。
|
|
145
|
+
|
|
146
|
+
## 平台适配
|
|
147
|
+
|
|
148
|
+
### opencode 适配器
|
|
149
|
+
|
|
150
|
+
#### 第二步:读取 auth.json 确认实际 provider key
|
|
151
|
+
|
|
152
|
+
\`\`\`bash
|
|
153
|
+
# Windows PowerShell / macOS / Linux
|
|
154
|
+
cat ~/.local/share/opencode/auth.json
|
|
155
|
+
\`\`\`
|
|
156
|
+
|
|
157
|
+
**关键点**:模型引用中的 provider 部分必须与 \`auth.json\` 中的 key 完全一致,而非 \`opencode.jsonc\` 中 \`provider.name\` 或 \`provider.id\`。
|
|
158
|
+
|
|
159
|
+
常见 provider key 示例:
|
|
160
|
+
- \`alibaba-cn\` — 阿里云中国区(DashScope)
|
|
161
|
+
- \`deepseek\` — DeepSeek
|
|
162
|
+
- \`anthropic\` — Anthropic
|
|
163
|
+
- \`openai\` — OpenAI
|
|
164
|
+
- \`zhipuai\` — 智谱 AI
|
|
165
|
+
|
|
166
|
+
#### 第四步:检查 opencode.jsonc 配置
|
|
125
167
|
|
|
126
168
|
\`\`\`jsonc
|
|
127
169
|
{
|
|
@@ -139,13 +181,15 @@ cat ~/.local/share/opencode/auth.json
|
|
|
139
181
|
3. 不要随意添加前缀(如 \`alibaba/\`、\`Alibaba(China)/\`)
|
|
140
182
|
4. 如果不需要自定义 provider 选项(如 baseURL),可以完全不写 \`provider\` 块
|
|
141
183
|
|
|
142
|
-
|
|
184
|
+
#### 第五步:修改并重启
|
|
143
185
|
|
|
144
186
|
修改 \`opencode.jsonc\` 后**必须重启 opencode** 才能生效。运行中的会话使用启动时加载的配置。
|
|
145
187
|
|
|
146
|
-
###
|
|
188
|
+
### Claude Code 适配器
|
|
147
189
|
|
|
148
|
-
|
|
190
|
+
- Claude Code **无 \`auth.json\`**。
|
|
191
|
+
- 模型/provider 由 **Claude 侧**决定(\`/model\`、\`settings.json\`/\`env\`、网关如 cc-switch)。
|
|
192
|
+
- Claude Code **无 \`opencode.jsonc\`**,模型引用不进 jsonc。
|
|
149
193
|
|
|
150
194
|
## 快速诊断清单
|
|
151
195
|
|
|
@@ -156,6 +200,7 @@ cat ~/.local/share/opencode/auth.json
|
|
|
156
200
|
| 模型支持目标能力 | 查阅 models.dev | Input/Tool Call 等字段 = Yes |
|
|
157
201
|
| opencode.jsonc 语法 | 检查 JSON 格式 | 无语法错误 |
|
|
158
202
|
| 重启生效 | 重启 opencode 后重新测试 | 无 Model not found 报错 |
|
|
203
|
+
| 模型由 Claude 侧配置 | \`/model\` 或 settings/env | 模型可用 |
|
|
159
204
|
|
|
160
205
|
## 多模态(openfeel-vision)Agent 专项
|
|
161
206
|
|
|
@@ -170,6 +215,8 @@ openfeel-vision Agent 必须配置多模态模型。当前默认使用 \`deepsee
|
|
|
170
215
|
|
|
171
216
|
**推荐**:优先使用 \`deepseek-flash\`(已内置多模态);如需更大上下文可备选 \`qwen3-vl-plus\`。
|
|
172
217
|
|
|
218
|
+
> **Claude Code 适配器**:多模态由 Claude 侧模型决定;\`openfeel-vision\` subagent 须选支持图像输入的模型。
|
|
219
|
+
|
|
173
220
|
## 常见错误与修复
|
|
174
221
|
|
|
175
222
|
| 错误信息 | 原因 | 修复 |
|
|
@@ -178,6 +225,8 @@ openfeel-vision Agent 必须配置多模态模型。当前默认使用 \`deepsee
|
|
|
178
225
|
| \`Model not found: alibaba/xxx\` | 内置 key 与实际注册的 key 不一致 | 检查 auth.json,使用实际 key |
|
|
179
226
|
| \`Model not found: xxx. Did you mean: yyy\` | 模型名拼写错误或不存在 | 使用 \`Did you mean\` 建议的名称 |
|
|
180
227
|
| Agent 调度成功但无法处理图片 | 配置了纯文本模型 | 改为支持图像输入的模型(如 \`deepseek-flash\`) |
|
|
228
|
+
|
|
229
|
+
> **Claude Code 适配器**:以上排查针对 opencode 的 \`auth.json\`/\`opencode.jsonc\`;Claude 侧的模型解析以 \`/model\`、\`settings.json\`/\`env\` 或网关配置为准。
|
|
181
230
|
`,
|
|
182
231
|
'openfeel-bug-acceptance': `---
|
|
183
232
|
name: openfeel-bug-acceptance
|
|
@@ -322,7 +371,10 @@ description: 渐进式查阅 .openfeel/kb/ 项目知识库,按当前任务需
|
|
|
322
371
|
💡 如需确保索引为最新,可运行: python scripts/build_kb_index.py --dry-run
|
|
323
372
|
\`\`\`
|
|
324
373
|
|
|
325
|
-
> 注:语义检索是 \`openfeel-check-kb\`
|
|
374
|
+
> 注:语义检索是 \`openfeel-check-kb\` 的内置回退能力。调用方只需加载一次:
|
|
375
|
+
> - opencode 适配器:\`skill("openfeel-check-kb")\`;
|
|
376
|
+
> - Claude Code 适配器:以 \`Skill\` 工具加载 \`openfeel-check-kb\`(工具名映射见 \`openfeel-tool-usage\`)。
|
|
377
|
+
> 无需再手动调用 \`openfeel-search-kb\`。
|
|
326
378
|
|
|
327
379
|
### 6. 强制检索标记
|
|
328
380
|
|
|
@@ -336,7 +388,7 @@ Skill 加载后,根据步骤 3 的匹配结果决定是否追加提示:
|
|
|
336
388
|
`,
|
|
337
389
|
'openfeel-cli-usage': `---
|
|
338
390
|
name: openfeel-cli-usage
|
|
339
|
-
description: OpenFeel CLI 命令用法参考:命令清单与关键参数、15 个 phase 枚举与转移表、stageId 命名与目录映射约定、v1.1.2 新增能力(自描述/可纠错、--json 结构化输出、health --fix、scheme draft、knowledge dedup、纠正清理侧命令面)、v1.1.4 新增能力(checkpoint 选择性恢复 --stage/--dry-run、flow stage reset 精准复位、故障恢复路径)、v1.1.5 新增能力(setup --check [--json] 诊断 /
|
|
391
|
+
description: OpenFeel CLI 命令用法参考:命令清单与关键参数、15 个 phase 枚举与转移表、stageId 命名与目录映射约定、v1.1.2 新增能力(自描述/可纠错、--json 结构化输出、health --fix、scheme draft、knowledge dedup、纠正清理侧命令面)、v1.1.4 新增能力(checkpoint 选择性恢复 --stage/--dry-run、flow stage reset 精准复位、故障恢复路径)、v1.1.5 新增能力(setup --check [--json] 诊断 / 被动部署提示)、v1.1.6 新增能力(Claude Code 适配器 \`--tools claude\` / settings 注入)、v1.1.7 新增能力(双模式工作流 workflow_mode:flow mode 只读查询 / flow phases --mode 模式分节 / plan stage add --workflow-mode / stage set --workflow-mode / config set --sync-stages --stage)。当需要查询 CLI 命令、参数、phase、stageId、阶段命名时加载。
|
|
340
392
|
---
|
|
341
393
|
|
|
342
394
|
# OpenFeel CLI 用法参考
|
|
@@ -346,8 +398,9 @@ description: OpenFeel CLI 命令用法参考:命令清单与关键参数、15
|
|
|
346
398
|
- 定位:**查询型参考手册**(只读,不自执行)。回答「命令是什么、参数怎么给、phase/stageId 规则如何」。
|
|
347
399
|
- 边界:**执行型交互向导**请用 \`openfeel-wizard\` skill(跑 \`openfeel flow wizard\` 推进流水线);本 skill 只承载静态知识查阅。
|
|
348
400
|
- 与 \`openfeel-tool-usage\` 协同:工具选择规范见该 skill;本 skill 补充 CLI 命令细节。
|
|
401
|
+
- 正文以**能力名**叙述;平台差异见 \`### opencode 适配器\` / \`### Claude Code 适配器\` 两小节。
|
|
349
402
|
|
|
350
|
-
> 本文档为 v1.1.
|
|
403
|
+
> 本文档为 v1.1.7 快照;命令/参数细节以 \`openfeel <cmd> --help\`(本仓执行)实时输出为准(CLI 演进后本文档可能滞后)。
|
|
351
404
|
>
|
|
352
405
|
> ⚠️ **本仓自举**:本仓(openfeel 源码仓库)开发/执行时请用 \`node bin/openfeel.js <cmd>\`;安装后使用 \`openfeel <cmd>\`。
|
|
353
406
|
|
|
@@ -356,16 +409,16 @@ description: OpenFeel CLI 命令用法参考:命令清单与关键参数、15
|
|
|
356
409
|
| 命令 | 用途 | 关键参数 |
|
|
357
410
|
|------|------|----------|
|
|
358
411
|
| \`openfeel init [path]\` | 初始化项目工作区 | \`--lang <zh-CN\\|en>\`、\`--demo\`、\`--workspace-only\`、\`--non-interactive\` |
|
|
359
|
-
| \`openfeel setup\` | 部署全局框架配置(不建项目 \`.openfeel/\`);\`--check\` 只读诊断全局部署一致性 | \`--lang <zh-CN\\|en>\`、\`--check [--json]
|
|
360
|
-
| \`openfeel update [path]\` | 部署适配文件到目标项目 | \`--lang\`、\`--force
|
|
412
|
+
| \`openfeel setup\` | 部署全局框架配置(不建项目 \`.openfeel/\`);\`--check\` 只读诊断全局部署一致性 | \`--lang <zh-CN\\|en>\`、\`--check [--json]\`、\`--tools <list>\` |
|
|
413
|
+
| \`openfeel update [path]\` | 部署适配文件到目标项目 | \`--lang\`、\`--force\`、\`--tools <list>\` |
|
|
361
414
|
| \`openfeel migrate [path]\` | Legacy 布局迁移(检测/备份/迁移/回滚) | \`--dry-run\`、\`--remap-assignee\`、\`--clean-global-core-md\`;\`migrate rollback\` |
|
|
362
415
|
| \`openfeel flow ...\` | 流水线状态管理 | 见下「flow 子命令」 |
|
|
363
416
|
| \`openfeel flow checkpoint restore\` | Checkpoint 恢复(全量 / 选择性 / 预览) | \`<file> [--force] [--stage <id>] [--dry-run]\`(无 \`--stage\`=全量覆盖,最后手段;\`--stage\`=按阶段回退;\`--dry-run\`=零写盘预览) |
|
|
364
417
|
| \`openfeel flow stage reset\` | 精准复位阶段 phase(\`flow advance\` 的对称复位,允许回退) | \`<stageId> --to <phase> [--dry-run]\`(受合法值域 + \`to=done\` 阻塞 REV 约束) |
|
|
365
|
-
| \`openfeel plan stage add\\|list\` | 工作阶段管理 | \`add <name> --deps <ids...> --tasks <items...> --exec-mode <manual\\|auto> --auto-advance <enabled\\|disabled>\`(初值取 \`config.yaml.defaults
|
|
418
|
+
| \`openfeel plan stage add\\|list\` | 工作阶段管理 | \`add <name> --deps <ids...> --tasks <items...> --exec-mode <manual\\|auto> --auto-advance <enabled\\|disabled> --workflow-mode <full\\|fast>\`(初值取 \`config.yaml.defaults\`;显式选项优先;\`--workflow-mode\` 覆盖 config 默认) |
|
|
366
419
|
| \`openfeel plan scheme create\\|publish\\|rename\\|list\\|remove\\|register\` | 操作方案管理 | \`create <stage> <title> [--draft]\`、\`publish <stage> <opId>\`、\`rename <stage> <opId> --title <text>\`、\`remove <stage> <opId> [--force] [--dry-run]\`、\`register <stage> [opId] [--dry-run]\`(补注册 fileOrphans) |
|
|
367
|
-
| \`openfeel stage status\\|set\\|task\` | \`status.md\` 原子操作 | \`set <id> --status/--exec-mode/--auto-advance/--review-agent\`、\`task <id> [no] --add/--done/--undone\`(\`stage create\` 已弃用) |
|
|
368
|
-
| \`openfeel config ...\` | 配置管理 | \`get\\|set <key> <value> [--global]\`(支持全量 \`defaults.*\`,且 \`defaults.X ≡ X\`)、\`set ... --sync-stages
|
|
420
|
+
| \`openfeel stage status\\|set\\|task\` | \`status.md\` 原子操作 | \`set <id> --status/--exec-mode/--auto-advance/--review-agent/--workflow-mode\`、\`task <id> [no] --add/--done/--undone\`(\`stage create\` 已弃用) |
|
|
421
|
+
| \`openfeel config ...\` | 配置管理 | \`get\\|set <key> <value> [--global]\`(支持全量 \`defaults.*\`,且 \`defaults.X ≡ X\`)、\`set ... --sync-stages [--stage <ids...>]\`(批量写入已注册阶段 \`status.md\` 的 \`自动推进\`/\`执行模式\`/\`工作流模式\`;\`--stage\` 限定作用域,单独使用 / 与 \`--global\` 组合 → exit 1)、\`get-lang\\|set-lang\`、\`list-projects\`、\`effective [key]\` |
|
|
369
422
|
| \`openfeel model set\\|get\\|list\` | 模型三层级配置 | \`set <agent> <model>\` |
|
|
370
423
|
| \`openfeel lint i18n\\|kb\` | 健康检查(i18n 键一致性 / kb 过期引用) | 发现问题**非 0 退出** |
|
|
371
424
|
| \`openfeel knowledge ...\` | 知识库管理 | \`list\` / \`add\` / \`search\` / \`index\` / \`dedup\` |
|
|
@@ -375,12 +428,24 @@ description: OpenFeel CLI 命令用法参考:命令清单与关键参数、15
|
|
|
375
428
|
| \`openfeel roadmap create\\|show\` | 分期大纲管理 | \`create <version>\`、\`show [version]\` |
|
|
376
429
|
| \`openfeel instructions <artifactId>\` | 为指定 artifact 生成结构化指令 | \`--change <name>\`、\`--schema <name>\`、\`--json\` |
|
|
377
430
|
|
|
378
|
-
**flow 子命令**:\`status\` / \`current\` / \`overview\` / \`phases\` / \`stage\`(\`add\` / \`remove\` / \`set --deps\` / **\`reset <id> --to <phase> [--dry-run]\`**)/ \`metrics\` / \`advance\`(\`--stage <id> --to <phase>\`、\`--op\`、\`--force\`、\`--dry-run\`、\`--quiet\`)/ \`attempt\` / \`log\` / \`review\` / \`retry\` / \`repair\` / \`ops\` / \`migrate\` / \`checkpoint\`(\`list\` / **\`restore <file> [--force] [--stage <id>] [--dry-run]\`**)/ \`health\` / \`recover\` / \`wizard\`。
|
|
431
|
+
**flow 子命令**:\`status\` / \`current\` / \`overview\` / \`phases\` / \`mode\`(\`[--stage <id>] [--json]\`,只读) / \`stage\`(\`add\` / \`remove\` / \`set --deps\` / **\`reset <id> --to <phase> [--dry-run]\`**)/ \`metrics\` / \`advance\`(\`--stage <id> --to <phase>\`、\`--op\`、\`--force\`、\`--dry-run\`、\`--quiet\`)/ \`attempt\` / \`log\` / \`review\` / \`retry\` / \`repair\` / \`ops\` / \`migrate\` / \`checkpoint\`(\`list\` / **\`restore <file> [--force] [--stage <id>] [--dry-run]\`**)/ \`health\` / \`recover\` / \`wizard\`。
|
|
379
432
|
|
|
380
433
|
**纠错/清理侧补充**:\`flow review add|resolve|update|remove\`;\`flow ops list [--stage <id>] [--json]\`(操作方案视图,draft 分组展示);\`flow repair [--prune-orphans]\`(默认只报告,\`--prune-orphans\` 仅清键孤儿,单向不删文件);\`plan scheme register\`(补注册**文件孤儿**:有 op 文件无注册键 → 写入 flow.json,\`--dry-run\` 零写盘;与 \`flow repair --prune-orphans\`(仅清键孤儿)对称);**\`flow stage reset <id> --to <phase>\`**(\`advance\` 的**对称复位**:允许回退,受合法 phase 值域 + \`to=done\` 阻塞 REV 约束,\`--dry-run\` 零写盘);**\`flow checkpoint restore <file> --stage <id> [--dry-run]\`**(按阶段选择性回退;\`--dry-run\` 差异预览零写盘)。
|
|
381
434
|
|
|
382
435
|
> 命令职责分层:\`plan stage add\`(完整,推荐)> \`flow stage add\`(仅注册 \`flow.json\`,不建目录)> \`stage create\`(已弃用)。
|
|
383
436
|
|
|
437
|
+
## v1.1.6 新增能力(stage-68~73)
|
|
438
|
+
|
|
439
|
+
- **多 harness 并存**:\`openfeel setup\` / \`openfeel update\` 新增 \`--tools <逗号列表>\`(如 \`opencode,claude\`);非法值 **exit 1** 前置校验零写盘;默认仅 \`opencode\`。
|
|
440
|
+
- **Claude Code 适配器资产**:\`--tools claude\` 部署 \`~/.claude/\`——\`CLAUDE.md\`(全局约束,用户已有内容 append 不覆盖)、\`agents/\`(**9 个**,含 \`feel\`)、\`skills/\`(**17 个**共享源)、\`settings.json\`(注入 \`"agent":"feel"\` + \`"permissions":{"defaultMode":"auto"}\`,用户既有键逐字保留);默认零触(不带 \`--tools\` 时 \`~/.claude/\` 零变化)。
|
|
441
|
+
|
|
442
|
+
## v1.1.7 新增能力(stage-74~76)
|
|
443
|
+
|
|
444
|
+
- **双模式工作流(\`workflow_mode\`)**:值域 \`full | fast\`(默认 \`fast\`)。三层载体:\`config.yaml defaults.workflow_mode\`(项目默认 / 记忆)→ \`status.md「工作流模式」\`(阶段覆盖,**读取权威**)→ \`flow.json\` 冗余字段(可选、**不参与级联**);级联优先序 \`status.md > config.yaml > builtin\`(\`profile.yaml\` 不承载)。只读查询:\`openfeel flow mode [--stage <id>] [--json]\`(当前模式 + 四源 \`source\`)。
|
|
445
|
+
- **fast 快线转移表(并列)**:\`transitions\` 共 **9 条目**(8 条流转键 + \`done\` 终止项):\`plan_pending → plan_review\`(**计划审查必经**)、\`plan_review → plan_passed / plan_pending\`、\`plan_passed → exec_running\`、\`exec_running → review_pending\`、\`review_pending → review_failed / review_passed\`、\`review_failed → review_pending / exec_running\`(回环)、\`review_passed → archiving\`、\`archiving → done\`、\`done\`(终态)。**\`phases\` / \`advanceAccepted\` 恒 15 项、模式无关**;fast 下 6 个相位不可达(\`scheme_*\` / \`test_*\`)。
|
|
446
|
+
- **模式命令面**:\`plan stage add --workflow-mode <full|fast>\`(值域派生、非法 exit 1 不建阶段)、\`stage set <id> --workflow-mode <full|fast>\`(缺失字段插入)、\`flow phases [--mode <full|fast>] [--stage <id>]\`(模式分节;\`--json\` 追加 \`workflowMode\`)、\`config set ... --sync-stages [--stage <ids...>]\`(同步字段含「工作流模式」)。
|
|
447
|
+
- **\`config effective\` 四键**:\`auto_advance\` / \`execution_mode\` / \`merge_mode\` / \`workflow_mode\`。
|
|
448
|
+
|
|
384
449
|
## v1.1.5 新增能力(stage-67)
|
|
385
450
|
|
|
386
451
|
- **主动诊断 \`openfeel setup --check [--json]\`**:只读检测全局部署版本(\`~/.openfeel/update_state.json.openfeel_version\`)与 CLI 版本一致性,**不执行部署**;一致退出 \`0\`,\`mismatch\`/\`missing\`/\`unknown\` 退出 \`1\`;\`--json\` 输出 \`{schemaVersion,status,cliVersion,deployedVersion}\`(\`status\` ∈ \`ok|mismatch|missing|unknown\`)。
|
|
@@ -388,6 +453,8 @@ description: OpenFeel CLI 命令用法参考:命令清单与关键参数、15
|
|
|
388
453
|
|
|
389
454
|
## 升级流程
|
|
390
455
|
|
|
456
|
+
### opencode 适配器
|
|
457
|
+
|
|
391
458
|
\`\`\`bash
|
|
392
459
|
npm i -g openfeel@latest # 1. 升级 CLI
|
|
393
460
|
openfeel setup # 2. 重跑部署,刷新全局 AGENTS.md/agents/skills/opencode.jsonc
|
|
@@ -396,11 +463,22 @@ openfeel setup # 2. 重跑部署,刷新全局 AGENTS.md/agents/ski
|
|
|
396
463
|
|
|
397
464
|
仅 \`npm i -g\` 不会刷新全局资产,须重跑 \`openfeel setup\` 并重启 harness。\`openfeel setup --check\` 可诊断全局部署版本与 CLI 版本是否一致(一致退出 0,否则退出 1)。
|
|
398
465
|
|
|
466
|
+
### Claude Code 适配器
|
|
467
|
+
|
|
468
|
+
\`\`\`bash
|
|
469
|
+
npm i -g openfeel@latest # 1. 升级 CLI
|
|
470
|
+
openfeel setup --tools claude # 2. 重跑部署(claude 目标)
|
|
471
|
+
\`\`\`
|
|
472
|
+
|
|
473
|
+
- **\`--tools\` 由 v1.1.6 提供**:\`openfeel setup --tools claude\`;首次创建 \`~/.claude/{agents,skills}\` 后**重启会话或 \`/reload-skills\`** 使新 skill/agent 生效。
|
|
474
|
+
- 首次创建 \`~/.claude/{agents,skills}\` 后需**重启会话或 \`/reload-skills\`** 使新 skill/agent 生效。
|
|
475
|
+
- \`CLAUDE.md\` 于**下次会话**生效。
|
|
476
|
+
|
|
399
477
|
## v1.1.2 新增能力(stage-41~55)
|
|
400
478
|
|
|
401
479
|
> 以下为 v1.1.2 相对上版的增量能力(分组摘要,细节以 \`<cmd> --help\` 为准)。
|
|
402
480
|
|
|
403
|
-
- **A. 自描述与可纠错(stage-41)**:\`flow phases [--json]\`(**
|
|
481
|
+
- **A. 自描述与可纠错(stage-41)**:\`flow phases [--json] [--mode <full|fast>] [--stage <id>]\`(**6 键**:\`schemaVersion\`/\`phases\`/\`transitions\`/\`advanceAccepted\`/\`transitionsDiff\`/\`workflowMode\`(v1.1.7 追加);既有五键语义逐字不变)、\`flow stage remove [--force] [--dry-run] [--purge]\`、stageId 校验/冲突检测(\`validateStageId\` / \`suggestStageId\` / \`findStageDirConflict\`)、\`plan stage add --deps\`。
|
|
404
482
|
- **B. 状态与口径(stage-42)**:\`config effective [key]\`(有效值 + 生效来源 \`status.md > config.yaml > profile.yaml > builtin\`)、\`pipeline.phase\` 全量 done 判定、审计日志 \`register_stage\` / \`register_op\`。
|
|
405
483
|
- **C. 部署与备份(stage-46)**:覆盖写前自动备份 \`~/.openfeel/backup/{ts}/\` + \`update_infos.md\`「备份」类条目(Agent 按 \`feel.md\` 检查规则核对)。
|
|
406
484
|
- **D. 纠正/清理侧命令面(stage-51/52,v1.1.4-stage-64 补 register)**:\`plan scheme remove\`(仅删 \`flow.json\` 注册键,不删 op 文件;done/checkpoint 保护)、\`plan scheme register <stage> [opId] [--dry-run]\`(对称补全:补注册 fileOrphans,\`--dry-run\` 零写盘;**\`create\` 序号基于「ops/ 文件 ∪ flow.json 注册」的最小未用正整数(空位回填),创建后对目标阶段未注册文件输出 stderr 告警并提示 \`plan scheme register\`**)、\`plan scheme rename --title\`(必填,空标题报错)、\`plan scheme publish\` + \`create --draft\`(draft→pending,空模板拒绝)、\`flow stage set --deps\`(覆盖写入;**不带 \`--deps\` 视为清空**)、\`flow review update|remove\`、\`stage set\`(**幂等**:同值 no-op + 同值不生成 \`.bak\`;\`--exec-mode <manual\\|auto>\` / \`--auto-advance <enabled\\|disabled>\` / \`--review-agent <agent>\`)、\`stage task --add|--done|--undone\`、\`plan stage add --tasks\`/\`--exec-mode\`/\`--auto-advance\`(显式覆盖 config 默认)、\`flow repair --prune-orphans\`、\`flow health --fix [--dry-run]\`(默认只报告;\`--fix\` **仅回写 status.md「状态」字段**;\`--dry-run\` 预览零写盘)、\`flow ops list\`、\`flow advance --quiet\` + \`--to <远距 phase>\`(存在唯一路径时自动逐步;\`--dry-run\` 展示完整路径)、\`knowledge dedup\`(检索相似条目,**只读建议,不修改 kb**)。\`flow attempt\` 对 **draft op 拒绝**。
|
|
@@ -434,7 +512,23 @@ plan_pending → plan_review → plan_passed → scheme_pending → scheme_revie
|
|
|
434
512
|
| \`archiving\` | \`done\` |
|
|
435
513
|
| \`done\` | (终态) |
|
|
436
514
|
|
|
437
|
-
|
|
515
|
+
**fast 快线转移表(\`workflow_mode=fast\`)** —— \`transitions\` 共 **9 条目**(8 条流转键 + \`done\` 终止项),快线链(可达相位序列)为 \`plan_pending → plan_review → plan_passed → exec_running → review_pending → review_failed → review_passed → archiving → done\`:
|
|
516
|
+
|
|
517
|
+
| phase | 合法目标 |
|
|
518
|
+
|-------|----------|
|
|
519
|
+
| \`plan_pending\` | \`plan_review\` |
|
|
520
|
+
| \`plan_review\` | \`plan_passed\`, \`plan_pending\` |
|
|
521
|
+
| \`plan_passed\` | \`exec_running\` |
|
|
522
|
+
| \`exec_running\` | \`review_pending\` |
|
|
523
|
+
| \`review_pending\` | \`review_failed\`, \`review_passed\` |
|
|
524
|
+
| \`review_failed\` | \`review_pending\`, \`exec_running\` |
|
|
525
|
+
| \`review_passed\` | \`archiving\` |
|
|
526
|
+
| \`archiving\` | \`done\` |
|
|
527
|
+
| \`done\` | (终态) |
|
|
528
|
+
|
|
529
|
+
> \`phases\` / \`advanceAccepted\` 恒 15 项(模式无关);fast 下 \`scheme_pending\` / \`scheme_review\` / \`scheme_passed\` / \`test_pending\` / \`test_failed\` / \`test_passed\` 共 **6 项**不可达(无入边)。
|
|
530
|
+
|
|
531
|
+
- 转移表以**运行时** \`.openfeel/pipeline.yaml\` 为准;\`openfeel flow phases\` 查看当前生效值。(\`--mode <full|fast>\` 显式指定 / \`--stage <id>\` 按阶段派生;\`--json\` 追加 \`workflowMode\`)
|
|
438
532
|
- 推进:\`openfeel flow advance --stage <id> --to <phase>\`。**\`advanceAccepted\` = 内置 15 个 phase 的「推进白名单」**(\`flow advance\` 只接受这 15 个值),**不是**组合式条件键的替代品(旧文案曾误述,此处已更正)。**组合式条件差异**(如内置默认含 \`review_passed|test_passed\`,本仓 \`pipeline.yaml\` 未列)经 \`--json.transitionsDiff.missing\` **显式可见**(stage-50 裁定:**不补组合键**,改以 \`transitionsDiff\` 显式化)。
|
|
439
533
|
- 参考:\`.openfeel/manual/**\`(CLI/flow 模块文档)。
|
|
440
534
|
|
|
@@ -469,11 +563,19 @@ plan_pending → plan_review → plan_passed → scheme_pending → scheme_revie
|
|
|
469
563
|
|
|
470
564
|
## 权限模型要点
|
|
471
565
|
|
|
566
|
+
### opencode 适配器
|
|
567
|
+
|
|
472
568
|
- 9 个 agent 内联 \`permission:\` 白名单,均含 \`external_directory: "allow"\`(单一键,无读写粒度)。
|
|
473
569
|
- **合并语义**:agent \`.md\` frontmatter 与 \`opencode.jsonc\` 按权限键**深合并**,同名键以 agent \`.md\` 为准(配置文件无法覆盖已声明键)。
|
|
474
570
|
- **收紧入口**:项目根 \`.opencode/agent/<name>.md\` 覆盖全局同名 agent 并重写完整 \`permission\` 块;勿手改全局 agent frontmatter(会被 \`update\` 覆盖)。
|
|
475
571
|
- 详 \`.openfeel/manual/core/permission.md\`。
|
|
476
572
|
|
|
573
|
+
### Claude Code 适配器
|
|
574
|
+
|
|
575
|
+
- subagent 于 frontmatter 声明 \`tools\`(白名单,未列即不可用)、\`disallowedTools\`(黑名单)与 \`permissionMode\`。
|
|
576
|
+
- **无 \`external_directory\` 对等概念**。
|
|
577
|
+
- \`settings.json\` 由 \`openfeel setup/update --tools claude\` 注入(\`agent:"feel"\` + \`permissions.defaultMode:"auto"\`,用户键保留),**v1.1.6 起**。
|
|
578
|
+
|
|
477
579
|
## 与 openfeel-wizard 的区别
|
|
478
580
|
|
|
479
581
|
| 维度 | \`openfeel-cli-usage\`(本 skill) | \`openfeel-wizard\` |
|
|
@@ -538,7 +640,7 @@ description: 读取 .openfeel/plan/{series}/{stage}/status.md,判断当前子
|
|
|
538
640
|
|
|
539
641
|
### 0. 读取全局配置
|
|
540
642
|
|
|
541
|
-
读取 \`.openfeel/config.yaml\`,解析 \`defaults\` 中的 \`execution_mode\`、\`auto_advance\`、\`merge_mode\`。
|
|
643
|
+
读取 \`.openfeel/config.yaml\`,解析 \`defaults\` 中的 \`execution_mode\`、\`auto_advance\`、\`merge_mode\`、\`workflow_mode\`。
|
|
542
644
|
|
|
543
645
|
### 1. 定位状态文件
|
|
544
646
|
|
|
@@ -554,6 +656,7 @@ description: 读取 .openfeel/plan/{series}/{stage}/status.md,判断当前子
|
|
|
554
656
|
|
|
555
657
|
- \`执行模式\`
|
|
556
658
|
- \`自动推进\`
|
|
659
|
+
- \`工作流模式\`
|
|
557
660
|
- \`状态\`
|
|
558
661
|
- \`当前责任 Agent\`
|
|
559
662
|
- \`上一责任 Agent\`
|
|
@@ -588,7 +691,9 @@ description: 读取 .openfeel/plan/{series}/{stage}/status.md,判断当前子
|
|
|
588
691
|
- \`deps_satisfied = true\`(本 Skill 递归判断)
|
|
589
692
|
- \`状态\` 为 \`ready_for_code\` 或 \`auto_running\`
|
|
590
693
|
- \`自动推进\` 为 \`enabled\`(若 status.md 未填则回退到 config.yaml \`auto_advance\`)
|
|
591
|
-
2. 收集为 \`parallel_candidates\`
|
|
694
|
+
2. 收集为 \`parallel_candidates\` 列表,供主会话(Feel)批量调度执行。
|
|
695
|
+
|
|
696
|
+
> 口径:**subagent 不互调**(不直接调用其他 subagent);需向用户确认的事项一律由主会话负责。
|
|
592
697
|
|
|
593
698
|
### 5. 判断自动推进资格
|
|
594
699
|
|
|
@@ -612,6 +717,7 @@ description: 读取 .openfeel/plan/{series}/{stage}/status.md,判断当前子
|
|
|
612
717
|
- 阶段:{stage}
|
|
613
718
|
- 执行模式:manual | auto
|
|
614
719
|
- 自动推进:disabled | enabled
|
|
720
|
+
- 工作流模式:full | fast
|
|
615
721
|
- 状态:{status}
|
|
616
722
|
- 当前责任 Agent:{agent}
|
|
617
723
|
- 前置依赖:{依赖列表 或 无}
|
|
@@ -626,6 +732,8 @@ description: 读取 .openfeel/plan/{series}/{stage}/status.md,判断当前子
|
|
|
626
732
|
{根据状态给出下一步,例如:启动 Code、等待用户、启动 openfeel-feel-tester、停止流程;若存在并行候选则建议批量启动}
|
|
627
733
|
\`\`\`
|
|
628
734
|
|
|
735
|
+
> **模式感知(fast)**:\`工作流模式\` 为 \`fast\` 时,「下一步建议」不指向方案 / 测试环节(快线链为 计划 → 计划审查 → 执行 → 代码审查 → 归档);\`plan_pending\` 阶段下一步建议 = \`plan_review\`(必经,勿建议直接 \`plan_passed\`);相位口径为「**可达 ≠ 合法**」——合法枚举仍 15 项(fast 下仅 6 项不可达),**不得**表述为相位缩减。
|
|
736
|
+
|
|
629
737
|
## 状态到下一步映射
|
|
630
738
|
|
|
631
739
|
| 状态 | 下一步建议 |
|
|
@@ -635,8 +743,8 @@ description: 读取 .openfeel/plan/{series}/{stage}/status.md,判断当前子
|
|
|
635
743
|
| \`coding\` | openfeel-executor 正在开发 |
|
|
636
744
|
| \`ready_for_review\` | openfeel-executor 可启动 openfeel-reviewer 审查,或等待用户触发 |
|
|
637
745
|
| \`review_failed\` | openfeel-reviewer 可启动 openfeel-executor 修复审查问题 |
|
|
638
|
-
| \`review_passed\` |
|
|
639
|
-
| \`ready_for_test\` |
|
|
746
|
+
| \`review_passed\` | 主会话可推进到 ready_for_test |
|
|
747
|
+
| \`ready_for_test\` | 主会话可启动 openfeel-feel-tester |
|
|
640
748
|
| \`test_writing\` | openfeel-feel-tester 正在写测试 |
|
|
641
749
|
| \`testing\` | openfeel-feel-tester 正在测试 |
|
|
642
750
|
| \`bug_found\` | openfeel-feel-tester 可启动 openfeel-executor 修复 Bug |
|
|
@@ -669,16 +777,18 @@ description: 加载流水线健康检查结果,供 Agent 判断 flow.json 与
|
|
|
669
777
|
`,
|
|
670
778
|
'openfeel-model-check': `---
|
|
671
779
|
name: openfeel-model-check
|
|
672
|
-
description: Feel
|
|
780
|
+
description: 主会话(Feel)自检时检查所有 Agent 的模型配置状态,识别期望模型 vs 实际模型的差距,引导用户在目标工具中完成配置。首次配置后存储为部署模板,新项目可直接复用。
|
|
673
781
|
---
|
|
674
782
|
|
|
675
783
|
# 模型配置检查
|
|
676
784
|
|
|
677
785
|
> ⚠️ **本仓自举**:本仓(openfeel 源码仓库)开发/执行时请用 \`node bin/openfeel.js <cmd>\`;安装后使用 \`openfeel <cmd>\`。
|
|
678
786
|
|
|
787
|
+
> 正文以**能力名**叙述;平台差异见 \`### opencode 适配器\` / \`### Claude Code 适配器\` 两小节。
|
|
788
|
+
|
|
679
789
|
## 触发时机
|
|
680
790
|
|
|
681
|
-
|
|
791
|
+
主会话在以下时机加载本 Skill:
|
|
682
792
|
- 会话启动自检(每次)
|
|
683
793
|
- 用户请求检查模型配置(按需)
|
|
684
794
|
- 新项目首次初始化后(\`openfeel init\`)
|
|
@@ -687,19 +797,11 @@ Feel Agent 在以下时机加载本 Skill:
|
|
|
687
797
|
|
|
688
798
|
### 1. 识别当前平台
|
|
689
799
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
| 配置文件 | 平台 |
|
|
693
|
-
|----------|------|
|
|
694
|
-
| \`opencode.jsonc\` | OpenCode(当前适配器) |
|
|
695
|
-
| \`kilo/kilo.json\` | Kilo |
|
|
696
|
-
| \`claude/claude.json\` | Claude |
|
|
697
|
-
|
|
698
|
-
若无平台配置文件,提示用户当前不在支持的平台中。
|
|
800
|
+
读取当前 harness 的平台配置文件,确定当前适配器平台(已知平台配置文件与 agents 目录差异见 \`## 平台适配\`)。
|
|
699
801
|
|
|
700
802
|
### 2. 扫描 Agent 定义
|
|
701
803
|
|
|
702
|
-
扫描
|
|
804
|
+
扫描 agents 目录(目录差异见 \`## 平台适配\`)下所有 \`.md\` 文件,提取每个 Agent 的模型需求。
|
|
703
805
|
|
|
704
806
|
**提取规则(优先级从高到低)**:
|
|
705
807
|
|
|
@@ -776,7 +878,7 @@ models:
|
|
|
776
878
|
\`\`\`markdown
|
|
777
879
|
| Agent | 角色要求 | 实际模型 | 配置来源 | 状态 |
|
|
778
880
|
|-------|----------|----------|----------|:--:|
|
|
779
|
-
|
|
|
881
|
+
| 主会话 | 主力推理 | deepseek-v4-pro | default | ⚠️ |
|
|
780
882
|
| openfeel-reviewer | **异种推理** | deepseek-v4-pro | default | ❌ 与主力相同! |
|
|
781
883
|
| openfeel-executor | 快速 | deepseek-v4-pro | default | ⚠️ 未使用快速模型 |
|
|
782
884
|
\`\`\`
|
|
@@ -788,7 +890,7 @@ models:
|
|
|
788
890
|
\`\`\`markdown
|
|
789
891
|
## 🔍 模型配置检查报告
|
|
790
892
|
|
|
791
|
-
|
|
893
|
+
**平台**:当前 harness(opencode 适配器 / Claude Code 适配器)
|
|
792
894
|
**配置文件**:.openfeel/config.yaml
|
|
793
895
|
**检查时间**:yyyy-mm-dd HH:MM
|
|
794
896
|
|
|
@@ -816,12 +918,12 @@ models:
|
|
|
816
918
|
|
|
817
919
|
### 6. 引导用户配置
|
|
818
920
|
|
|
819
|
-
|
|
921
|
+
若检查发现以下任一问题,**必须**使用向用户提问工具(opencode 适配器:\`question\`;Claude Code 适配器:\`AskUserQuestion\`)引导用户:
|
|
820
922
|
|
|
821
923
|
| 触发条件 | 引导内容 |
|
|
822
924
|
|----------|----------|
|
|
823
925
|
| \`models\` 节不存在 | "未检测到模型配置。你需要为不同角色分配模型吗?" → 引导创建 |
|
|
824
|
-
| openfeel-reviewer 使用与主力相同模型 | "⚠️ openfeel-reviewer
|
|
926
|
+
| openfeel-reviewer 使用与主力相同模型 | "⚠️ openfeel-reviewer 当前与主会话使用相同模型,异种交叉审查的核心优势无法发挥。建议为 openfeel-reviewer 配置不同的模型系列。" |
|
|
825
927
|
| openfeel-executor 使用推理模型 | "⚠️ openfeel-executor 建议使用快速模型以节省成本。是否配置?" |
|
|
826
928
|
| 关键 Agent 无任何配置 | "以下 Agent 无模型配置:{列表}。请配置。" |
|
|
827
929
|
|
|
@@ -841,7 +943,7 @@ models:
|
|
|
841
943
|
# 或直接复制此文件到 .openfeel/ 并重命名为 config.yaml(需合并其他节)
|
|
842
944
|
#
|
|
843
945
|
# 最近配置时间:yyyy-mm-dd HH:MM
|
|
844
|
-
#
|
|
946
|
+
# 平台:当前 harness(opencode 适配器 / Claude Code 适配器)
|
|
845
947
|
|
|
846
948
|
models:
|
|
847
949
|
default:
|
|
@@ -860,6 +962,32 @@ models:
|
|
|
860
962
|
|
|
861
963
|
此模板在下次 \`openfeel init\` 或新项目部署时自动检测并建议复用。
|
|
862
964
|
|
|
965
|
+
## 平台适配
|
|
966
|
+
|
|
967
|
+
### opencode 适配器
|
|
968
|
+
|
|
969
|
+
读取 \`opencode.jsonc\`(或对应平台的配置文件),确定当前适配器平台:
|
|
970
|
+
|
|
971
|
+
| 配置文件 | 平台 |
|
|
972
|
+
|----------|------|
|
|
973
|
+
| \`opencode.jsonc\` | OpenCode(当前适配器) |
|
|
974
|
+
| \`kilo/kilo.json\` | Kilo |
|
|
975
|
+
|
|
976
|
+
若无平台配置文件,提示用户当前不在支持的平台中。
|
|
977
|
+
|
|
978
|
+
扫描 \`.opencode/agents/\`(或对应平台的 agents/ 目录)下所有 \`.md\` 文件,提取每个 Agent 的模型需求。
|
|
979
|
+
|
|
980
|
+
- 报告/模板中的平台标签:\`**平台**:OpenCode(当前适配器)\`(原文标签,正文已改为中性表述「当前 harness(opencode 适配器 / Claude Code 适配器)」)。
|
|
981
|
+
- 向用户提问使用 \`question\` 工具。
|
|
982
|
+
|
|
983
|
+
### Claude Code 适配器
|
|
984
|
+
|
|
985
|
+
- Claude Code **无平台配置文件**(原平台识别表中指向 Claude 的错误配置行已删除)。
|
|
986
|
+
- 全局约束:\`~/.claude/CLAUDE.md\`;本期由 **stage-73** 注入 \`settings.json\`。
|
|
987
|
+
- agents 目录:\`~/.claude/agents/\`。
|
|
988
|
+
- 报告平台标签:\`Claude Code 适配器\`。
|
|
989
|
+
- 向用户提问使用 \`AskUserQuestion\` 工具。
|
|
990
|
+
|
|
863
991
|
## 输出规范
|
|
864
992
|
|
|
865
993
|
- 状态图标:✅ 已满足、⚠️ 降级使用(可接受但非最优)、❌ 缺失或严重不匹配
|
|
@@ -868,13 +996,15 @@ models:
|
|
|
868
996
|
`,
|
|
869
997
|
'openfeel-model-config': `---
|
|
870
998
|
name: openfeel-model-config
|
|
871
|
-
description: 查找和配置 Agent 模型。当 Agent 报 "Model not found" 或需要调整/新增 Agent
|
|
999
|
+
description: 查找和配置 Agent 模型。当 Agent 报 "Model not found" 或需要调整/新增 Agent 模型时使用。覆盖模型配置位置与优先级链(opencode 适配器 / Claude Code 适配器)、模型名查找方法、多模态模型(openfeel-vision)特殊注意事项。
|
|
872
1000
|
---
|
|
873
1001
|
|
|
874
1002
|
# Skill: openfeel-model-config
|
|
875
1003
|
|
|
876
1004
|
# Agent 模型查找与配置
|
|
877
1005
|
|
|
1006
|
+
> 正文以**能力名**叙述;平台差异见 \`### opencode 适配器\` / \`### Claude Code 适配器\` 两小节。
|
|
1007
|
+
|
|
878
1008
|
## 何时使用
|
|
879
1009
|
|
|
880
1010
|
- Agent 调用时报 \`Model not found: xxx\`
|
|
@@ -884,6 +1014,8 @@ description: 查找和配置 Agent 模型。当 Agent 报 "Model not found" 或
|
|
|
884
1014
|
|
|
885
1015
|
## 配置位置
|
|
886
1016
|
|
|
1017
|
+
### opencode 适配器
|
|
1018
|
+
|
|
887
1019
|
Agent 模型配置在 **\`opencode.jsonc\`**(项目根目录)中:
|
|
888
1020
|
|
|
889
1021
|
\`\`\`jsonc
|
|
@@ -900,6 +1032,12 @@ Agent 模型配置在 **\`opencode.jsonc\`**(项目根目录)中:
|
|
|
900
1032
|
|
|
901
1033
|
> 💡 **推荐**:可用 \`openfeel model set/get/list --scope default|global|project\` 一键读写三层级模型(工具默认 / 全局 / 当前项目),无需手工定位文件。
|
|
902
1034
|
|
|
1035
|
+
### Claude Code 适配器
|
|
1036
|
+
|
|
1037
|
+
- Agent 模型配置在 Claude Code 侧的 \`~/.claude/agents/*.md\` frontmatter \`model\` 字段。
|
|
1038
|
+
- 模型配置经 \`/model\`、\`settings.json\`/\`env\` 或网关(如 cc-switch)等途径确定。
|
|
1039
|
+
- \`settings.json\`(本期由 stage-73 注入)仅作参考,模板默认 \`model: inherit\`。
|
|
1040
|
+
|
|
903
1041
|
## 查找可用模型名
|
|
904
1042
|
|
|
905
1043
|
当收到 \`"Model not found: xxx. Did you mean: aaa, bbb?"\` 错误时:
|
|
@@ -909,6 +1047,8 @@ Agent 模型配置在 **\`opencode.jsonc\`**(项目根目录)中:
|
|
|
909
1047
|
|
|
910
1048
|
## Agent 定义文件中的 model 字段
|
|
911
1049
|
|
|
1050
|
+
### opencode 适配器
|
|
1051
|
+
|
|
912
1052
|
\`.opencode/agents/<name>.md\` 的 frontmatter \`model:\` 字段**是生效的,且优先于** \`opencode.jsonc\` 的 \`agent.<name>.model\`(stage-40 REV-1606 实测)。opencode 模型解析优先级链:
|
|
913
1053
|
|
|
914
1054
|
\`\`\`
|
|
@@ -919,21 +1059,31 @@ Agent 模型配置在 **\`opencode.jsonc\`**(项目根目录)中:
|
|
|
919
1059
|
1. 修改 \`.opencode/agents/<name>.md\` 的 frontmatter \`model:\`(模板源 \`src/core/templates-data/opencode/agents/\` 同步)
|
|
920
1060
|
2. (可选,保持一致)同步修改 \`opencode.jsonc\` 的 \`agent.<name>.model\`
|
|
921
1061
|
|
|
1062
|
+
### Claude Code 适配器
|
|
1063
|
+
|
|
1064
|
+
Claude Code 模型解析优先级链:项目 \`.claude/agents\` > 用户 \`~/.claude/agents\`;frontmatter \`model\` **优先于** \`inherit\`。
|
|
1065
|
+
|
|
922
1066
|
## 多模态(openfeel-vision)模型特殊规则
|
|
923
1067
|
|
|
924
|
-
|
|
925
|
-
|
|
1068
|
+
### opencode 适配器
|
|
1069
|
+
|
|
1070
|
+
- 主会话(Feel)的主力模型(DeepSeek V4 Pro)不支持图片输入
|
|
1071
|
+
- 遇到图片输入时主会话会自动委托 openfeel-vision Agent
|
|
926
1072
|
- openfeel-vision Agent 需要配置多模态模型(现用 \`deepseek-flash\`,备选 \`qwen3-vl-plus\`)
|
|
927
1073
|
- 模型名不要随意添加前缀(如 \`alibaba/\`),以平台提示的可用名为准
|
|
928
1074
|
- **模型引用格式**:\`{auth.json中的key}/{模型ID}\`,不是 \`provider.name\` 也不是 \`provider.id\`
|
|
929
1075
|
- 读取 \`~/.local/share/opencode/auth.json\` 确认实际 provider key(常见:\`alibaba-cn\`、\`deepseek\`、\`zhipuai\`)
|
|
930
1076
|
- \`provider\` 块中的 \`name\` 和 \`id\` 仅用于显示,不影响模型解析
|
|
931
1077
|
|
|
1078
|
+
### Claude Code 适配器
|
|
1079
|
+
|
|
1080
|
+
- 多模态由 Claude 侧模型决定;\`openfeel-vision\` subagent 须选支持图像输入的模型。
|
|
1081
|
+
|
|
932
1082
|
## 项目 Agent 模型概览
|
|
933
1083
|
|
|
934
1084
|
| Agent | 模型类型 | 备注 |
|
|
935
1085
|
|-------|---------|------|
|
|
936
|
-
| Feel
|
|
1086
|
+
| 主会话(Feel) | 推理模型 | DeepSeek V4 Pro — 不支持多模态 |
|
|
937
1087
|
| openfeel-planner | 推理模型 | — |
|
|
938
1088
|
| openfeel-schemer | 推理模型 | — |
|
|
939
1089
|
| openfeel-executor | 快速模型 (Flash) | — |
|
|
@@ -962,6 +1112,8 @@ description: 跨会话上下文恢复,供 Agent 在会话启动时重建流水
|
|
|
962
1112
|
2. 读取**索引** \`.openfeel/users/{username}/dev_last.md\`(「用户偏好」「主题索引」「公共交接区」)→ **按需**再读主题文件(**文件名英文,如 \`decisions.md\`/\`pending.md\`**)恢复详情;**旧格式**(无 \`## 主题索引\` 节)→ 触发惰性迁移(按英文命名映射拆分生成 \`dev_last/\` + 索引,原文保留)
|
|
963
1113
|
3. 将两者合并为当前会话起点
|
|
964
1114
|
|
|
1115
|
+
> **模式感知**:恢复后按当前阶段 \`status.md「工作流模式」\` 确认流程模式(\`flow recover\` 输出不含模式字段;fast 工作流快线下按快线链继续)。
|
|
1116
|
+
|
|
965
1117
|
> **加锁提示(A9)**:恢复流程为**只读**,无需加锁;仅**会话末尾写入**走 \`withFileLock\` 临界区(见 agents-md「并发写加锁协议」)。
|
|
966
1118
|
|
|
967
1119
|
## 输出
|
|
@@ -1196,7 +1348,7 @@ description: Agent 工具使用规范(todowrite/question/task/skill 四工具
|
|
|
1196
1348
|
触发条件(任一必问):需求歧义 / 多个同等合理方案 / 不可逆后果 / 架构决策。使用要求:(Recommended) 标记、选项附后果、≤3 选项、高风险含"取消"。禁止:模糊时自行假设、多方案不选直接实施。
|
|
1197
1349
|
|
|
1198
1350
|
### 3. task — 子 Agent 调度
|
|
1199
|
-
触发条件:并行探索多代码区 / 复杂多步委托 general / 下游 Agent
|
|
1351
|
+
触发条件:并行探索多代码区 / 复杂多步委托 general / 下游 Agent(经主会话(Feel))。使用要求:并行一条消息多 task、prompt 含任务描述+期望返回、明确只读/可写。
|
|
1200
1352
|
|
|
1201
1353
|
### 4. skill — 技能加载
|
|
1202
1354
|
触发条件:查阶段状态→openfeel-get-stage-status / 查知识库→openfeel-check-kb / 取 Bug→openfeel-get-bugs。使用要求:会话开始载 check-kb、处理阶段任务前载 get-stage-status、不凭记忆跳过。
|
|
@@ -1209,6 +1361,23 @@ description: Agent 工具使用规范(todowrite/question/task/skill 四工具
|
|
|
1209
1361
|
| 探索代码 | task(explore) | 手动逐个 grep/read |
|
|
1210
1362
|
| 获取状态 | skill(openfeel-get-stage-status) | 凭记忆推断 |
|
|
1211
1363
|
| 批量文件操作 | task(general) | 串行逐个处理 |
|
|
1364
|
+
|
|
1365
|
+
## 工具名映射(跨 harness)
|
|
1366
|
+
|
|
1367
|
+
本 skill 的四种核心工具(\`todowrite\`/\`question\`/\`task\`/\`skill\`)在各 harness 的等价工具名见下表;**不改变**既有触发条件/使用要求/优先级表语义。
|
|
1368
|
+
|
|
1369
|
+
| opencode(小写) | Claude Code | 说明 |
|
|
1370
|
+
|------|------|------|
|
|
1371
|
+
| \`bash\` | \`Bash\` | 命令执行 |
|
|
1372
|
+
| \`read\` | \`Read\` | 读文件 |
|
|
1373
|
+
| \`write\` | \`Write\` | 写文件 |
|
|
1374
|
+
| \`edit\` | \`Edit\` | 编辑文件 |
|
|
1375
|
+
| \`glob\` | \`Glob\` | 文件匹配 |
|
|
1376
|
+
| \`grep\` | \`Grep\` | 内容检索 |
|
|
1377
|
+
| \`todowrite\` | \`TodoWrite\` | 任务列表 |
|
|
1378
|
+
| \`skill\` | \`Skill\` | 技能加载 |
|
|
1379
|
+
| \`task\` | \`Task\` | 子 Agent 调度 |
|
|
1380
|
+
| \`question\` | \`AskUserQuestion\` | 向用户提问 |
|
|
1212
1381
|
`,
|
|
1213
1382
|
'openfeel-update-stage-status': `---
|
|
1214
1383
|
name: openfeel-update-stage-status
|
|
@@ -1241,7 +1410,7 @@ description: 标准化更新 .openfeel/plan/{series}/{stage}/status.md 的子计
|
|
|
1241
1410
|
|
|
1242
1411
|
### 0. 读取全局配置
|
|
1243
1412
|
|
|
1244
|
-
读取 \`.openfeel/config.yaml\`,获取 \`defaults\` 中的 \`execution_mode\`、\`auto_advance\`、\`merge_mode\`。
|
|
1413
|
+
读取 \`.openfeel/config.yaml\`,获取 \`defaults\` 中的 \`execution_mode\`、\`auto_advance\`、\`merge_mode\`、\`workflow_mode\`。
|
|
1245
1414
|
|
|
1246
1415
|
### 1. 读取状态文件
|
|
1247
1416
|
|
|
@@ -1286,6 +1455,7 @@ planned | ready_for_code | coding | ready_for_review | review_failed | review_pa
|
|
|
1286
1455
|
|
|
1287
1456
|
- \`执行模式\`
|
|
1288
1457
|
- \`自动推进\`
|
|
1458
|
+
- \`工作流模式\`(模式字段**不由**状态更新覆盖)
|
|
1289
1459
|
- \`前置依赖\`(由 Architect 在 Phase 3.5 中声明,运行时不应修改)
|
|
1290
1460
|
|
|
1291
1461
|
### 4. 追加状态记录
|
|
@@ -1347,6 +1517,8 @@ description: 交互式流水线向导,供 Agent 在终端中逐步推进流水
|
|
|
1347
1517
|
2. 按提示选择要推进的阶段和下一步 phase(基于当前阶段的可达 transitions)
|
|
1348
1518
|
3. 确认后执行推进,循环直至阶段 done 或退出
|
|
1349
1519
|
|
|
1520
|
+
> **模式选型**:首次运行时向导会询问工作流模式(\`full\` / \`fast\`),写入 \`config.yaml defaults.workflow_mode\`(项目级记忆);非 TTY 环境沿用既有守卫、不询问。
|
|
1521
|
+
|
|
1350
1522
|
## 输出
|
|
1351
1523
|
|
|
1352
1524
|
向导推进结果:阶段 phase 变化(from → to),结束/退出提示
|
|
@@ -1386,9 +1558,9 @@ description: 会话启动时检查并补齐 .openfeel/ 工作区目录结构与
|
|
|
1386
1558
|
\`.openfeel/users/{username}/dev_last.md\`(**索引**;同名目录 \`dev_last/\` 存主题文件,**文件名英文**)
|
|
1387
1559
|
|
|
1388
1560
|
### 6. 增量更新复核
|
|
1389
|
-
检查 \`~/.openfeel/update_infos.md
|
|
1561
|
+
检查 \`~/.openfeel/update_infos.md\`,若存在未修复条目(追加/异常),提醒用户重启会话或委托主会话(Feel)处理;本 Agent 不自行修改该文件。
|
|
1390
1562
|
|
|
1391
|
-
>
|
|
1563
|
+
> 目录结构语义、公共/私域分区、用户身份约束、路径自校验规则见全局规则文件(opencode 适配器:\`~/.config/opencode/AGENTS.md\`;Claude Code 适配器:\`~/.claude/CLAUDE.md\`)(约束);本 skill 仅承载操作步骤。
|
|
1392
1564
|
`,
|
|
1393
1565
|
};
|
|
1394
1566
|
// AUTO-GENERATED-END: SKILL_DEFINITIONS
|
|
@@ -1537,8 +1709,10 @@ export function updateProject(projectPath, selectedTools = ["opencode"], lang =
|
|
|
1537
1709
|
const state = loadUpdateState(projectPath);
|
|
1538
1710
|
const globalState = loadGlobalUpdateState();
|
|
1539
1711
|
const conflicts = [];
|
|
1540
|
-
//
|
|
1541
|
-
|
|
1712
|
+
// 过滤:仅处理选中的工具(两工具都未选才早退)
|
|
1713
|
+
const wantOpencode = selectedTools.includes('opencode');
|
|
1714
|
+
const wantClaude = selectedTools.includes('claude');
|
|
1715
|
+
if (!wantOpencode && !wantClaude) {
|
|
1542
1716
|
return { created: [], updated: [], skipped: [], conflicts: [], appended: [] };
|
|
1543
1717
|
}
|
|
1544
1718
|
// N8:检测项目内遗留 .opencode/{agents,skills,instructions},只提示不迁移
|
|
@@ -1547,12 +1721,6 @@ export function updateProject(projectPath, selectedTools = ["opencode"], lang =
|
|
|
1547
1721
|
if (legacyDirs.length > 0) {
|
|
1548
1722
|
console.warn(t('update.legacyLayoutWarnTmpl', getCliLang(projectPath), { dirs: legacyDirs.join(',') }));
|
|
1549
1723
|
}
|
|
1550
|
-
// 全局部署目标(D1)
|
|
1551
|
-
const agentsDir = getGlobalAgentsDir();
|
|
1552
|
-
const skillsDir = getGlobalSkillsDir();
|
|
1553
|
-
// 确保全局目标目录存在
|
|
1554
|
-
mkdirSync(agentsDir, { recursive: true });
|
|
1555
|
-
mkdirSync(skillsDir, { recursive: true });
|
|
1556
1724
|
// 记录项目语言映射到全局配置
|
|
1557
1725
|
// 使用 options?.lang(用户通过 --lang 显式指定的语言)优先,
|
|
1558
1726
|
// 回退到 lang(getCliLang 三级回退结果)。确保记录的语言与实际部署语言一致。
|
|
@@ -1572,85 +1740,132 @@ export function updateProject(projectPath, selectedTools = ["opencode"], lang =
|
|
|
1572
1740
|
globalState.files[getGlobalAgentsMdPath()] = globalState.files[staleCoreKey];
|
|
1573
1741
|
delete globalState.files[staleCoreKey];
|
|
1574
1742
|
}
|
|
1575
|
-
//
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
const
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
const
|
|
1585
|
-
const
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
// 2. 生成 Skill 定义文件到全局 skills 目录(每个 Skill 一个子目录,包含 SKILL.md)
|
|
1590
|
-
for (const [name, content] of Object.entries(SKILL_DEFINITIONS)) {
|
|
1591
|
-
const skillSubDir = join(skillsDir, name);
|
|
1592
|
-
mkdirSync(skillSubDir, { recursive: true });
|
|
1593
|
-
const filePath = join(skillSubDir, 'SKILL.md');
|
|
1594
|
-
const action = deployGlobalAsset(filePath, content, newGlobalState, 'update');
|
|
1595
|
-
pushAction(action, filePath, created, updated, skipped, appended);
|
|
1596
|
-
}
|
|
1597
|
-
// 3. 全局 opencode.jsonc:深度合并(保留用户字段),加全局锁 + 原子写
|
|
1598
|
-
const globalJsoncPath = getGlobalOpencodeJsoncPath();
|
|
1599
|
-
try {
|
|
1600
|
-
// 写前备份(B3):备份须在 jsonc 锁之外(之前)完成,避免 backup 锁与 jsonc 锁嵌套
|
|
1601
|
-
const globalJsoncBackup = backupFileBeforeWrite(globalJsoncPath, { command: 'update' });
|
|
1602
|
-
if (globalJsoncBackup) {
|
|
1603
|
-
appendUpdateInfo('backed', { absolutePath: globalJsoncPath, backupRel: globalJsoncBackup.backupRel, command: 'update' });
|
|
1604
|
-
notifyBackupIfTTY(globalJsoncBackup.backupRel);
|
|
1743
|
+
// opencode 分支(步骤 0~4)——原样保留
|
|
1744
|
+
if (wantOpencode) {
|
|
1745
|
+
// 全局部署目标(D1)
|
|
1746
|
+
const agentsDir = getGlobalAgentsDir();
|
|
1747
|
+
const skillsDir = getGlobalSkillsDir();
|
|
1748
|
+
// 确保全局目标目录存在
|
|
1749
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
1750
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
1751
|
+
// 0. 生成全局框架约束 AGENTS.md(~/.config/opencode/AGENTS.md)
|
|
1752
|
+
const agentsMdPath = getGlobalAgentsMdPath();
|
|
1753
|
+
const agentsMdContent = loadTemplate(lang, 'agents-md');
|
|
1754
|
+
{
|
|
1755
|
+
const action = deployGlobalAsset(agentsMdPath, agentsMdContent, newGlobalState, 'update');
|
|
1756
|
+
pushAction(action, agentsMdPath, created, updated, skipped, appended);
|
|
1605
1757
|
}
|
|
1606
|
-
//
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
const
|
|
1610
|
-
|
|
1611
|
-
|
|
1758
|
+
// 1. 生成 Agent 定义文件到全局 agents 目录(绝对路径作 state key)
|
|
1759
|
+
for (const name of listAgentIds(lang)) {
|
|
1760
|
+
const content = loadAgentTemplate(lang, name);
|
|
1761
|
+
const filePath = join(agentsDir, `${name}.md`);
|
|
1762
|
+
const action = deployGlobalAsset(filePath, content, newGlobalState, 'update');
|
|
1763
|
+
pushAction(action, filePath, created, updated, skipped, appended);
|
|
1764
|
+
}
|
|
1765
|
+
// 2. 生成 Skill 定义文件到全局 skills 目录(每个 Skill 一个子目录,包含 SKILL.md)
|
|
1766
|
+
for (const [name, content] of Object.entries(SKILL_DEFINITIONS)) {
|
|
1767
|
+
const skillSubDir = join(skillsDir, name);
|
|
1768
|
+
mkdirSync(skillSubDir, { recursive: true });
|
|
1769
|
+
const filePath = join(skillSubDir, 'SKILL.md');
|
|
1770
|
+
const action = deployGlobalAsset(filePath, content, newGlobalState, 'update');
|
|
1771
|
+
pushAction(action, filePath, created, updated, skipped, appended);
|
|
1772
|
+
}
|
|
1773
|
+
// 3. 全局 opencode.jsonc:深度合并(保留用户字段),加全局锁 + 原子写
|
|
1774
|
+
const globalJsoncPath = getGlobalOpencodeJsoncPath();
|
|
1775
|
+
try {
|
|
1776
|
+
// 写前备份(B3):备份须在 jsonc 锁之外(之前)完成,避免 backup 锁与 jsonc 锁嵌套
|
|
1777
|
+
const globalJsoncBackup = backupFileBeforeWrite(globalJsoncPath, { command: 'update' });
|
|
1778
|
+
if (globalJsoncBackup) {
|
|
1779
|
+
appendUpdateInfo('backed', { absolutePath: globalJsoncPath, backupRel: globalJsoncBackup.backupRel, command: 'update' });
|
|
1780
|
+
notifyBackupIfTTY(globalJsoncBackup.backupRel);
|
|
1781
|
+
}
|
|
1782
|
+
// REV-1805:read-merge-write 全部置于锁内,消除与 model-config 锁内读写的 TOCTOU 竞态
|
|
1783
|
+
const globalJsoncNew = withFileLock(globalLockPath('global-opencode-jsonc'), () => {
|
|
1784
|
+
// 安全读取(T50):目录占位/不可读 → null,跳过合并与写入,按空配置继续
|
|
1785
|
+
const current = readJsoncFile(globalJsoncPath);
|
|
1786
|
+
if (current === null) {
|
|
1787
|
+
return null;
|
|
1788
|
+
}
|
|
1789
|
+
let merged;
|
|
1790
|
+
// 合并可能因块注释 parse 失败抛异常(parseJsonc 边界):降级为「跳过合并、保留原文件」并告警
|
|
1791
|
+
try {
|
|
1792
|
+
merged = mergeGlobalOpencodeJsonc(current);
|
|
1793
|
+
}
|
|
1794
|
+
catch (err) {
|
|
1795
|
+
console.warn(t('update.globalJsoncParseSkipTmpl', getCliLang(projectPath), { err: err.message }));
|
|
1796
|
+
merged = current;
|
|
1797
|
+
}
|
|
1798
|
+
atomicWriteFileSync(globalJsoncPath, merged);
|
|
1799
|
+
return merged;
|
|
1800
|
+
});
|
|
1801
|
+
if (globalJsoncNew !== null) {
|
|
1802
|
+
updateFileHash(newGlobalState, globalJsoncPath, globalJsoncNew);
|
|
1612
1803
|
}
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1804
|
+
}
|
|
1805
|
+
catch (err) {
|
|
1806
|
+
if (err instanceof BackupError) {
|
|
1807
|
+
// 备份失败(REV-011-A):跳过全局 jsonc 写入、记 anomaly、继续其余步骤(对齐 B3 幂等语义)
|
|
1808
|
+
appendUpdateInfo('anomaly', { absolutePath: globalJsoncPath, note: 'backup_failed' });
|
|
1809
|
+
console.warn(t('update.globalJsoncWriteSkipTmpl', getCliLang(projectPath), { err: err.message }));
|
|
1617
1810
|
}
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
merged = current;
|
|
1811
|
+
else {
|
|
1812
|
+
throw err; // 非备份错误照旧上抛(锁超时等不回退)
|
|
1621
1813
|
}
|
|
1622
|
-
atomicWriteFileSync(globalJsoncPath, merged);
|
|
1623
|
-
return merged;
|
|
1624
|
-
});
|
|
1625
|
-
if (globalJsoncNew !== null) {
|
|
1626
|
-
updateFileHash(newGlobalState, globalJsoncPath, globalJsoncNew);
|
|
1627
1814
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
if (
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
console.warn(t('update.globalJsoncWriteSkipTmpl', getCliLang(projectPath), { err: err.message }));
|
|
1815
|
+
// 4. 项目 opencode.jsonc:不存在则写最小 { $schema };已存在则保留(旧非法字段清理属 stage-39)
|
|
1816
|
+
const projectJsoncPath = resolve(projectPath, 'opencode.jsonc');
|
|
1817
|
+
if (!existsSync(projectJsoncPath)) {
|
|
1818
|
+
atomicWriteFileSync(projectJsoncPath, JSON.stringify(buildProjectOpencodeJsoncObj(), null, 2) + '\n');
|
|
1819
|
+
created.push('opencode.jsonc');
|
|
1634
1820
|
}
|
|
1635
1821
|
else {
|
|
1636
|
-
|
|
1822
|
+
skipped.push('opencode.jsonc (use existing)');
|
|
1637
1823
|
}
|
|
1638
1824
|
}
|
|
1639
|
-
//
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1825
|
+
// claude 分支:CLAUDE.md + 9 agent + 17 共享 skill + settings.json(stage-73)
|
|
1826
|
+
if (wantClaude) {
|
|
1827
|
+
const claudeAgentsDir = getClaudeAgentsDir();
|
|
1828
|
+
const claudeSkillsDir = getClaudeSkillsDir();
|
|
1829
|
+
mkdirSync(claudeAgentsDir, { recursive: true });
|
|
1830
|
+
mkdirSync(claudeSkillsDir, { recursive: true });
|
|
1831
|
+
// 1c. CLAUDE.md(受管区三态复用 deployGlobalAsset;用户已有 → append 不覆盖)
|
|
1832
|
+
const claudeMd = getClaudeMdPath();
|
|
1833
|
+
pushAction(deployGlobalAsset(claudeMd, loadClaudeConstraintTemplate(lang), newGlobalState, 'update'), claudeMd, created, updated, skipped, appended);
|
|
1834
|
+
// 2c. 9 agents(含 feel)
|
|
1835
|
+
for (const name of listClaudeAgentIds(lang)) {
|
|
1836
|
+
const p = join(claudeAgentsDir, `${name}.md`);
|
|
1837
|
+
pushAction(deployGlobalAsset(p, loadClaudeAgentTemplate(lang, name), newGlobalState, 'update'), p, created, updated, skipped, appended);
|
|
1838
|
+
}
|
|
1839
|
+
// 3c. 17 共享 skills
|
|
1840
|
+
for (const [name, content] of Object.entries(SKILL_DEFINITIONS)) {
|
|
1841
|
+
const dir = join(claudeSkillsDir, name);
|
|
1842
|
+
mkdirSync(dir, { recursive: true });
|
|
1843
|
+
const p = join(dir, 'SKILL.md');
|
|
1844
|
+
pushAction(deployGlobalAsset(p, content, newGlobalState, 'update'), p, created, updated, skipped, appended);
|
|
1845
|
+
}
|
|
1846
|
+
// 4c. settings.json(与 setup 对称,共享 applyClaudeSettings,杜绝双实现漂移)
|
|
1847
|
+
const settingsPath = getClaudeSettingsPath();
|
|
1848
|
+
pushAction(applyClaudeSettings(newGlobalState, 'update', getCliLang(projectPath)), settingsPath, created, updated, skipped, appended);
|
|
1647
1849
|
}
|
|
1648
|
-
//
|
|
1649
|
-
if (
|
|
1850
|
+
// 重启提醒(按 harness 组合;isTTY 守卫、非交互静默)
|
|
1851
|
+
if (process.stdout.isTTY) {
|
|
1650
1852
|
const reminderLang = getCliLang(projectPath);
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1853
|
+
const opencodeChanged = updated.some((f) => f.startsWith(getGlobalAgentsDir()));
|
|
1854
|
+
const claudeChanged = [...created, ...updated, ...appended].some((f) => f.startsWith(getClaudeAgentsDir()) || f.startsWith(getClaudeSkillsDir())
|
|
1855
|
+
|| f === getClaudeMdPath() || f === getClaudeSettingsPath());
|
|
1856
|
+
const harnesses = [];
|
|
1857
|
+
if (opencodeChanged) {
|
|
1858
|
+
harnesses.push('opencode');
|
|
1859
|
+
}
|
|
1860
|
+
if (claudeChanged) {
|
|
1861
|
+
harnesses.push('Claude Code');
|
|
1862
|
+
}
|
|
1863
|
+
if (harnesses.length > 0) {
|
|
1864
|
+
console.log(t('update.restartHarnessTmpl', reminderLang, { harness: harnesses.join(' / ') }));
|
|
1865
|
+
if (claudeChanged) {
|
|
1866
|
+
console.log(t('update.claudeReloadHintTmpl', reminderLang));
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1654
1869
|
}
|
|
1655
1870
|
// ── 写入冲突标记文件 ──
|
|
1656
1871
|
if (conflicts.length > 0) {
|
|
@@ -1758,6 +1973,18 @@ function getIncomingContent(relativePath, lang) {
|
|
|
1758
1973
|
const name = basename(dirname(relativePath));
|
|
1759
1974
|
return SKILL_DEFINITIONS[name] ?? '';
|
|
1760
1975
|
}
|
|
1976
|
+
// Claude 全局约束 CLAUDE.md
|
|
1977
|
+
if (relativePath === getClaudeMdPath()) {
|
|
1978
|
+
return loadClaudeConstraintTemplate(lang);
|
|
1979
|
+
}
|
|
1980
|
+
// Claude agent:位于 getClaudeAgentsDir() 下的 {name}.md
|
|
1981
|
+
if (relativePath.startsWith(getClaudeAgentsDir())) {
|
|
1982
|
+
return loadClaudeAgentTemplate(lang, basename(relativePath, '.md'));
|
|
1983
|
+
}
|
|
1984
|
+
// Claude skill:位于 getClaudeSkillsDir() 下的 {name}/SKILL.md
|
|
1985
|
+
if (relativePath.startsWith(getClaudeSkillsDir()) && basename(relativePath) === 'SKILL.md') {
|
|
1986
|
+
return SKILL_DEFINITIONS[basename(dirname(relativePath))] ?? '';
|
|
1987
|
+
}
|
|
1761
1988
|
// 项目 opencode.jsonc
|
|
1762
1989
|
if (relativePath === 'opencode.jsonc') {
|
|
1763
1990
|
return JSON.stringify(buildProjectOpencodeJsoncObj(), null, 2) + '\n';
|