@rookiestar/eng-lang-tutor 1.0.0
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.
Potentially problematic release.
This version of @rookiestar/eng-lang-tutor might be problematic. Click here for more details.
- package/CLAUDE.md +259 -0
- package/README.md +224 -0
- package/README_EN.md +224 -0
- package/SKILL.md +495 -0
- package/bin/eng-lang-tutor.js +177 -0
- package/docs/OPENCLAW_DEPLOYMENT.md +228 -0
- package/examples/sample_keypoint.json +130 -0
- package/examples/sample_quiz.json +92 -0
- package/npm-scripts/install.js +132 -0
- package/package.json +46 -0
- package/references/resources.md +292 -0
- package/requirements.txt +9 -0
- package/scripts/command_parser.py +336 -0
- package/scripts/cron_push.py +226 -0
- package/scripts/dedup.py +325 -0
- package/scripts/gamification.py +406 -0
- package/scripts/scorer.py +323 -0
- package/scripts/state_manager.py +1025 -0
- package/scripts/tts/__init__.py +30 -0
- package/scripts/tts/base.py +109 -0
- package/scripts/tts/manager.py +290 -0
- package/scripts/tts/providers/__init__.py +10 -0
- package/scripts/tts/providers/xunfei.py +192 -0
- package/templates/keypoint_schema.json +420 -0
- package/templates/prompt_templates.md +1261 -0
- package/templates/quiz_schema.json +201 -0
- package/templates/state_schema.json +241 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# OpenClaw 部署指南
|
|
2
|
+
|
|
3
|
+
本文档说明如何将 `eng-lang-tutor` skill 部署到 OpenClaw 服务器,并通过 Discord 等渠道使用。
|
|
4
|
+
|
|
5
|
+
## 1. 前置条件
|
|
6
|
+
|
|
7
|
+
- 一台已安装 OpenClaw 的服务器
|
|
8
|
+
- OpenClaw Gateway 正在运行
|
|
9
|
+
- 已配置好 Discord Bot(可选其他渠道)
|
|
10
|
+
|
|
11
|
+
## 2. 部署步骤
|
|
12
|
+
|
|
13
|
+
### 2.1 上传 Skill 到服务器
|
|
14
|
+
|
|
15
|
+
**方式 A:使用 SCP 上传**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 在本地机器上执行
|
|
19
|
+
scp -r /path/to/eng-lang-tutor user@your-server:~/.openclaw/skills/
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**方式 B:使用 Git Clone**
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# 在服务器上执行
|
|
26
|
+
cd ~/.openclaw/skills/
|
|
27
|
+
git clone https://github.com/rookiestar/eng-lang-tutor.git
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2.2 确认目录结构
|
|
31
|
+
|
|
32
|
+
确保目录结构如下:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
~/.openclaw/skills/eng-lang-tutor/
|
|
36
|
+
├── SKILL.md # 核心技能文件(必需)
|
|
37
|
+
├── scripts/ # Python 脚本
|
|
38
|
+
│ ├── state_manager.py
|
|
39
|
+
│ ├── scorer.py
|
|
40
|
+
│ ├── gamification.py
|
|
41
|
+
│ └── dedup.py
|
|
42
|
+
├── templates/ # JSON Schema
|
|
43
|
+
├── references/ # 参考资源
|
|
44
|
+
├── examples/ # 示例文件
|
|
45
|
+
└── data/ # 运行时数据
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2.3 验证 Skill 加载
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# 查看已加载的 skills
|
|
52
|
+
openclaw skills list
|
|
53
|
+
|
|
54
|
+
# 查看特定 skill 详情
|
|
55
|
+
openclaw skills info eng-lang-tutor
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 3. 配置 Discord 渠道
|
|
59
|
+
|
|
60
|
+
### 3.1 创建 Discord Bot
|
|
61
|
+
|
|
62
|
+
1. 访问 [Discord Developer Portal](https://discord.com/developers/applications)
|
|
63
|
+
2. 创建新应用,命名为你的 Bot
|
|
64
|
+
3. 进入 Bot 页面,创建 Bot 并获取 Token
|
|
65
|
+
4. 启用 Message Content Intent
|
|
66
|
+
|
|
67
|
+
### 3.2 配置 OpenClaw
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# 设置 Discord Token
|
|
71
|
+
openclaw config set discord.token YOUR_BOT_TOKEN
|
|
72
|
+
|
|
73
|
+
# 设置服务器 ID(可选)
|
|
74
|
+
openclaw config set discord.guildId YOUR_SERVER_ID
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3.3 邀请 Bot 到服务器
|
|
78
|
+
|
|
79
|
+
1. 在 Discord Developer Portal 中,进入 OAuth2 > URL Generator
|
|
80
|
+
2. 选择 `bot` 和 `applications.commands` scope
|
|
81
|
+
3. 选择所需权限(Send Messages, Read Messages 等)
|
|
82
|
+
4. 复制生成的邀请链接并在浏览器中打开
|
|
83
|
+
5. 选择要添加 Bot 的服务器
|
|
84
|
+
|
|
85
|
+
### 3.4 完成配对
|
|
86
|
+
|
|
87
|
+
首次与 Bot 对话时,会收到配对码:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# 在服务器上执行配对
|
|
91
|
+
openclaw pairing approve discord YOUR_PAIRING_CODE
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 4. 使用 Skill
|
|
95
|
+
|
|
96
|
+
### 4.1 通过 Discord 使用
|
|
97
|
+
|
|
98
|
+
在 Discord 中与 Bot 对话,触发英语学习功能:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
# 触发今日知识点
|
|
102
|
+
今天有什么英语知识点?
|
|
103
|
+
|
|
104
|
+
# 触发 Quiz
|
|
105
|
+
给我出个 Quiz
|
|
106
|
+
|
|
107
|
+
# 查看学习进度
|
|
108
|
+
我的学习进度怎么样?
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 4.2 设置定时推送(cron)
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# 编辑 crontab
|
|
115
|
+
crontab -e
|
|
116
|
+
|
|
117
|
+
# 添加每日定时推送(例如每天早上 9 点)
|
|
118
|
+
0 9 * * * openclaw agent --channel discord --message "每日英语学习时间到!今天的知识点是:" --agent eng-lang-tutor
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 5. 进阶配置
|
|
122
|
+
|
|
123
|
+
### 5.1 配置用户偏好
|
|
124
|
+
|
|
125
|
+
在 Discord 中与 Bot 对话设置:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
设置我的 CEFR 等级为 B2
|
|
129
|
+
我的导师风格设为严谨
|
|
130
|
+
调整主题配比,增加职场内容的比例
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 5.2 配置环境变量
|
|
134
|
+
|
|
135
|
+
在服务器上设置 API 密钥(如果使用外部 LLM):
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# 编辑 OpenClaw 配置
|
|
139
|
+
openclaw config set model.provider anthropic
|
|
140
|
+
openclaw config set model.api_key YOUR_API_KEY
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 5.3 数据持久化
|
|
144
|
+
|
|
145
|
+
确保 `data/` 目录有正确的写入权限:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
chmod -R 755 ~/.openclaw/skills/eng-lang-tutor/data/
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 6. 故障排查
|
|
152
|
+
|
|
153
|
+
### 6.1 Skill 未加载
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# 检查 skill 目录
|
|
157
|
+
ls -la ~/.openclaw/skills/eng-lang-tutor/
|
|
158
|
+
|
|
159
|
+
# 检查 SKILL.md 是否存在
|
|
160
|
+
cat ~/.openclaw/skills/eng-lang-tutor/SKILL.md
|
|
161
|
+
|
|
162
|
+
# 重启 Gateway
|
|
163
|
+
openclaw gateway restart
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 6.2 Discord 无响应
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# 检查 Gateway 日志
|
|
170
|
+
openclaw logs
|
|
171
|
+
|
|
172
|
+
# 验证 Discord Token
|
|
173
|
+
openclaw config get discord.token
|
|
174
|
+
|
|
175
|
+
# 检查 Bot 状态
|
|
176
|
+
openclaw doctor
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 6.3 Python 脚本错误
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# 检查 Python 环境
|
|
183
|
+
python3 --version
|
|
184
|
+
|
|
185
|
+
# 安装依赖(如有需要)
|
|
186
|
+
pip3 install -r ~/.openclaw/skills/eng-lang-tutor/requirements.txt
|
|
187
|
+
|
|
188
|
+
# 手动测试脚本
|
|
189
|
+
cd ~/.openclaw/skills/eng-lang-tutor/scripts/
|
|
190
|
+
python3 state_manager.py --show
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 7. 架构图
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
┌─────────────────────────────────────────────────────────┐
|
|
197
|
+
│ Discord │
|
|
198
|
+
│ (用户交互) │
|
|
199
|
+
└─────────────────────────┬───────────────────────────────┘
|
|
200
|
+
│
|
|
201
|
+
▼
|
|
202
|
+
┌─────────────────────────────────────────────────────────┐
|
|
203
|
+
│ OpenClaw Gateway │
|
|
204
|
+
│ (消息路由 + 会话管理) │
|
|
205
|
+
└─────────────────────────┬───────────────────────────────┘
|
|
206
|
+
│
|
|
207
|
+
▼
|
|
208
|
+
┌─────────────────────────────────────────────────────────┐
|
|
209
|
+
│ eng-lang-tutor Skill │
|
|
210
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
211
|
+
│ │ SKILL.md │ │ scripts/ │ │ data/ │ │
|
|
212
|
+
│ │ (技能描述) │ │ (Python代码) │ │ (状态存储) │ │
|
|
213
|
+
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|
214
|
+
└─────────────────────────────────────────────────────────┘
|
|
215
|
+
│
|
|
216
|
+
▼
|
|
217
|
+
┌─────────────────────────────────────────────────────────┐
|
|
218
|
+
│ LLM Provider │
|
|
219
|
+
│ (Claude/GPT/Qwen 等) │
|
|
220
|
+
└─────────────────────────────────────────────────────────┘
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## 8. 参考链接
|
|
224
|
+
|
|
225
|
+
- [OpenClaw 官方文档](https://docs.openclaw.ai)
|
|
226
|
+
- [OpenClaw GitHub](https://github.com/openclaw/openclaw)
|
|
227
|
+
- [Discord 开发者门户](https://discord.com/developers/applications)
|
|
228
|
+
- [OpenClaw Skills 开发指南](https://docs.openclaw.ai/skills)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"date": "2026-02-20",
|
|
3
|
+
"topic_fingerprint": "workplace_touch_base",
|
|
4
|
+
"category": "oral",
|
|
5
|
+
"topic": "workplace",
|
|
6
|
+
"scene": {
|
|
7
|
+
"context": "You want to briefly connect with a colleague about a project or task. This is common in American workplaces for quick check-ins without scheduling a formal meeting.",
|
|
8
|
+
"formality": "neutral"
|
|
9
|
+
},
|
|
10
|
+
"expressions": [
|
|
11
|
+
{
|
|
12
|
+
"phrase": "Let's touch base",
|
|
13
|
+
"pronunciation_tip": "Sounds like 'touch base', not 'touch bases'. It comes from baseball!",
|
|
14
|
+
"usage_note": "Use this when you want to have a brief, informal check-in. Very common in American business culture."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"phrase": "Can we touch base on this?",
|
|
18
|
+
"pronunciation_tip": "Natural speed: 'Can-we-touch-base-on-this' flows together.",
|
|
19
|
+
"usage_note": "Add 'on this' when referring to a specific topic or project."
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"alternatives": [
|
|
23
|
+
"Let's sync up",
|
|
24
|
+
"Can we catch up briefly?",
|
|
25
|
+
"Let's check in",
|
|
26
|
+
"Do you have a minute to connect?"
|
|
27
|
+
],
|
|
28
|
+
"chinglish_trap": {
|
|
29
|
+
"wrong": "Let's discuss together. / I want to communicate with you.",
|
|
30
|
+
"correct": "Let's touch base. / Can we sync up?",
|
|
31
|
+
"explanation": "Chinese speakers often translate directly, using 'discuss together' or 'communicate with you', which sounds formal and awkward in casual workplace settings. 'Touch base' is the natural American way to suggest a quick check-in."
|
|
32
|
+
},
|
|
33
|
+
"examples": [
|
|
34
|
+
{
|
|
35
|
+
"situation": "Morning standup meeting",
|
|
36
|
+
"dialogue": [
|
|
37
|
+
"A: Hey, I haven't seen the latest mockups. Can we touch base on those?",
|
|
38
|
+
"B: Sure, I'll swing by your desk after lunch.",
|
|
39
|
+
"A: Perfect, thanks!"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"situation": "Email follow-up",
|
|
44
|
+
"dialogue": [
|
|
45
|
+
"A: I'm heading into a meeting, but let's touch base later about the client presentation.",
|
|
46
|
+
"B: Sounds good. I'll be free around 3.",
|
|
47
|
+
"A: Great, I'll ping you then."
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"extended_learning": {
|
|
52
|
+
"related_phrases": [
|
|
53
|
+
"circle back - return to a topic later",
|
|
54
|
+
"loop in - include someone in communication",
|
|
55
|
+
"keep in the loop - keep someone informed"
|
|
56
|
+
],
|
|
57
|
+
"cultural_note": "The phrase 'touch base' comes from baseball, where runners must touch each base to score. In business, it means making brief contact to share updates or align on goals. Americans use this several times per day in corporate settings!",
|
|
58
|
+
"common_mistakes": [
|
|
59
|
+
"Saying 'touch bases' (wrong plural)",
|
|
60
|
+
"Using it for long, formal meetings (it implies brevity)",
|
|
61
|
+
"Not following up after saying you'll 'touch base'"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"references": {
|
|
65
|
+
"dictionary": {
|
|
66
|
+
"source": "merriam-webster",
|
|
67
|
+
"url": "https://www.merriam-webster.com/dictionary/touch%20base",
|
|
68
|
+
"note": "Official definition and usage examples"
|
|
69
|
+
},
|
|
70
|
+
"usage_context": {
|
|
71
|
+
"source": "youglish",
|
|
72
|
+
"url": "https://youglish.com/pronounce/touch%20base/english/us",
|
|
73
|
+
"note": "Hear it in 1000+ real YouTube videos"
|
|
74
|
+
},
|
|
75
|
+
"etymology": {
|
|
76
|
+
"source": "etymonline",
|
|
77
|
+
"url": "https://www.etymonline.com/word/touch",
|
|
78
|
+
"note": "From baseball: runners must touch each base to score"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"display": {
|
|
82
|
+
"title": "🏢 今日知识点 | Today's Knowledge Point",
|
|
83
|
+
"topic_tag": "🏷️ 主题: 职场口语 | Workplace Oral",
|
|
84
|
+
"formality_tag": "📊 正式度: 中性 | Neutral",
|
|
85
|
+
"scene_intro": "🎬 场景 | Scene",
|
|
86
|
+
"scene_text": "Quick check-in with colleagues without scheduling a formal meeting.",
|
|
87
|
+
"expressions_title": "💬 核心表达 | Key Expressions",
|
|
88
|
+
"expressions_formatted": [
|
|
89
|
+
{
|
|
90
|
+
"emoji": "✨",
|
|
91
|
+
"phrase": "**Let's touch base**",
|
|
92
|
+
"phrase_plain": "Let's touch base",
|
|
93
|
+
"pronunciation": "🔊 Sounds like 'touch base' (not 'bases')! From baseball ⚾",
|
|
94
|
+
"usage": "💡 Brief, informal check-in."
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"emoji": "✨",
|
|
98
|
+
"phrase": "**Can we touch base on this?**",
|
|
99
|
+
"phrase_plain": "Can we touch base on this?",
|
|
100
|
+
"pronunciation": "🔊 Flows: Can-we-touch-base-ON-this.",
|
|
101
|
+
"usage": "💡 Use when referring to a specific topic."
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"alternatives_title": "🔄 其他说法 | Alternatives",
|
|
105
|
+
"alternatives_formatted": "• **Let's sync up**\n• **Can we catch up briefly?**\n• **Let's check in**\n• Do you have a minute to connect?",
|
|
106
|
+
"chinglish_title": "⚠️ Chinglish 陷阱 | Chinglish Trap",
|
|
107
|
+
"chinglish_formatted": "❌ Wrong: \"Let's discuss together.\"\n❌ Wrong: \"I want to communicate with you.\"\n✅ Correct: **Let's touch base!**\n✅ Correct: **Can we sync up?**\n\n📝 Why? Direct translation sounds formal and awkward. **Touch base** is the natural American way!",
|
|
108
|
+
"examples_title": "🗣️ 对话示例 | Example Dialogues",
|
|
109
|
+
"examples_formatted": [
|
|
110
|
+
{
|
|
111
|
+
"situation_emoji": "☕",
|
|
112
|
+
"situation": "Morning standup",
|
|
113
|
+
"dialogue": "💬 A: Hey, can we **touch base** on those mockups?\n💬 B: Sure, I'll swing by after lunch.\n💬 A: Perfect, thanks!",
|
|
114
|
+
"key_phrase_highlight": "**touch base**"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"situation_emoji": "📧",
|
|
118
|
+
"situation": "Email follow-up",
|
|
119
|
+
"dialogue": "💬 A: Let's **touch base** later about the presentation.\n💬 B: Sounds good. Free around 3?\n💬 A: Great, I'll ping you then!",
|
|
120
|
+
"key_phrase_highlight": "**touch base**"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"extended_title": "📚 延伸学习 | Extended Learning",
|
|
124
|
+
"extended_formatted": "🔗 Related: **circle back** | **loop in** | **keep in the loop**\n\n🌎 Cultural Note: From baseball ⚾ - runners **touch** each **base** to score. Americans use this phrase several times a day!\n\n🚫 Common Mistakes:\n • Saying 'touch bases' ❌\n • Using for long meetings (it implies brevity)\n • Not following up",
|
|
125
|
+
"references_title": "📖 权威参考 | References",
|
|
126
|
+
"references_formatted": "📚 [Merriam-Webster](https://www.merriam-webster.com/dictionary/touch%20base) - Definition & examples\n🎬 [YouGlish](https://youglish.com/pronounce/touch%20base/english/us) - 1000+ YouTube videos\n📜 [Etymonline](https://www.etymonline.com/word/touch) - Word origin",
|
|
127
|
+
"footer": "───────────────────\n📅 2026-02-20 | 📝 Take the quiz to earn XP!"
|
|
128
|
+
},
|
|
129
|
+
"generated": true
|
|
130
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"quiz_date": "2026-02-20",
|
|
3
|
+
"keypoint_fingerprint": "workplace_touch_base",
|
|
4
|
+
"questions": [
|
|
5
|
+
{
|
|
6
|
+
"id": 1,
|
|
7
|
+
"type": "multiple_choice",
|
|
8
|
+
"question": "Your colleague asks to 'touch base' about a project. What do they mean?",
|
|
9
|
+
"context": "You receive a Slack message: 'Hey, can we touch base on the Q4 report?'",
|
|
10
|
+
"options": [
|
|
11
|
+
"A. They want to have a formal presentation",
|
|
12
|
+
"B. They want to have a brief check-in conversation",
|
|
13
|
+
"C. They want to cancel the project",
|
|
14
|
+
"D. They want you to write the entire report"
|
|
15
|
+
],
|
|
16
|
+
"correct_answer": "B",
|
|
17
|
+
"explanation": "'Touch base' means having a brief, informal check-in. It comes from baseball and implies a quick connection, not a formal meeting.",
|
|
18
|
+
"xp_value": 10,
|
|
19
|
+
"display": {
|
|
20
|
+
"type_emoji": "🔤",
|
|
21
|
+
"type_name": "选择题 | Multiple Choice",
|
|
22
|
+
"question_formatted": "💬 Your colleague asks to **'touch base'**. What do they mean?",
|
|
23
|
+
"context_formatted": "📱 Slack: \"Hey, can we **touch base** on the Q4 report?\"",
|
|
24
|
+
"options_formatted": [
|
|
25
|
+
"⬜ A. They want a formal presentation",
|
|
26
|
+
"⬜ B. They want a brief check-in",
|
|
27
|
+
"⬜ C. They want to cancel the project",
|
|
28
|
+
"⬜ D. They want you to write the report"
|
|
29
|
+
],
|
|
30
|
+
"correct_feedback": "✅ Correct! **'Touch base'** = quick check-in ⚡",
|
|
31
|
+
"wrong_feedback": "❌ Not quite. **'Touch base'** means a brief, informal chat!",
|
|
32
|
+
"key_phrase": "**touch base**",
|
|
33
|
+
"xp_display": "💎 +10 XP"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": 2,
|
|
38
|
+
"type": "chinglish_fix",
|
|
39
|
+
"question": "Identify and fix the Chinglish expression in this email:",
|
|
40
|
+
"context": "\"Hi Team, I want to communicate with you about the project. Let's discuss together tomorrow.\"",
|
|
41
|
+
"correct_answer": "touch base / sync up / check in",
|
|
42
|
+
"explanation": "'Communicate with you' and 'discuss together' are direct translations that sound formal and awkward. Americans would say 'touch base' or 'sync up' instead.",
|
|
43
|
+
"xp_value": 15,
|
|
44
|
+
"display": {
|
|
45
|
+
"type_emoji": "🔧",
|
|
46
|
+
"type_name": "Chinglish 修正 | Fix the Chinglish",
|
|
47
|
+
"question_formatted": "🔧 Find and fix the Chinglish expressions:",
|
|
48
|
+
"email_formatted": "📧 Original email:\n\"Hi Team, I want to 'communicate with you' about the project. Let's 'discuss together' tomorrow.\"",
|
|
49
|
+
"hint": "💡 Hint: How would an American say this naturally?",
|
|
50
|
+
"correct_feedback": "✅ Fixed! **\"Let's touch base\"** or **\"Let's sync up\"** sounds much better! 🎉",
|
|
51
|
+
"wrong_feedback": "❌ 'Communicate with you' → **'touch base'**\n❌ 'Discuss together' → **'sync up'**",
|
|
52
|
+
"answer_formatted": "📝 Better: \"Hi Team, can we **touch base** about the project? Let's **sync up** tomorrow.\"",
|
|
53
|
+
"key_phrase": "**touch base / sync up**",
|
|
54
|
+
"xp_display": "💎 +15 XP"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": 3,
|
|
59
|
+
"type": "fill_blank",
|
|
60
|
+
"question": "Complete the sentence with the correct expression:",
|
|
61
|
+
"context": "You want to suggest a quick meeting with your manager. You say: 'I wanted to ___ on the project timeline.'",
|
|
62
|
+
"word_bank": ["touch base", "discuss together", "communicate"],
|
|
63
|
+
"correct_answer": "touch base",
|
|
64
|
+
"explanation": "'Touch base' is the natural American expression for suggesting a quick check-in. 'Discuss together' sounds awkward and redundant.",
|
|
65
|
+
"xp_value": 12,
|
|
66
|
+
"display": {
|
|
67
|
+
"type_emoji": "✏️",
|
|
68
|
+
"type_name": "填空题 | Fill in the Blank",
|
|
69
|
+
"question_formatted": "✏️ Complete the sentence:",
|
|
70
|
+
"context_formatted": "💼 To your manager: \"I wanted to **___** on the project timeline.\"",
|
|
71
|
+
"word_bank_formatted": "📦 Word Bank: [ **touch base** | 'discuss together' ❌ | 'communicate' ❌ ]",
|
|
72
|
+
"correct_feedback": "✅ Perfect! **'Touch base'** is the way to go! 🎯",
|
|
73
|
+
"wrong_feedback": "❌ 'Discuss together' sounds awkward. Try **'touch base'**!",
|
|
74
|
+
"key_phrase": "**touch base**",
|
|
75
|
+
"xp_display": "💎 +12 XP"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"total_xp": 37,
|
|
80
|
+
"passing_score": 70,
|
|
81
|
+
"display": {
|
|
82
|
+
"header": "📝 今日测验 | Daily Quiz",
|
|
83
|
+
"date": "📅 2026-02-20",
|
|
84
|
+
"topic": "🏷️ Topic: **workplace_touch_base**",
|
|
85
|
+
"instructions": "🎯 3道小题,答对2道就过关!3 questions, get 2 right to pass!",
|
|
86
|
+
"progress_bar": "⬜⬜⬜ 0/3 questions",
|
|
87
|
+
"key_phrase_summary": "🔑 Key Phrase: **touch base** = 快速沟通/碰头",
|
|
88
|
+
"xp_summary": "💎 Total XP: 37 | 🏆 Pass: 2/3 correct",
|
|
89
|
+
"footer": "───────────────────\n💪 Good luck! 加油! 🚀"
|
|
90
|
+
},
|
|
91
|
+
"generated": true
|
|
92
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Post-install script for @rookiestar/eng-lang-tutor
|
|
5
|
+
*
|
|
6
|
+
* This script runs automatically after npm install and:
|
|
7
|
+
* 1. Installs the skill to ~/.openclaw/skills/eng-lang-tutor/
|
|
8
|
+
* 2. Migrates data from old data/ directory if needed (handled by Python code)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
|
|
15
|
+
const SKILL_NAME = 'eng-lang-tutor';
|
|
16
|
+
const SKILLS_DIR = path.join(os.homedir(), '.openclaw', 'skills');
|
|
17
|
+
const SKILL_TARGET = path.join(SKILLS_DIR, SKILL_NAME);
|
|
18
|
+
|
|
19
|
+
// Get the package root directory
|
|
20
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
21
|
+
|
|
22
|
+
function install() {
|
|
23
|
+
console.log(`\n📦 Setting up ${SKILL_NAME} skill...\n`);
|
|
24
|
+
|
|
25
|
+
// Create skills directory if it doesn't exist
|
|
26
|
+
if (!fs.existsSync(SKILLS_DIR)) {
|
|
27
|
+
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
28
|
+
console.log(`✓ Created skills directory: ${SKILLS_DIR}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Remove existing installation if present
|
|
32
|
+
if (fs.existsSync(SKILL_TARGET)) {
|
|
33
|
+
console.log(`✓ Updating existing installation...`);
|
|
34
|
+
fs.rmSync(SKILL_TARGET, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Create target directory
|
|
38
|
+
fs.mkdirSync(SKILL_TARGET, { recursive: true });
|
|
39
|
+
|
|
40
|
+
// Files and directories to copy
|
|
41
|
+
const itemsToCopy = [
|
|
42
|
+
'scripts',
|
|
43
|
+
'templates',
|
|
44
|
+
'references',
|
|
45
|
+
'examples',
|
|
46
|
+
'docs',
|
|
47
|
+
'SKILL.md',
|
|
48
|
+
'CLAUDE.md',
|
|
49
|
+
'README.md',
|
|
50
|
+
'README_EN.md',
|
|
51
|
+
'requirements.txt'
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// Copy each item
|
|
55
|
+
let copiedCount = 0;
|
|
56
|
+
for (const item of itemsToCopy) {
|
|
57
|
+
const sourcePath = path.join(PACKAGE_ROOT, item);
|
|
58
|
+
const targetPath = path.join(SKILL_TARGET, item);
|
|
59
|
+
|
|
60
|
+
if (!fs.existsSync(sourcePath)) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
if (fs.statSync(sourcePath).isDirectory()) {
|
|
66
|
+
copyDir(sourcePath, targetPath);
|
|
67
|
+
} else {
|
|
68
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
69
|
+
}
|
|
70
|
+
copiedCount++;
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error(` Warning: Could not copy ${item}: ${err.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(`✓ Copied ${copiedCount} items to ${SKILL_TARGET}`);
|
|
77
|
+
|
|
78
|
+
// Show post-install message
|
|
79
|
+
console.log(`
|
|
80
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
81
|
+
║ Installation Complete! ║
|
|
82
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
83
|
+
║ ║
|
|
84
|
+
║ ${SKILL_NAME} has been installed to: ║
|
|
85
|
+
║ ${SKILL_TARGET}
|
|
86
|
+
║ ║
|
|
87
|
+
║ Next steps: ║
|
|
88
|
+
║ 1. Install Python dependencies: ║
|
|
89
|
+
║ pip install -r ${SKILL_TARGET}/requirements.txt ║
|
|
90
|
+
║ ║
|
|
91
|
+
║ 2. Restart your OpenClaw agent ║
|
|
92
|
+
║ ║
|
|
93
|
+
║ 3. Configure through onboarding (first time only) ║
|
|
94
|
+
║ ║
|
|
95
|
+
║ Data location: ║
|
|
96
|
+
║ ~/.openclaw/state/eng-lang-tutor/ ║
|
|
97
|
+
║ (or set OPENCLAW_STATE_DIR env var) ║
|
|
98
|
+
║ ║
|
|
99
|
+
║ Commands: ║
|
|
100
|
+
║ npx eng-lang-tutor install - Reinstall skill ║
|
|
101
|
+
║ npx eng-lang-tutor uninstall - Remove skill ║
|
|
102
|
+
║ ║
|
|
103
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function copyDir(src, dest) {
|
|
108
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
109
|
+
|
|
110
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
111
|
+
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
const srcPath = path.join(src, entry.name);
|
|
114
|
+
const destPath = path.join(dest, entry.name);
|
|
115
|
+
|
|
116
|
+
if (entry.isDirectory()) {
|
|
117
|
+
copyDir(srcPath, destPath);
|
|
118
|
+
} else {
|
|
119
|
+
fs.copyFileSync(srcPath, destPath);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Run installation
|
|
125
|
+
try {
|
|
126
|
+
install();
|
|
127
|
+
} catch (err) {
|
|
128
|
+
console.error(`\n❌ Installation failed: ${err.message}`);
|
|
129
|
+
console.error('You may need to run the install manually:');
|
|
130
|
+
console.error(' npx eng-lang-tutor install\n');
|
|
131
|
+
process.exit(0); // Don't fail npm install
|
|
132
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rookiestar/eng-lang-tutor",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "English language tutor skill for OpenClaw - Learn authentic American English expressions with gamification",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"english",
|
|
7
|
+
"language-learning",
|
|
8
|
+
"tutor",
|
|
9
|
+
"openclaw",
|
|
10
|
+
"skill",
|
|
11
|
+
"gamification"
|
|
12
|
+
],
|
|
13
|
+
"author": "rookiestar",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"bin": {
|
|
16
|
+
"eng-lang-tutor": "./bin/eng-lang-tutor.js"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"postinstall": "node npm-scripts/install.js"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin/",
|
|
23
|
+
"npm-scripts/",
|
|
24
|
+
"scripts/",
|
|
25
|
+
"templates/",
|
|
26
|
+
"references/",
|
|
27
|
+
"examples/",
|
|
28
|
+
"docs/",
|
|
29
|
+
"SKILL.md",
|
|
30
|
+
"CLAUDE.md",
|
|
31
|
+
"README.md",
|
|
32
|
+
"README_EN.md",
|
|
33
|
+
"requirements.txt"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=14.0.0"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/rookiestar/eng-lang-tutor.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/rookiestar/eng-lang-tutor/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/rookiestar/eng-lang-tutor#readme"
|
|
46
|
+
}
|