@ranger1/dx 0.1.40 → 0.1.41
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.
|
@@ -18,7 +18,7 @@ pnpm add -g @ranger1/dx@latest && dx initial
|
|
|
18
18
|
|
|
19
19
|
## Step 1: 并行检测
|
|
20
20
|
|
|
21
|
-
**同时执行以下
|
|
21
|
+
**同时执行以下 4 个 Bash 调用(真正并行):**
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
# 批次 1: CLI 版本检测
|
|
@@ -32,24 +32,20 @@ echo "agent-browser:" && (which agent-browser && agent-browser --version 2>/dev/
|
|
|
32
32
|
# 批次 2: 项目文件检测
|
|
33
33
|
echo "=== PROJECT_FILES ===";
|
|
34
34
|
echo "AGENTS.md:" && (test -f AGENTS.md && echo "FOUND" || echo "NOT_FOUND");
|
|
35
|
-
echo "instructions:" && (grep -q '"AGENTS.md"' ~/.config/opencode/opencode.json 2>/dev/null && grep -q '"ruler/' ~/.config/opencode/opencode.json 2>/dev/null && echo "CONFIGURED" || echo "NOT_CONFIGURED");
|
|
36
35
|
```
|
|
37
36
|
|
|
38
37
|
```bash
|
|
39
38
|
# 批次 3: OpenCode 插件检测
|
|
40
39
|
# 注意:插件名可能带版本号(如 @1.3.0),使用模糊匹配
|
|
41
40
|
echo "=== OPENCODE_PLUGINS ===";
|
|
42
|
-
echo "oh-my-opencode:" && (grep -q 'oh-my-opencode'
|
|
43
|
-
echo "opencode-openai-codex-auth:" && (grep -q 'opencode-openai-codex-auth'
|
|
41
|
+
echo "oh-my-opencode:" && (opencode plugin list 2>/dev/null | grep -q 'oh-my-opencode' && echo "INSTALLED" || echo "NOT_INSTALLED");
|
|
42
|
+
echo "opencode-openai-codex-auth:" && (opencode plugin list 2>/dev/null | grep -q 'opencode-openai-codex-auth' && echo "INSTALLED" || echo "NOT_INSTALLED");
|
|
44
43
|
```
|
|
45
44
|
|
|
46
45
|
```bash
|
|
47
|
-
# 批次 4:
|
|
48
|
-
echo "===
|
|
49
|
-
echo "
|
|
50
|
-
echo "agents.sisyphus.variant:" && (node -e "const fs=require('node:fs');const os=require('node:os');const p=os.homedir()+'/.config/opencode/oh-my-opencode.json';try{const j=JSON.parse(fs.readFileSync(p,'utf8'));process.exit(j?.agents?.sisyphus?.variant==='none'?0:1)}catch(e){process.exit(1)}" 2>/dev/null && echo "CONFIGURED" || echo "NOT_CONFIGURED");
|
|
51
|
-
echo "agent.quick:" && (grep -Eq '"agent"[[:space:]]*:' ~/.config/opencode/opencode.json 2>/dev/null && grep -Eq '"quick"[[:space:]]*:' ~/.config/opencode/opencode.json 2>/dev/null && echo "CONFIGURED" || echo "NOT_CONFIGURED");
|
|
52
|
-
echo "agent.middle:" && (grep -Eq '"agent"[[:space:]]*:' ~/.config/opencode/opencode.json 2>/dev/null && grep -Eq '"middle"[[:space:]]*:' ~/.config/opencode/opencode.json 2>/dev/null && echo "CONFIGURED" || echo "NOT_CONFIGURED");
|
|
46
|
+
# 批次 4: attach 配置(统一)
|
|
47
|
+
echo "=== OPENCODE_ATTACH ===";
|
|
48
|
+
echo "attach:" && (python3 ~/.opencode/commands/opencode_attach.py --dry-run >/dev/null 2>&1 && echo "READY" || echo "NOT_READY");
|
|
53
49
|
```
|
|
54
50
|
|
|
55
51
|
```bash
|
|
@@ -72,14 +68,10 @@ dx | <状态> | <版本>
|
|
|
72
68
|
python3 | <状态> | <版本>
|
|
73
69
|
python(软链接) | <状态> | <版本>
|
|
74
70
|
AGENTS.md | <状态> | -
|
|
75
|
-
全局 instructions 配置 | <状态> | -
|
|
76
71
|
oh-my-opencode 插件 | <状态> | -
|
|
77
72
|
opencode-openai-codex-auth 插件 | <状态> | -
|
|
78
73
|
agent-browser | <状态> | <版本>
|
|
79
|
-
|
|
80
|
-
全局 agents.sisyphus.variant 配置 | <状态> | -
|
|
81
|
-
全局 agent.quick 配置 | <状态> | -
|
|
82
|
-
全局 agent.middle 配置 | <状态> | -
|
|
74
|
+
attach(全局配置写入) | <状态> | -
|
|
83
75
|
```
|
|
84
76
|
|
|
85
77
|
---
|
|
@@ -107,62 +99,6 @@ brew install opencode || npm install -g opencode
|
|
|
107
99
|
|
|
108
100
|
- AGENTS.md 文件不存在,OpenCode 需要此文件作为项目指令入口
|
|
109
101
|
- 建议创建或检查文件路径
|
|
110
|
-
- AGENTS.md 应位于项目根目录,并在全局 `~/.config/opencode/opencode.json` 的 `instructions` 中引用
|
|
111
|
-
|
|
112
|
-
### 3.3 全局 opencode.json instructions 配置缺失
|
|
113
|
-
|
|
114
|
-
**注意:instructions 配置应在全局配置文件 `~/.config/opencode/opencode.json` 中,而非项目根目录。项目根目录不需要 opencode.json 文件。**
|
|
115
|
-
|
|
116
|
-
1. 先读取现有全局配置:
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
cat ~/.config/opencode/opencode.json
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
2. 使用 Edit 工具在 `~/.config/opencode/opencode.json` 中添加或修改 `instructions` 配置:
|
|
123
|
-
|
|
124
|
-
```json
|
|
125
|
-
{
|
|
126
|
-
"$schema": "https://opencode.ai/config.json",
|
|
127
|
-
"instructions": ["AGENTS.md", "ruler/**/*.md"]
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### 3.4 全局配置指令无效
|
|
132
|
-
|
|
133
|
-
使用 Edit 工具修复 `~/.config/opencode/opencode.json`,确保包含:
|
|
134
|
-
|
|
135
|
-
- `"AGENTS.md"`: 主配置文件
|
|
136
|
-
- `"ruler/**/*.md"`: 自动加载 ruler 目录下所有 .md 文件(因 OpenCode 不支持 @ 引用)
|
|
137
|
-
|
|
138
|
-
### 3.5 全局 OpenCode 插件安装
|
|
139
|
-
|
|
140
|
-
**注意:OpenCode 插件配置应在全局配置文件 `~/.config/opencode/opencode.json` 中,而非项目根目录。**
|
|
141
|
-
|
|
142
|
-
1. 先读取现有全局配置:
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
cat ~/.config/opencode/opencode.json
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
2. 使用 Edit 工具在 `~/.config/opencode/opencode.json` 的 `plugin` 数组中添加缺失的插件:
|
|
149
|
-
- `oh-my-opencode`
|
|
150
|
-
- `opencode-openai-codex-auth`
|
|
151
|
-
|
|
152
|
-
示例 plugin 配置:
|
|
153
|
-
|
|
154
|
-
```json
|
|
155
|
-
"plugin": [
|
|
156
|
-
"oh-my-opencode",
|
|
157
|
-
"opencode-openai-codex-auth"
|
|
158
|
-
]
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
3. 验证安装:
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
grep -E 'oh-my-opencode|opencode-openai-codex-auth' ~/.config/opencode/opencode.json
|
|
165
|
-
```
|
|
166
102
|
|
|
167
103
|
### 3.6 agent-browser 未安装
|
|
168
104
|
|
|
@@ -212,87 +148,15 @@ fi
|
|
|
212
148
|
python --version
|
|
213
149
|
```
|
|
214
150
|
|
|
215
|
-
### 3.
|
|
216
|
-
|
|
217
|
-
**注意:oh-my-opencode 配置应在全局配置文件 `~/.config/opencode/oh-my-opencode.json` 中,而非项目根目录。**
|
|
151
|
+
### 3.9 自动 attach(推荐)
|
|
218
152
|
|
|
219
|
-
|
|
153
|
+
执行 attach(会自动覆盖/新建对应节点,其它不动,并生成备份文件):
|
|
220
154
|
|
|
221
155
|
```bash
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
2. 使用 Edit 工具添加缺失的配置节点:
|
|
226
|
-
|
|
227
|
-
#### 3.7.1 sisyphus_agent 配置缺失
|
|
228
|
-
|
|
229
|
-
如果根节点缺少 `sisyphus_agent`,使用 Edit 工具添加:
|
|
230
|
-
|
|
231
|
-
```json
|
|
232
|
-
{
|
|
233
|
-
"sisyphus_agent": {
|
|
234
|
-
"disabled": false,
|
|
235
|
-
"default_builder_enabled": true,
|
|
236
|
-
"planner_enabled": true,
|
|
237
|
-
"replace_plan": false
|
|
238
|
-
}
|
|
239
|
-
}
|
|
156
|
+
python3 ~/.opencode/commands/opencode_attach.py
|
|
240
157
|
```
|
|
241
158
|
|
|
242
|
-
注意:这是根节点配置,应添加到 JSON 的第一层级。
|
|
243
159
|
|
|
244
|
-
#### 3.7.2 agents.sisyphus.variant 不是 none
|
|
245
|
-
|
|
246
|
-
如果 `~/.config/opencode/oh-my-opencode.json` 的 `agents.sisyphus.variant` 缺失或不是 `none`,使用 Edit 工具修复为:
|
|
247
|
-
|
|
248
|
-
```json
|
|
249
|
-
{
|
|
250
|
-
"agents": {
|
|
251
|
-
"sisyphus": {
|
|
252
|
-
"variant": "none"
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
3. 验证配置:
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
# 检查 sisyphus_agent
|
|
262
|
-
grep -q '"sisyphus_agent"' ~/.config/opencode/oh-my-opencode.json && echo "✅ sisyphus_agent 已配置" || echo "❌ sisyphus_agent 缺失"
|
|
263
|
-
|
|
264
|
-
# 检查 agents.sisyphus.variant
|
|
265
|
-
node -e "const fs=require('node:fs');const os=require('node:os');const p=os.homedir()+'/.config/opencode/oh-my-opencode.json';const j=JSON.parse(fs.readFileSync(p,'utf8'));console.log(j?.agents?.sisyphus?.variant||'MISSING');process.exit(j?.agents?.sisyphus?.variant==='none'?0:1)" && echo "✅ agents.sisyphus.variant=none" || echo "❌ agents.sisyphus.variant 不是 none"
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### 3.8 全局 opencode.json agent 配置缺失
|
|
269
|
-
|
|
270
|
-
**注意:agent 配置应在全局配置文件 `~/.config/opencode/opencode.json` 中,而非项目根目录。**
|
|
271
|
-
|
|
272
|
-
如果 `~/.config/opencode/opencode.json` 缺少 `agent.quick` 或 `agent.middle`,使用 Edit 工具添加:
|
|
273
|
-
|
|
274
|
-
```json
|
|
275
|
-
{
|
|
276
|
-
"agent": {
|
|
277
|
-
"quick": {
|
|
278
|
-
"model": "github-copilot/claude-haiku-4.5"
|
|
279
|
-
},
|
|
280
|
-
"middle": {
|
|
281
|
-
"model": "github-copilot/claude-sonnet-4.5"
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
验证配置:
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
# 检查 agent.quick
|
|
291
|
-
grep -Eq '"agent"[[:space:]]*:' ~/.config/opencode/opencode.json && grep -Eq '"quick"[[:space:]]*:' ~/.config/opencode/opencode.json && echo "✅ agent.quick 已配置" || echo "❌ agent.quick 缺失"
|
|
292
|
-
|
|
293
|
-
# 检查 agent.middle
|
|
294
|
-
grep -Eq '"agent"[[:space:]]*:' ~/.config/opencode/opencode.json && grep -Eq '"middle"[[:space:]]*:' ~/.config/opencode/opencode.json && echo "✅ agent.middle 已配置" || echo "❌ agent.middle 缺失"
|
|
295
|
-
```
|
|
296
160
|
|
|
297
161
|
---
|
|
298
162
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sisyphus_agent": {
|
|
3
|
+
"disabled": false,
|
|
4
|
+
"default_builder_enabled": true,
|
|
5
|
+
"planner_enabled": true,
|
|
6
|
+
"replace_plan": false
|
|
7
|
+
},
|
|
8
|
+
"agents": {
|
|
9
|
+
"sisyphus": {
|
|
10
|
+
"model": "openai/gpt-5.2",
|
|
11
|
+
"variant": "none"
|
|
12
|
+
},
|
|
13
|
+
"oracle": {
|
|
14
|
+
"model": "openai/gpt-5.2",
|
|
15
|
+
"variant": "high"
|
|
16
|
+
},
|
|
17
|
+
"librarian": {
|
|
18
|
+
"model": "github-copilot/gpt-5-mini"
|
|
19
|
+
},
|
|
20
|
+
"explore": {
|
|
21
|
+
"model": "github-copilot/gpt-5-mini"
|
|
22
|
+
},
|
|
23
|
+
"multimodal-looker": {
|
|
24
|
+
"model": "github-copilot/gemini-3-flash-preview"
|
|
25
|
+
},
|
|
26
|
+
"prometheus": {
|
|
27
|
+
"model": "openai/gpt-5.2",
|
|
28
|
+
"variant": "max"
|
|
29
|
+
},
|
|
30
|
+
"metis": {
|
|
31
|
+
"model": "openai/gpt-5.2",
|
|
32
|
+
"variant": "max"
|
|
33
|
+
},
|
|
34
|
+
"momus": {
|
|
35
|
+
"model": "openai/gpt-5.2",
|
|
36
|
+
"variant": "medium"
|
|
37
|
+
},
|
|
38
|
+
"atlas": {
|
|
39
|
+
"model": "openai/gpt-5.2-codex"
|
|
40
|
+
},
|
|
41
|
+
"codex-reviewer": {
|
|
42
|
+
"model": "openai/gpt-5.2-codex",
|
|
43
|
+
"variant": "xhigh",
|
|
44
|
+
"temperature": 0.1
|
|
45
|
+
},
|
|
46
|
+
"gemini-reviewer": {
|
|
47
|
+
"model": "github-copilot/gemini-3-pro-preview",
|
|
48
|
+
"variant": "max"
|
|
49
|
+
},
|
|
50
|
+
"claude-reviewer": {
|
|
51
|
+
"model": "github-copilot/claude-sonnet-4.5",
|
|
52
|
+
"variant": "high"
|
|
53
|
+
},
|
|
54
|
+
"pr-fixer": {
|
|
55
|
+
"model": "openai/gpt-5.2-codex",
|
|
56
|
+
"variant": "xhigh",
|
|
57
|
+
"temperature": 0.1
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"concurrency": 5,
|
|
61
|
+
"categories": {
|
|
62
|
+
"visual-engineering": {
|
|
63
|
+
"model": "github-copilot/gemini-3-pro-preview",
|
|
64
|
+
"variant": "high"
|
|
65
|
+
},
|
|
66
|
+
"ultrabrain": {
|
|
67
|
+
"model": "openai/gpt-5.2-codex",
|
|
68
|
+
"variant": "xhigh"
|
|
69
|
+
},
|
|
70
|
+
"artistry": {
|
|
71
|
+
"model": "github-copilot/gemini-3-pro-preview",
|
|
72
|
+
"variant": "max"
|
|
73
|
+
},
|
|
74
|
+
"quick": {
|
|
75
|
+
"model": "github-copilot/claude-haiku-4.5"
|
|
76
|
+
},
|
|
77
|
+
"middle": {
|
|
78
|
+
"model": "github-copilot/claude-sonnet-4.5"
|
|
79
|
+
},
|
|
80
|
+
"unspecified-low": {
|
|
81
|
+
"model": "github-copilot/claude-sonnet-4.5",
|
|
82
|
+
"variant": "medium"
|
|
83
|
+
},
|
|
84
|
+
"unspecified-high": {
|
|
85
|
+
"model": "openai/gpt-5.2",
|
|
86
|
+
"variant": "medium"
|
|
87
|
+
},
|
|
88
|
+
"writing": {
|
|
89
|
+
"model": "github-copilot/gemini-3-flash-preview"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"instructions": [
|
|
3
|
+
"AGENTS.md",
|
|
4
|
+
"ruler/**/*.md"
|
|
5
|
+
],
|
|
6
|
+
"plugin": [
|
|
7
|
+
"opencode-antigravity-auth",
|
|
8
|
+
"oh-my-opencode",
|
|
9
|
+
"opencode-openai-codex-auth"
|
|
10
|
+
],
|
|
11
|
+
"agent": {
|
|
12
|
+
"quick": {
|
|
13
|
+
"model": "github-copilot/gpt-5-mini"
|
|
14
|
+
},
|
|
15
|
+
"middle": {
|
|
16
|
+
"model": "github-copilot/claude-sonnet-4.5"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"permission": {
|
|
20
|
+
"read": {
|
|
21
|
+
"*.env": "allow",
|
|
22
|
+
"*.env.*": "allow"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"model": "openai/gpt-5.2"
|
|
26
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
import sys
|
|
8
|
+
import time
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _is_plain_object(value):
|
|
13
|
+
return isinstance(value, dict)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def deep_merge_in_place(target, source):
|
|
17
|
+
if not _is_plain_object(target) or not _is_plain_object(source):
|
|
18
|
+
raise TypeError("deep_merge_in_place expects dicts")
|
|
19
|
+
|
|
20
|
+
for key, s_val in source.items():
|
|
21
|
+
if _is_plain_object(s_val):
|
|
22
|
+
t_val = target.get(key)
|
|
23
|
+
if not _is_plain_object(t_val):
|
|
24
|
+
t_val = {}
|
|
25
|
+
target[key] = t_val
|
|
26
|
+
deep_merge_in_place(t_val, s_val)
|
|
27
|
+
else:
|
|
28
|
+
target[key] = s_val
|
|
29
|
+
|
|
30
|
+
return target
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def load_json_file(path):
|
|
34
|
+
raw = path.read_text(encoding="utf-8")
|
|
35
|
+
return json.loads(raw)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def atomic_write_json(path, data):
|
|
39
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
40
|
+
tmp_path = path.with_name(f"{path.name}.tmp.{os.getpid()}")
|
|
41
|
+
serialized = json.dumps(data, ensure_ascii=False, indent=2) + "\n"
|
|
42
|
+
tmp_path.write_text(serialized, encoding="utf-8")
|
|
43
|
+
os.replace(tmp_path, path)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def backup_file(path):
|
|
47
|
+
if not path.exists():
|
|
48
|
+
return None
|
|
49
|
+
ts = time.strftime("%Y%m%d%H%M%S")
|
|
50
|
+
bak = path.with_name(f"{path.name}.bak.{ts}")
|
|
51
|
+
shutil.copy2(path, bak)
|
|
52
|
+
return bak
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def attach(source_path, target_path, *, make_backup=True, dry_run=False):
|
|
56
|
+
source = load_json_file(source_path)
|
|
57
|
+
if not _is_plain_object(source):
|
|
58
|
+
raise ValueError(f"Source JSON root must be an object: {source_path}")
|
|
59
|
+
|
|
60
|
+
if target_path.exists():
|
|
61
|
+
target = load_json_file(target_path)
|
|
62
|
+
if not _is_plain_object(target):
|
|
63
|
+
raise ValueError(f"Target JSON root must be an object: {target_path}")
|
|
64
|
+
else:
|
|
65
|
+
target = {}
|
|
66
|
+
|
|
67
|
+
merged = deep_merge_in_place(target, source)
|
|
68
|
+
|
|
69
|
+
bak = None
|
|
70
|
+
if make_backup and target_path.exists() and not dry_run:
|
|
71
|
+
bak = backup_file(target_path)
|
|
72
|
+
|
|
73
|
+
if not dry_run:
|
|
74
|
+
atomic_write_json(target_path, merged)
|
|
75
|
+
|
|
76
|
+
return bak
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def main(argv):
|
|
80
|
+
parser = argparse.ArgumentParser(
|
|
81
|
+
description=(
|
|
82
|
+
"Attach JSON fragments into OpenCode global config files. "
|
|
83
|
+
"Rule: deep-merge objects; replace arrays/primitives; preserve other keys."
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--oh-source",
|
|
88
|
+
default=str(Path(__file__).resolve().parents[1] / "commands" / "oh_attach.json"),
|
|
89
|
+
help="Path to oh_attach.json",
|
|
90
|
+
)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--opencode-source",
|
|
93
|
+
default=str(Path(__file__).resolve().parents[1] / "commands" / "opencode_attach.json"),
|
|
94
|
+
help="Path to opencode_attach.json",
|
|
95
|
+
)
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
"--config-dir",
|
|
98
|
+
default=str(Path.home() / ".config" / "opencode"),
|
|
99
|
+
help="Config directory (default: ~/.config/opencode)",
|
|
100
|
+
)
|
|
101
|
+
parser.add_argument("--no-backup", action="store_true", help="Do not create .bak files")
|
|
102
|
+
parser.add_argument("--dry-run", action="store_true", help="Do not write files")
|
|
103
|
+
|
|
104
|
+
args = parser.parse_args(argv)
|
|
105
|
+
|
|
106
|
+
config_dir = Path(os.path.expanduser(args.config_dir)).resolve()
|
|
107
|
+
oh_target = config_dir / "oh-my-opencode.json"
|
|
108
|
+
opencode_target = config_dir / "opencode.json"
|
|
109
|
+
|
|
110
|
+
oh_source = Path(args.oh_source).resolve()
|
|
111
|
+
opencode_source = Path(args.opencode_source).resolve()
|
|
112
|
+
|
|
113
|
+
if not oh_source.exists():
|
|
114
|
+
raise FileNotFoundError(f"Missing source file: {oh_source}")
|
|
115
|
+
if not opencode_source.exists():
|
|
116
|
+
raise FileNotFoundError(f"Missing source file: {opencode_source}")
|
|
117
|
+
|
|
118
|
+
make_backup = not args.no_backup
|
|
119
|
+
dry_run = args.dry_run
|
|
120
|
+
|
|
121
|
+
bak1 = attach(oh_source, oh_target, make_backup=make_backup, dry_run=dry_run)
|
|
122
|
+
bak2 = attach(opencode_source, opencode_target, make_backup=make_backup, dry_run=dry_run)
|
|
123
|
+
|
|
124
|
+
if dry_run:
|
|
125
|
+
print("DRY_RUN: no files written")
|
|
126
|
+
return 0
|
|
127
|
+
|
|
128
|
+
if bak1:
|
|
129
|
+
print(f"backup: {bak1}")
|
|
130
|
+
if bak2:
|
|
131
|
+
print(f"backup: {bak2}")
|
|
132
|
+
print(f"updated: {oh_target}")
|
|
133
|
+
print(f"updated: {opencode_target}")
|
|
134
|
+
return 0
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
try:
|
|
139
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
140
|
+
except Exception as e:
|
|
141
|
+
print(f"ERROR: {e}", file=sys.stderr)
|
|
142
|
+
raise SystemExit(1)
|
package/lib/opencode-initial.js
CHANGED
|
@@ -27,8 +27,8 @@ async function collectTemplateFiles(dir) {
|
|
|
27
27
|
}
|
|
28
28
|
if (!entry.isFile()) continue
|
|
29
29
|
const lowerName = entry.name.toLowerCase()
|
|
30
|
-
// 拷贝 .md
|
|
31
|
-
if (!lowerName.endsWith('.md') && !lowerName.endsWith('.py')) continue
|
|
30
|
+
// 拷贝 .md / .py / .json 文件
|
|
31
|
+
if (!lowerName.endsWith('.md') && !lowerName.endsWith('.py') && !lowerName.endsWith('.json')) continue
|
|
32
32
|
// 跳过 Python 编译文件
|
|
33
33
|
if (lowerName.endsWith('.pyc') || lowerName.endsWith('.pyo') || lowerName.endsWith('.pyd')) continue
|
|
34
34
|
out.push(full)
|
|
@@ -59,6 +59,7 @@ async function copyTemplateTree({ srcDir, dstDir }) {
|
|
|
59
59
|
const files = await collectTemplateFiles(srcDir)
|
|
60
60
|
let mdCount = 0
|
|
61
61
|
let pyCount = 0
|
|
62
|
+
let jsonCount = 0
|
|
62
63
|
|
|
63
64
|
for (const file of files) {
|
|
64
65
|
const rel = relative(srcDir, file)
|
|
@@ -75,10 +76,12 @@ async function copyTemplateTree({ srcDir, dstDir }) {
|
|
|
75
76
|
} catch {
|
|
76
77
|
// 忽略权限设置失败
|
|
77
78
|
}
|
|
79
|
+
} else if (file.endsWith('.json')) {
|
|
80
|
+
jsonCount++
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
return { total: files.length, md: mdCount, py: pyCount }
|
|
84
|
+
return { total: files.length, md: mdCount, py: pyCount, json: jsonCount }
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
function resolveTemplateRoot(packageRoot) {
|
|
@@ -125,6 +128,14 @@ export async function runOpenCodeInitial(options = {}) {
|
|
|
125
128
|
const commandsStats = await copyTemplateTree({ srcDir: srcCommands, dstDir: dstCommands })
|
|
126
129
|
|
|
127
130
|
logger.success(`已初始化 OpenCode 模板到: ${dstRoot}`)
|
|
128
|
-
logger.info(
|
|
129
|
-
|
|
131
|
+
logger.info(
|
|
132
|
+
`agents: ${agentsStats.md} 个 .md 文件` +
|
|
133
|
+
`${agentsStats.py > 0 ? ` + ${agentsStats.py} 个 .py 文件` : ''}` +
|
|
134
|
+
`${agentsStats.json > 0 ? ` + ${agentsStats.json} 个 .json 文件` : ''}`
|
|
135
|
+
)
|
|
136
|
+
logger.info(
|
|
137
|
+
`commands: ${commandsStats.md} 个 .md 文件` +
|
|
138
|
+
`${commandsStats.py > 0 ? ` + ${commandsStats.py} 个 .py 文件` : ''}` +
|
|
139
|
+
`${commandsStats.json > 0 ? ` + ${commandsStats.json} 个 .json 文件` : ''}`
|
|
140
|
+
)
|
|
130
141
|
}
|