@aiyiran/myclaw 1.0.92 → 1.0.93
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/agent-list/workspace-danci/memory/english-words-20260401.md +225 -0
- package/build-manifest.js +43 -20
- package/index.js +105 -2
- package/package.json +1 -1
- package/patch-agent.js +9 -9
- package/patch-manifest.json +11 -4
- package/pull.js +197 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# 英语单词学习记录
|
|
2
|
+
## 日期:2026年4月1日
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 学习目标
|
|
7
|
+
- 20个英语单词
|
|
8
|
+
- 对象:初中生
|
|
9
|
+
- 要求:记得快、记得好
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 单词列表
|
|
14
|
+
|
|
15
|
+
### 1. espionage [ɪˈspaɪənɪdʒ]
|
|
16
|
+
- 词性:名词
|
|
17
|
+
- 含义:间谍活动
|
|
18
|
+
- 例句:The government has several agents involved in espionage.
|
|
19
|
+
(政府有好几个特工参与间谍活动。)
|
|
20
|
+
|
|
21
|
+
### 2. mission [ˈmɪʃn]
|
|
22
|
+
- 词性:名词
|
|
23
|
+
- 含义:任务
|
|
24
|
+
- 例句:The mission brief was sent to your computer.
|
|
25
|
+
(任务简报已经发到你的电脑里了。)
|
|
26
|
+
|
|
27
|
+
### 3. brief [briːf]
|
|
28
|
+
- 词性:名词/形容词
|
|
29
|
+
- 含义:简报(n.)/ 简短的(adj.)
|
|
30
|
+
- 例句:The mission brief was sent to your computer.
|
|
31
|
+
(任务简报已经发到你的电脑里了。)
|
|
32
|
+
|
|
33
|
+
### 4. agent [ˈeɪdʒənt]
|
|
34
|
+
- 词性:名词
|
|
35
|
+
- 含义:特工、代理人
|
|
36
|
+
- 例句:The secret agent went into the building alone.
|
|
37
|
+
(那名秘密特工独自走进了那栋大楼。)
|
|
38
|
+
- 简化例句:He is an undercover cop.(他是一名卧底警察。)
|
|
39
|
+
|
|
40
|
+
### 5. undercover [ˌʌndəˈkʌvə(r)]
|
|
41
|
+
- 词性:形容词
|
|
42
|
+
- 含义:卧底的、秘密执行的
|
|
43
|
+
- 例句:He is an undercover cop.(他是一名卧底警察。)
|
|
44
|
+
- 记忆技巧:under(在…下面)+ cover(覆盖)= 在覆盖之下 = 卧底的
|
|
45
|
+
|
|
46
|
+
### 6. surveillance [səˈveɪləns]
|
|
47
|
+
- 词性:名词
|
|
48
|
+
- 含义:监视、监控
|
|
49
|
+
- 例句:The police kept the building under surveillance.
|
|
50
|
+
(警察对那栋大楼进行了监视。)
|
|
51
|
+
- 记忆技巧:谐音"司马在外"(Sima Fu)= 司马孚在外面监视 = surveillance
|
|
52
|
+
|
|
53
|
+
### 7. gadget [ˈɡædʒɪt]
|
|
54
|
+
- 词性:名词
|
|
55
|
+
- 含义:小玩意儿、小装置
|
|
56
|
+
- 例句:The spy used a cool gadget to open the door.
|
|
57
|
+
(特工用一个酷炫的小装置打开了门。)
|
|
58
|
+
- 词源:19世纪英国水手的俚语,用来称呼各种不知道叫什么的小零件
|
|
59
|
+
|
|
60
|
+
### 8. intel [ˈɪntl]
|
|
61
|
+
- 词性:名词
|
|
62
|
+
- 含义:情报(intelligence的缩写)
|
|
63
|
+
- 例句:The agent got some important intel.
|
|
64
|
+
(特工收到了一条重要情报。)
|
|
65
|
+
- 记忆技巧:in + tel(telephone)= 从电话里得到的情报
|
|
66
|
+
|
|
67
|
+
### 9. extraction [ɪkˈstrækʃn]
|
|
68
|
+
- 词性:名词
|
|
69
|
+
- 含义:撤离、营救
|
|
70
|
+
- 例句:The team made a quick extraction.(小队快速撤离。)
|
|
71
|
+
- 记忆技巧:ex(出来)+ tract(拉)= 拉出来 = 撤离
|
|
72
|
+
- 5个例句:
|
|
73
|
+
1. The rescue team did a fast extraction.
|
|
74
|
+
2. The spy was in trouble, so they ordered an extraction.
|
|
75
|
+
3. The extraction point is near the old building.
|
|
76
|
+
4. He finished the extraction mission successfully.
|
|
77
|
+
5. The helicopter came for the extraction.
|
|
78
|
+
|
|
79
|
+
### 10. code [kəʊd]
|
|
80
|
+
- 词性:名词
|
|
81
|
+
- 含义:密码、代码
|
|
82
|
+
- 例句:The spy used a secret code to send messages.
|
|
83
|
+
(特工用密码发送信息。)
|
|
84
|
+
- 5个例句:
|
|
85
|
+
1. Don't tell anyone the secret code.
|
|
86
|
+
2. The password is a four-digit code.
|
|
87
|
+
3. He broke the code and saved the day.
|
|
88
|
+
4. What is the secret code?
|
|
89
|
+
5. She sent a message in code.
|
|
90
|
+
|
|
91
|
+
### 11. cipher [ˈsaɪfə(r)]
|
|
92
|
+
- 词性:名词
|
|
93
|
+
- 含义:密码、密文(更专业的加密术语)
|
|
94
|
+
- 例句:Can you read this cipher?(你能读懂这个密码吗?)
|
|
95
|
+
- 与code的区别:code是把整个词换成另一个词,cipher是把每个字母换成另一个字母
|
|
96
|
+
- 5个例句:
|
|
97
|
+
1. This text looks like a cipher.
|
|
98
|
+
2. She wrote the message in cipher.
|
|
99
|
+
3. He tried to solve the cipher.
|
|
100
|
+
4. The cipher was very hard to break.
|
|
101
|
+
5. Can you read this cipher?
|
|
102
|
+
|
|
103
|
+
### 12. double agent
|
|
104
|
+
- 词性:名词短语
|
|
105
|
+
- 含义:双面间谍
|
|
106
|
+
- 例句:He is a double agent, working for both sides.
|
|
107
|
+
(他是双面间谍,同时为两边工作。)
|
|
108
|
+
|
|
109
|
+
### 13. coming of age
|
|
110
|
+
- 词性:短语/习语
|
|
111
|
+
- 含义:长大成人、成年
|
|
112
|
+
- 例句:The movie is about a boy's coming of age.
|
|
113
|
+
(这部电影是关于一个男孩的成长故事。)
|
|
114
|
+
- 说明:coming of age = 来到成年,最早是法律术语,后延伸指心理成熟
|
|
115
|
+
- 5个例句:
|
|
116
|
+
1. His coming of age was very difficult.
|
|
117
|
+
2. The book is about coming of age.
|
|
118
|
+
3. She had a coming of age experience.
|
|
119
|
+
4. Coming of age is an important time in life.
|
|
120
|
+
5. This book is a story about a young man's coming of age in a small town.
|
|
121
|
+
|
|
122
|
+
### 14. adolescence [ˌædəˈlesns]
|
|
123
|
+
- 词性:名词
|
|
124
|
+
- 含义:青春期
|
|
125
|
+
- 例句:Many changes happen during adolescence.
|
|
126
|
+
(青春期会发生很多变化。)
|
|
127
|
+
- 5个例句:
|
|
128
|
+
1. He spent his adolescence in Paris.
|
|
129
|
+
2. Adolescence is a time of big changes.
|
|
130
|
+
3. Many teenagers feel confused during adolescence.
|
|
131
|
+
4. She wrote a diary during her adolescence.
|
|
132
|
+
5. Adolescence usually starts around age 12.
|
|
133
|
+
|
|
134
|
+
### 15. identity [aɪˈdentəti]
|
|
135
|
+
- 词性:名词
|
|
136
|
+
- 含义:身份
|
|
137
|
+
- 例句:He hid his true identity.(他隐藏了自己的真实身份。)
|
|
138
|
+
- 注意:identity和Identity是同一个词,只是大小写不同(首字母大写只是因为出现在句首)
|
|
139
|
+
|
|
140
|
+
### 16. independence [ˌɪndɪˈpendəns]
|
|
141
|
+
- 词性:名词
|
|
142
|
+
- 含义:独立、自立
|
|
143
|
+
- 例句:The country got its independence in 1949.
|
|
144
|
+
(这个国家在1949年获得了独立。)
|
|
145
|
+
- 记忆技巧:in(不)+ depend(依赖)+ ence = 不依赖别人 = 独立
|
|
146
|
+
|
|
147
|
+
### 17. peer pressure
|
|
148
|
+
- 词性:名词短语
|
|
149
|
+
- 含义:同伴压力
|
|
150
|
+
- 例句:He started smoking because of peer pressure.
|
|
151
|
+
(他因为同伴压力开始抽烟。)
|
|
152
|
+
- 记忆技巧:peer(同龄人)+ pressure(压力)= 来自同龄人的压力
|
|
153
|
+
- 5个例句:
|
|
154
|
+
1. She didn't want to cheat, but peer pressure was too strong.
|
|
155
|
+
2. Peer pressure can make you do bad things.
|
|
156
|
+
3. He resisted peer pressure and said no.
|
|
157
|
+
4. Teens often face peer pressure at school.
|
|
158
|
+
5. Good friends won't give you bad peer pressure.
|
|
159
|
+
|
|
160
|
+
### 18. belonging [bɪˈlɒŋɪŋ]
|
|
161
|
+
- 词性:名词
|
|
162
|
+
- 含义:归属感、归属
|
|
163
|
+
- 例句:She felt a sense of belonging in her new school.
|
|
164
|
+
(她在新学校找到了归属感。)
|
|
165
|
+
|
|
166
|
+
### 19. self-discovery
|
|
167
|
+
- 词性:名词
|
|
168
|
+
- 含义:自我发现、认识自我
|
|
169
|
+
- 例句:Her trip to Tibet was a journey of self-discovery.
|
|
170
|
+
(她去西藏的旅行是一次自我发现的旅程。)
|
|
171
|
+
- 记忆技巧:self(自己)+ discovery(发现)= 发现你自己
|
|
172
|
+
|
|
173
|
+
### 20. relationships
|
|
174
|
+
- 词性:名词
|
|
175
|
+
- 含义:人际关系、关系
|
|
176
|
+
- 例句:Teenagers often have problems with peer relationships.
|
|
177
|
+
(青少年经常在人际关系方面有问题。)
|
|
178
|
+
|
|
179
|
+
### 21. internal conflict
|
|
180
|
+
- 词性:名词短语
|
|
181
|
+
- 含义:内心矛盾、内心冲突
|
|
182
|
+
- 例句:He had an internal conflict about telling the truth.
|
|
183
|
+
(他内心很矛盾,不知道该不该说实话。)
|
|
184
|
+
- 记忆技巧:internal(内心的)+ conflict(冲突)= 内心冲突
|
|
185
|
+
|
|
186
|
+
### 22. personal growth
|
|
187
|
+
- 词性:名词短语
|
|
188
|
+
- 含义:个人成长
|
|
189
|
+
- 例句:Reading books helps with personal growth.
|
|
190
|
+
(阅读有助于个人成长。)
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 故事串联
|
|
195
|
+
所有间谍主题词汇串联:
|
|
196
|
+
|
|
197
|
+
**The Mission(任务)**
|
|
198
|
+
|
|
199
|
+
A secret **agent** got a **mission brief** on his computer.
|
|
200
|
+
|
|
201
|
+
The **brief** said: go **undercover** and do some **espionage**.
|
|
202
|
+
|
|
203
|
+
But the bad guys had the whole building under **surveillance**!
|
|
204
|
+
|
|
205
|
+
He used a cool **gadget** to get inside...
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 初中生相关词汇整理
|
|
210
|
+
|
|
211
|
+
### 青春期主题词汇:
|
|
212
|
+
- adolescence 青春期
|
|
213
|
+
- coming of age 长大成人
|
|
214
|
+
- identity 身份
|
|
215
|
+
- independence 独立
|
|
216
|
+
- peer pressure 同伴压力
|
|
217
|
+
- belonging 归属感
|
|
218
|
+
- self-discovery 自我发现
|
|
219
|
+
- relationships 人际关系
|
|
220
|
+
- internal conflict 内心矛盾
|
|
221
|
+
- personal growth 个人成长
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
备注:学习者是初中生,英语水平一般。采用联想记忆、谐音记忆、词源解释等多种方法帮助记忆。
|
package/build-manifest.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* build-manifest.js - 自动构建 patch-manifest.json
|
|
6
6
|
* ============================================================================
|
|
7
7
|
*
|
|
8
|
-
* 扫描 agent-list/
|
|
8
|
+
* 扫描 agent-list/ 和 skills/ 目录,自动生成统一注入清单。
|
|
9
9
|
* 已有的 strategy 设置会保留(不会被覆盖)。
|
|
10
10
|
*
|
|
11
11
|
* 在 publish.sh 中自动调用,无需手动维护 manifest。
|
|
@@ -17,8 +17,9 @@ const path = require('path');
|
|
|
17
17
|
|
|
18
18
|
const MANIFEST_PATH = path.join(__dirname, 'patch-manifest.json');
|
|
19
19
|
const AGENT_LIST_DIR = path.join(__dirname, 'agent-list');
|
|
20
|
+
const SKILLS_DIR = path.join(__dirname, 'skills');
|
|
20
21
|
|
|
21
|
-
// 默认 config patches
|
|
22
|
+
// 默认 config patches(硬编码,不从目录扫描)
|
|
22
23
|
const DEFAULT_CONFIG = {
|
|
23
24
|
strategy: 'overwrite',
|
|
24
25
|
patches: {
|
|
@@ -30,27 +31,24 @@ const DEFAULT_CONFIG = {
|
|
|
30
31
|
|
|
31
32
|
function buildManifest() {
|
|
32
33
|
// 读取已有 manifest(保留手动设置的 strategy)
|
|
33
|
-
let existing = { agents: [], config: DEFAULT_CONFIG };
|
|
34
|
+
let existing = { agents: [], skills: [], config: DEFAULT_CONFIG };
|
|
34
35
|
if (fs.existsSync(MANIFEST_PATH)) {
|
|
35
36
|
try {
|
|
36
37
|
existing = JSON.parse(fs.readFileSync(MANIFEST_PATH, 'utf8'));
|
|
37
38
|
} catch {}
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
//
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
for (const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (a.id && a.description) {
|
|
48
|
-
existingStrategies[a.id + '_desc'] = a.description;
|
|
49
|
-
}
|
|
41
|
+
// 建立已有策略映射(保留手动覆盖)
|
|
42
|
+
const saved = {};
|
|
43
|
+
for (const list of [existing.agents || [], existing.skills || []]) {
|
|
44
|
+
for (const item of list) {
|
|
45
|
+
const key = item.id || item.name;
|
|
46
|
+
if (key && item.strategy) saved[key] = item.strategy;
|
|
47
|
+
if (key && item.description) saved[key + '_desc'] = item.description;
|
|
50
48
|
}
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
// 扫描 agent-list/
|
|
51
|
+
// === 1. 扫描 agent-list/ ===
|
|
54
52
|
const agents = [];
|
|
55
53
|
if (fs.existsSync(AGENT_LIST_DIR)) {
|
|
56
54
|
const dirs = fs.readdirSync(AGENT_LIST_DIR, { withFileTypes: true })
|
|
@@ -62,19 +60,40 @@ function buildManifest() {
|
|
|
62
60
|
agents.push({
|
|
63
61
|
id: agentId,
|
|
64
62
|
workspace: d.name,
|
|
65
|
-
strategy:
|
|
66
|
-
description:
|
|
63
|
+
strategy: saved[agentId] || 'auto',
|
|
64
|
+
description: saved[agentId + '_desc'] || agentId,
|
|
67
65
|
});
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
//
|
|
69
|
+
// === 2. 扫描 skills/ ===
|
|
70
|
+
const skills = [];
|
|
71
|
+
if (fs.existsSync(SKILLS_DIR)) {
|
|
72
|
+
const dirs = fs.readdirSync(SKILLS_DIR, { withFileTypes: true })
|
|
73
|
+
.filter(d => d.isDirectory())
|
|
74
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
75
|
+
|
|
76
|
+
for (const d of dirs) {
|
|
77
|
+
// 必须有 SKILL.md 才是合法 skill
|
|
78
|
+
const skillMd = path.join(SKILLS_DIR, d.name, 'SKILL.md');
|
|
79
|
+
if (!fs.existsSync(skillMd)) continue;
|
|
80
|
+
|
|
81
|
+
skills.push({
|
|
82
|
+
name: d.name,
|
|
83
|
+
strategy: saved[d.name] || 'auto',
|
|
84
|
+
description: saved[d.name + '_desc'] || d.name,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// === 3. 保留 config ===
|
|
72
90
|
const config = existing.config || DEFAULT_CONFIG;
|
|
73
91
|
|
|
74
92
|
const manifest = {
|
|
75
|
-
_doc: 'MyClaw 注入清单 (auto-generated
|
|
93
|
+
_doc: 'MyClaw 注入清单 (auto-generated)。strategy: auto | overwrite | off',
|
|
76
94
|
_generated: new Date().toISOString(),
|
|
77
95
|
agents,
|
|
96
|
+
skills,
|
|
78
97
|
config,
|
|
79
98
|
};
|
|
80
99
|
|
|
@@ -83,9 +102,13 @@ function buildManifest() {
|
|
|
83
102
|
console.log('📋 patch-manifest.json 已生成');
|
|
84
103
|
console.log(' 智能体: ' + agents.length + ' 个');
|
|
85
104
|
for (const a of agents) {
|
|
86
|
-
console.log('
|
|
105
|
+
console.log(' • ' + a.id + ' [' + a.strategy + ']');
|
|
106
|
+
}
|
|
107
|
+
console.log(' 技能: ' + skills.length + ' 个');
|
|
108
|
+
for (const s of skills) {
|
|
109
|
+
console.log(' • ' + s.name + ' [' + s.strategy + ']');
|
|
87
110
|
}
|
|
88
|
-
console.log('
|
|
111
|
+
console.log(' 配置: ' + Object.keys(config.patches || {}).length + ' 项 [' + (config.strategy || 'overwrite') + ']');
|
|
89
112
|
}
|
|
90
113
|
|
|
91
114
|
buildManifest();
|
package/index.js
CHANGED
|
@@ -545,7 +545,7 @@ function runPatch() {
|
|
|
545
545
|
const manifest = loadManifest();
|
|
546
546
|
if (manifest && manifest.config && manifest.config.patches) {
|
|
547
547
|
const configStrategy = manifest.config.strategy || 'overwrite';
|
|
548
|
-
if (configStrategy !== '
|
|
548
|
+
if (configStrategy !== 'off') {
|
|
549
549
|
// 将 dot-notation patch 展开为嵌套对象
|
|
550
550
|
const patches = manifest.config.patches;
|
|
551
551
|
const nested = {};
|
|
@@ -724,6 +724,102 @@ function runUpdate() {
|
|
|
724
724
|
console.log('');
|
|
725
725
|
}
|
|
726
726
|
|
|
727
|
+
// ============================================================================
|
|
728
|
+
// 资源管理列表
|
|
729
|
+
// ============================================================================
|
|
730
|
+
|
|
731
|
+
function runList() {
|
|
732
|
+
const fs = require('fs');
|
|
733
|
+
const path = require('path');
|
|
734
|
+
const os = require('os');
|
|
735
|
+
const { loadManifest } = require('./patch-agent');
|
|
736
|
+
const bar = '----------------------------------------';
|
|
737
|
+
|
|
738
|
+
console.log('');
|
|
739
|
+
console.log('[' + colors.blue + 'MyClaw' + colors.nc + '] ' + colors.blue + '注入资源管理' + colors.nc);
|
|
740
|
+
console.log(bar);
|
|
741
|
+
|
|
742
|
+
const manifest = loadManifest();
|
|
743
|
+
if (!manifest) {
|
|
744
|
+
console.log('');
|
|
745
|
+
console.log('[' + colors.yellow + '提示' + colors.nc + '] patch-manifest.json 不存在');
|
|
746
|
+
console.log(' 运行 ' + colors.yellow + 'myclaw patch' + colors.nc + ' 将自动生成');
|
|
747
|
+
console.log('');
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const openclawDir = path.join(os.homedir(), '.openclaw');
|
|
752
|
+
const configPath = path.join(openclawDir, 'openclaw.json');
|
|
753
|
+
let registeredIds = new Set();
|
|
754
|
+
try {
|
|
755
|
+
const cfg = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
756
|
+
if (cfg.agents && Array.isArray(cfg.agents.list)) {
|
|
757
|
+
for (const a of cfg.agents.list) {
|
|
758
|
+
if (a && a.id) registeredIds.add(a.id);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
} catch {}
|
|
762
|
+
|
|
763
|
+
// === Agents ===
|
|
764
|
+
console.log('');
|
|
765
|
+
console.log(' ' + colors.blue + '🤖 智能体 (Agents)' + colors.nc);
|
|
766
|
+
if (manifest.agents && manifest.agents.length > 0) {
|
|
767
|
+
for (const a of manifest.agents) {
|
|
768
|
+
const wsPath = path.join(openclawDir, a.workspace || ('workspace-' + a.id));
|
|
769
|
+
const wsExists = fs.existsSync(wsPath);
|
|
770
|
+
const registered = registeredIds.has(a.id);
|
|
771
|
+
const status = wsExists && registered ? colors.green + '✔ 已安装' + colors.nc
|
|
772
|
+
: wsExists ? colors.yellow + '⚠ 文件存在未注册' + colors.nc
|
|
773
|
+
: colors.red + '✗ 未安装' + colors.nc;
|
|
774
|
+
const strat = a.strategy === 'off' ? colors.red + a.strategy + colors.nc : a.strategy;
|
|
775
|
+
console.log(' ' + padRight(a.id, 20) + status + ' [' + strat + ']');
|
|
776
|
+
}
|
|
777
|
+
} else {
|
|
778
|
+
console.log(' (无)');
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// === Skills ===
|
|
782
|
+
console.log('');
|
|
783
|
+
console.log(' ' + colors.blue + '🧩 技能 (Skills)' + colors.nc);
|
|
784
|
+
if (manifest.skills && manifest.skills.length > 0) {
|
|
785
|
+
const skillsDir = path.join(openclawDir, 'skills');
|
|
786
|
+
for (const s of manifest.skills) {
|
|
787
|
+
const installed = fs.existsSync(path.join(skillsDir, s.name));
|
|
788
|
+
const status = installed ? colors.green + '✔ 已安装' + colors.nc : colors.red + '✗ 未安装' + colors.nc;
|
|
789
|
+
const strat = s.strategy === 'off' ? colors.red + s.strategy + colors.nc : s.strategy;
|
|
790
|
+
console.log(' ' + padRight(s.name, 20) + status + ' [' + strat + ']');
|
|
791
|
+
}
|
|
792
|
+
} else {
|
|
793
|
+
console.log(' (无)');
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// === Config ===
|
|
797
|
+
console.log('');
|
|
798
|
+
console.log(' ' + colors.blue + '⚙️ 配置 (Config Patches)' + colors.nc);
|
|
799
|
+
if (manifest.config && manifest.config.patches) {
|
|
800
|
+
const strat = manifest.config.strategy || 'overwrite';
|
|
801
|
+
const stratDisplay = strat === 'off' ? colors.red + strat + colors.nc : strat;
|
|
802
|
+
console.log(' 策略: [' + stratDisplay + ']');
|
|
803
|
+
for (const [key, value] of Object.entries(manifest.config.patches)) {
|
|
804
|
+
console.log(' ' + padRight(key, 30) + '→ ' + JSON.stringify(value));
|
|
805
|
+
}
|
|
806
|
+
} else {
|
|
807
|
+
console.log(' (无)');
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
console.log('');
|
|
811
|
+
console.log(bar);
|
|
812
|
+
console.log('策略说明: ' + colors.green + 'auto' + colors.nc + '=不存在才注入 '
|
|
813
|
+
+ colors.yellow + 'overwrite' + colors.nc + '=覆盖 '
|
|
814
|
+
+ colors.red + 'off' + colors.nc + '=关闭');
|
|
815
|
+
console.log('');
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
function padRight(str, len) {
|
|
819
|
+
if (str.length >= len) return str + ' ';
|
|
820
|
+
return str + ' '.repeat(len - str.length);
|
|
821
|
+
}
|
|
822
|
+
|
|
727
823
|
// ============================================================================
|
|
728
824
|
// 帮助信息
|
|
729
825
|
// ============================================================================
|
|
@@ -751,7 +847,9 @@ function showHelp() {
|
|
|
751
847
|
console.log(' open 打开浏览器控制台(自动带 token)');
|
|
752
848
|
console.log(' wsl2 WSL2 一键安装/修复 (仅限 Windows)');
|
|
753
849
|
console.log(' bat 在桌面生成一键启动脚本 (仅限 Windows)');
|
|
754
|
-
console.log('
|
|
850
|
+
console.log(' list 查看注入资源管理列表(智能体/技能/配置)');
|
|
851
|
+
console.log(' pull 从 ~/.openclaw 拉取最新资源到源目录(开发用)');
|
|
852
|
+
console.log(' patch 注入 MyClaw UI + 技能 + 智能体 + 配置');
|
|
755
853
|
console.log(' unpatch 回滚 UI 注入(恢复原版)');
|
|
756
854
|
console.log(' minimax 注入 MiniMax 模型配置 (可选: --key sk-xxx)');
|
|
757
855
|
console.log(' restart 重启 OpenClaw Gateway');
|
|
@@ -810,6 +908,11 @@ if (!command || command === 'help' || command === '--help' || command === '-h')
|
|
|
810
908
|
runLaunch();
|
|
811
909
|
} else if (command === 'bat') {
|
|
812
910
|
runBat();
|
|
911
|
+
} else if (command === 'list') {
|
|
912
|
+
runList();
|
|
913
|
+
} else if (command === 'pull') {
|
|
914
|
+
const pull = require('./pull');
|
|
915
|
+
pull.run();
|
|
813
916
|
} else if (command === 'patch') {
|
|
814
917
|
runPatch();
|
|
815
918
|
} else if (command === 'unpatch') {
|
package/package.json
CHANGED
package/patch-agent.js
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* 功能:
|
|
7
7
|
* 1. 读取 patch-manifest.json 中的 agents 列表
|
|
8
8
|
* 2. 根据 strategy 决定行为:
|
|
9
|
-
* -
|
|
9
|
+
* - auto: 目标 workspace 不存在时才注入(默认)
|
|
10
10
|
* - overwrite: 始终覆盖更新 workspace 文件
|
|
11
|
-
* -
|
|
11
|
+
* - off: 跳过,不注入
|
|
12
12
|
* 3. 将 workspace 复制到 ~/.openclaw/ 下
|
|
13
13
|
* 4. 在 openclaw.json 的 agents.list 中注册
|
|
14
14
|
* 5. 创建 agent 目录结构
|
|
@@ -110,12 +110,12 @@ function patchAgents() {
|
|
|
110
110
|
for (const entry of manifest.agents) {
|
|
111
111
|
const agentId = entry.id;
|
|
112
112
|
const workspaceName = entry.workspace || ('workspace-' + agentId);
|
|
113
|
-
const strategy = entry.strategy || '
|
|
113
|
+
const strategy = entry.strategy || 'auto';
|
|
114
114
|
const desc = entry.description || agentId;
|
|
115
115
|
|
|
116
|
-
//
|
|
117
|
-
if (strategy === '
|
|
118
|
-
console.log('[myclaw-agent] ⏭️ 跳过: ' + agentId + ' (' + desc + ') [
|
|
116
|
+
// off → 跳过
|
|
117
|
+
if (strategy === 'off') {
|
|
118
|
+
console.log('[myclaw-agent] ⏭️ 跳过: ' + agentId + ' (' + desc + ') [off]');
|
|
119
119
|
skipped++;
|
|
120
120
|
continue;
|
|
121
121
|
}
|
|
@@ -133,9 +133,9 @@ function patchAgents() {
|
|
|
133
133
|
|
|
134
134
|
const alreadyExists = fs.existsSync(destWorkspace);
|
|
135
135
|
|
|
136
|
-
//
|
|
137
|
-
if (strategy === '
|
|
138
|
-
console.log('[myclaw-agent] ✔️ 已存在: ' + agentId + ' (' + desc + ') [
|
|
136
|
+
// auto → 已存在则跳过
|
|
137
|
+
if (strategy === 'auto' && alreadyExists) {
|
|
138
|
+
console.log('[myclaw-agent] ✔️ 已存在: ' + agentId + ' (' + desc + ') [auto, 跳过]');
|
|
139
139
|
skipped++;
|
|
140
140
|
continue;
|
|
141
141
|
}
|
package/patch-manifest.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_doc": "MyClaw 注入清单 (auto-generated
|
|
3
|
-
"_generated": "2026-04-
|
|
2
|
+
"_doc": "MyClaw 注入清单 (auto-generated)。strategy: auto | overwrite | off",
|
|
3
|
+
"_generated": "2026-04-01T12:06:06.605Z",
|
|
4
4
|
"agents": [
|
|
5
5
|
{
|
|
6
6
|
"id": "danci",
|
|
7
7
|
"workspace": "workspace-danci",
|
|
8
|
-
"strategy": "
|
|
9
|
-
"description": "
|
|
8
|
+
"strategy": "auto",
|
|
9
|
+
"description": "danci"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"skills": [
|
|
13
|
+
{
|
|
14
|
+
"name": "minimax-inject",
|
|
15
|
+
"strategy": "auto",
|
|
16
|
+
"description": "minimax-inject"
|
|
10
17
|
}
|
|
11
18
|
],
|
|
12
19
|
"config": {
|
package/pull.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* MyClaw Pull - 从 ~/.openclaw/ 拉取最新资源到 myclaw 源目录
|
|
4
|
+
* ============================================================================
|
|
5
|
+
*
|
|
6
|
+
* 反向同步:将线上运行环境中的智能体、技能拷贝回 myclaw 包内,
|
|
7
|
+
* 确保下次 publish 时打包的是最新版本。
|
|
8
|
+
*
|
|
9
|
+
* 拉取范围:
|
|
10
|
+
* 1. manifest 中已有的 agents → 从 ~/.openclaw/workspace-* 回拷到 agent-list/
|
|
11
|
+
* 2. manifest 中已有的 skills → 从 ~/.openclaw/skills/* 回拷到 skills/
|
|
12
|
+
* 3. 如果发现 ~/.openclaw/ 中有新的 workspace-* 不在 manifest 中,提示是否纳入
|
|
13
|
+
*
|
|
14
|
+
* ============================================================================
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const os = require('os');
|
|
20
|
+
|
|
21
|
+
const OPENCLAW_DIR = path.join(os.homedir(), '.openclaw');
|
|
22
|
+
const AGENT_LIST_DIR = path.join(__dirname, 'agent-list');
|
|
23
|
+
const SKILLS_DIR = path.join(__dirname, 'skills');
|
|
24
|
+
const MANIFEST_PATH = path.join(__dirname, 'patch-manifest.json');
|
|
25
|
+
|
|
26
|
+
// 不应拉取的 workspace(排除列表)
|
|
27
|
+
const WORKSPACE_IGNORE = new Set([
|
|
28
|
+
'workspace', // 默认 workspace(非 agent)
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 递归复制目录(幂等覆盖)
|
|
33
|
+
* 跳过 .openclaw/ 和 node_modules/ 等运行时目录
|
|
34
|
+
*/
|
|
35
|
+
function copyDirSync(src, dest, skipDirs = ['.openclaw', 'node_modules', '.git']) {
|
|
36
|
+
if (!fs.existsSync(dest)) {
|
|
37
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
if (skipDirs.includes(entry.name)) continue;
|
|
43
|
+
|
|
44
|
+
const srcPath = path.join(src, entry.name);
|
|
45
|
+
const destPath = path.join(dest, entry.name);
|
|
46
|
+
|
|
47
|
+
if (entry.isDirectory()) {
|
|
48
|
+
copyDirSync(srcPath, destPath, skipDirs);
|
|
49
|
+
} else {
|
|
50
|
+
fs.copyFileSync(srcPath, destPath);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 统计目录内文件数量
|
|
57
|
+
*/
|
|
58
|
+
function countFiles(dir) {
|
|
59
|
+
if (!fs.existsSync(dir)) return 0;
|
|
60
|
+
let count = 0;
|
|
61
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
62
|
+
for (const e of entries) {
|
|
63
|
+
if (e.isDirectory()) {
|
|
64
|
+
count += countFiles(path.join(dir, e.name));
|
|
65
|
+
} else {
|
|
66
|
+
count++;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return count;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 加载 manifest
|
|
74
|
+
*/
|
|
75
|
+
function loadManifest() {
|
|
76
|
+
if (!fs.existsSync(MANIFEST_PATH)) return null;
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(fs.readFileSync(MANIFEST_PATH, 'utf8'));
|
|
79
|
+
} catch { return null; }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 扫描 ~/.openclaw/ 下所有 workspace-* 目录
|
|
84
|
+
*/
|
|
85
|
+
function scanLiveWorkspaces() {
|
|
86
|
+
if (!fs.existsSync(OPENCLAW_DIR)) return [];
|
|
87
|
+
return fs.readdirSync(OPENCLAW_DIR, { withFileTypes: true })
|
|
88
|
+
.filter(d => d.isDirectory() && d.name.startsWith('workspace-') && !WORKSPACE_IGNORE.has(d.name))
|
|
89
|
+
.map(d => ({
|
|
90
|
+
dirName: d.name,
|
|
91
|
+
id: d.name.replace(/^workspace-/, ''),
|
|
92
|
+
fullPath: path.join(OPENCLAW_DIR, d.name),
|
|
93
|
+
}))
|
|
94
|
+
.filter(ws => !AGENT_LIST_DIR.startsWith(ws.fullPath)); // 避免无限递归(比如拉取源码所在的 workspace)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 扫描 ~/.openclaw/skills/ 下所有技能目录
|
|
99
|
+
*/
|
|
100
|
+
function scanLiveSkills() {
|
|
101
|
+
const skillsDir = path.join(OPENCLAW_DIR, 'skills');
|
|
102
|
+
if (!fs.existsSync(skillsDir)) return [];
|
|
103
|
+
return fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
104
|
+
.filter(d => d.isDirectory())
|
|
105
|
+
.map(d => ({
|
|
106
|
+
name: d.name,
|
|
107
|
+
fullPath: path.join(skillsDir, d.name),
|
|
108
|
+
hasSkillMd: fs.existsSync(path.join(skillsDir, d.name, 'SKILL.md')),
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 执行拉取
|
|
114
|
+
*/
|
|
115
|
+
function run() {
|
|
116
|
+
const bar = '----------------------------------------';
|
|
117
|
+
|
|
118
|
+
console.log('');
|
|
119
|
+
console.log('[\x1b[34mMyClaw\x1b[0m] \x1b[34mPull - 拉取最新资源\x1b[0m');
|
|
120
|
+
console.log(bar);
|
|
121
|
+
console.log('');
|
|
122
|
+
|
|
123
|
+
if (!fs.existsSync(OPENCLAW_DIR)) {
|
|
124
|
+
console.log('[\x1b[31m错误\x1b[0m] ~/.openclaw 目录不存在');
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 确保目标目录存在
|
|
129
|
+
if (!fs.existsSync(AGENT_LIST_DIR)) {
|
|
130
|
+
fs.mkdirSync(AGENT_LIST_DIR, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const manifest = loadManifest();
|
|
134
|
+
const manifestAgentIds = new Set();
|
|
135
|
+
const manifestSkillNames = new Set();
|
|
136
|
+
|
|
137
|
+
if (manifest) {
|
|
138
|
+
if (manifest.agents) manifest.agents.forEach(a => manifestAgentIds.add(a.id));
|
|
139
|
+
if (manifest.skills) manifest.skills.forEach(s => manifestSkillNames.add(s.name));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// === 1. 拉取智能体 ===
|
|
143
|
+
console.log('\x1b[34m🤖 智能体 (Agents)\x1b[0m');
|
|
144
|
+
|
|
145
|
+
const liveWorkspaces = scanLiveWorkspaces();
|
|
146
|
+
let agentPulled = 0;
|
|
147
|
+
for (const ws of liveWorkspaces) {
|
|
148
|
+
const destDir = path.join(AGENT_LIST_DIR, ws.dirName);
|
|
149
|
+
const inManifest = manifestAgentIds.has(ws.id);
|
|
150
|
+
|
|
151
|
+
if (inManifest) {
|
|
152
|
+
const fileCount = countFiles(ws.fullPath);
|
|
153
|
+
copyDirSync(ws.fullPath, destDir);
|
|
154
|
+
console.log(' 🔄 已同步: ' + ws.id + ' (' + fileCount + ' 文件)');
|
|
155
|
+
agentPulled++;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (agentPulled === 0) {
|
|
160
|
+
console.log(' (没有需要同步的智能体)');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// === 2. 拉取技能 ===
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log('\x1b[34m🧩 技能 (Skills)\x1b[0m');
|
|
166
|
+
|
|
167
|
+
const liveSkills = scanLiveSkills();
|
|
168
|
+
let skillPulled = 0;
|
|
169
|
+
|
|
170
|
+
for (const sk of liveSkills) {
|
|
171
|
+
const inManifest = manifestSkillNames.has(sk.name);
|
|
172
|
+
|
|
173
|
+
if (inManifest) {
|
|
174
|
+
if (!sk.hasSkillMd) {
|
|
175
|
+
console.log(' ⚠️ 跳过无 SKILL.md 的技能: ' + sk.name);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const destDir = path.join(SKILLS_DIR, sk.name);
|
|
179
|
+
const fileCount = countFiles(sk.fullPath);
|
|
180
|
+
copyDirSync(sk.fullPath, destDir);
|
|
181
|
+
console.log(' 🔄 已同步: ' + sk.name + ' (' + fileCount + ' 文件)');
|
|
182
|
+
skillPulled++;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (skillPulled === 0) {
|
|
187
|
+
console.log(' (没有需要同步的技能)');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// === 汇总 ===
|
|
191
|
+
console.log('');
|
|
192
|
+
console.log(bar);
|
|
193
|
+
console.log('✅ Pull 完毕: 同步了 ' + agentPulled + ' 个智能体, ' + skillPulled + ' 个技能');
|
|
194
|
+
console.log('');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
module.exports = { run };
|