@sokeai/cli 1.0.21 → 1.0.25

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.
@@ -0,0 +1,225 @@
1
+ #!/bin/bash
2
+
3
+ # soke-cli 本地测试脚本
4
+ # 用于本地开发测试:编译 -> 安装到全局 -> 验证功能
5
+
6
+ # 颜色输出
7
+ RED='\033[0;31m'
8
+ GREEN='\033[0;32m'
9
+ YELLOW='\033[1;33m'
10
+ BLUE='\033[0;34m'
11
+ NC='\033[0m'
12
+
13
+ echo -e "${BLUE}========================================${NC}"
14
+ echo -e "${BLUE} soke-cli 本地测试${NC}"
15
+ echo -e "${BLUE}========================================${NC}"
16
+ echo ""
17
+
18
+ # 步骤1: 编译
19
+ echo -e "${YELLOW}[1/4] 编译 soke-cli...${NC}"
20
+ if go build -o soke-cli main.go; then
21
+ echo -e "${GREEN}✓ 编译成功${NC}"
22
+ else
23
+ echo -e "${RED}✗ 编译失败${NC}"
24
+ exit 1
25
+ fi
26
+ echo ""
27
+
28
+ # 步骤2: 检查本地版本功能
29
+ echo -e "${YELLOW}[2/4] 检查本地版本功能...${NC}"
30
+ echo -e " 检查 learning-profile 模块..."
31
+ if ./soke-cli learning-profile --help &>/dev/null; then
32
+ echo -e "${GREEN} ✓ learning-profile 模块存在${NC}"
33
+ else
34
+ echo -e "${RED} ✗ learning-profile 模块不存在${NC}"
35
+ exit 1
36
+ fi
37
+
38
+ echo -e " 检查 contact +search-dept 命令..."
39
+ if ./soke-cli contact +search-dept --help &>/dev/null; then
40
+ echo -e "${GREEN} ✓ contact +search-dept 命令存在${NC}"
41
+ else
42
+ echo -e "${RED} ✗ contact +search-dept 命令不存在${NC}"
43
+ exit 1
44
+ fi
45
+ echo ""
46
+
47
+ # 步骤3: 安装到全局
48
+ echo -e "${YELLOW}[3/4] 安装到全局...${NC}"
49
+
50
+ # 查找全局 CLI 路径
51
+ GLOBAL_CLI=$(which soke-cli 2>/dev/null)
52
+ if [ -z "$GLOBAL_CLI" ]; then
53
+ echo -e "${YELLOW} 未找到全局 soke-cli 安装${NC}"
54
+ echo -e "${YELLOW} 请先通过 npm 安装: npm install -g @sokeai/cli${NC}"
55
+ echo -e "${YELLOW} 跳过全局安装,仅测试本地版本${NC}"
56
+ SKIP_GLOBAL=true
57
+ else
58
+ echo -e " 全局 CLI 路径: ${BLUE}${GLOBAL_CLI}${NC}"
59
+
60
+ # 检查是否需要更新
61
+ NEED_UPDATE=false
62
+ if ! $GLOBAL_CLI learning-profile --help &>/dev/null; then
63
+ echo -e "${YELLOW} 全局版本不支持 learning-profile 模块${NC}"
64
+ NEED_UPDATE=true
65
+ elif ! $GLOBAL_CLI contact +search-dept --help &>/dev/null; then
66
+ echo -e "${YELLOW} 全局版本不支持 contact +search-dept 命令${NC}"
67
+ NEED_UPDATE=true
68
+ fi
69
+
70
+ if [ "$NEED_UPDATE" = true ]; then
71
+ echo -e "${YELLOW} 需要更新全局安装${NC}"
72
+ echo ""
73
+ echo -e "${YELLOW} 是否要用本地版本覆盖全局安装? (y/n)${NC}"
74
+ read -r CONFIRM
75
+
76
+ if [ "$CONFIRM" = "y" ] || [ "$CONFIRM" = "Y" ]; then
77
+ # 备份原文件
78
+ BACKUP_FILE="${GLOBAL_CLI}.backup.$(date +%Y%m%d_%H%M%S)"
79
+ echo -e " 备份原文件到: ${BACKUP_FILE}"
80
+ if sudo cp $GLOBAL_CLI $BACKUP_FILE; then
81
+ echo -e "${GREEN} ✓ 备份成功${NC}"
82
+ else
83
+ echo -e "${RED} ✗ 备份失败${NC}"
84
+ exit 1
85
+ fi
86
+
87
+ # 安装新版本
88
+ echo -e " 安装新版本..."
89
+ if sudo cp ./soke-cli $GLOBAL_CLI; then
90
+ echo -e "${GREEN} ✓ 安装成功${NC}"
91
+ echo -e "${BLUE} 备份文件: ${BACKUP_FILE}${NC}"
92
+ else
93
+ echo -e "${RED} ✗ 安装失败${NC}"
94
+ echo -e "${YELLOW} 恢复备份...${NC}"
95
+ sudo cp $BACKUP_FILE $GLOBAL_CLI
96
+ exit 1
97
+ fi
98
+ SKIP_GLOBAL=false
99
+ else
100
+ echo -e "${YELLOW} 跳过全局安装${NC}"
101
+ SKIP_GLOBAL=true
102
+ fi
103
+ else
104
+ echo -e "${GREEN} ✓ 全局版本已是最新,无需更新${NC}"
105
+ SKIP_GLOBAL=false
106
+ fi
107
+ fi
108
+ echo ""
109
+
110
+ # 步骤3.5: 分发 Skills 到本地 Agent
111
+ echo -e "${YELLOW}[3.5/4] 分发 Skills 到本地 Agent...${NC}"
112
+ if [ "$SKIP_GLOBAL" = false ]; then
113
+ echo -e " 执行 scripts/install.js 同步 Skills..."
114
+ # 注入特殊环境变量或者直接调用 node 执行
115
+ # 我们只想要触发 syncSkillsToSokeclawWorkspace 和 syncSkillsToWorkclawRegistry
116
+ # 但原 install.js 会尝试下载二进制文件,所以我们新建一个临时脚本或修改调用方式
117
+
118
+ # 为了安全起见,这里直接使用 node 运行一小段脚本引入 install.js 中的逻辑
119
+ cat > ./scripts/sync-skills-local.js << 'EOF'
120
+ const fs = require('fs');
121
+ const path = require('path');
122
+ const installCode = fs.readFileSync(path.join(__dirname, 'install.js'), 'utf8');
123
+
124
+ // 提取需要的函数
125
+ const syncFn1Match = installCode.match(/function syncSkillsToSokeclawWorkspace\(\) \{[\s\S]*?\n\}/);
126
+ const syncFn2Match = installCode.match(/function syncSkillsToWorkclawRegistry\(\) \{[\s\S]*?\n\}/);
127
+
128
+ // 我们更推荐直接利用已经写好的 js 模块(如果它是通过 module.exports 导出的)
129
+ // 但因为 install.js 是直接执行的脚本,我们通过简单的 node 脚本手动拷贝
130
+ const os = require('os');
131
+ function copyDirRecursive(srcDir, destDir) {
132
+ if (!fs.existsSync(srcDir)) return;
133
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
134
+ const entries = fs.readdirSync(srcDir, { withFileTypes: true });
135
+ for (const entry of entries) {
136
+ const srcPath = path.join(srcDir, entry.name);
137
+ const destPath = path.join(destDir, entry.name);
138
+ if (entry.isDirectory()) { copyDirRecursive(srcPath, destPath); continue; }
139
+ fs.copyFileSync(srcPath, destPath);
140
+ }
141
+ }
142
+
143
+ const homeDir = os.homedir();
144
+ const defaultSokeclawDir = path.join(homeDir, '.sokeclaw', 'openai-agents', 'workspaces', 'main', 'skills');
145
+ const packageRoot = path.join(__dirname, '..');
146
+ const packagedSkillsDir = path.join(packageRoot, 'skills');
147
+
148
+ if (fs.existsSync(packagedSkillsDir)) {
149
+ const skillNames = fs.readdirSync(packagedSkillsDir).filter(n => n.startsWith('soke-'));
150
+ if (fs.existsSync(defaultSokeclawDir)) {
151
+ for (const skillName of skillNames) {
152
+ const src = path.join(packagedSkillsDir, skillName);
153
+ const dest = path.join(defaultSokeclawDir, skillName);
154
+ copyDirRecursive(src, dest);
155
+ console.log(` ✓ 同步 ${skillName} 到 ${dest}`);
156
+ }
157
+ }
158
+ }
159
+ EOF
160
+ node ./scripts/sync-skills-local.js
161
+ rm ./scripts/sync-skills-local.js
162
+ echo -e "${GREEN} ✓ Skills 同步完成${NC}"
163
+ else
164
+ echo -e "${YELLOW} 跳过全局安装,同时跳过 Skills 同步${NC}"
165
+ fi
166
+ echo ""
167
+
168
+ # 步骤4: 运行功能测试
169
+ echo -e "${YELLOW}[4/4] 运行功能测试...${NC}"
170
+
171
+ # 测试本地版本
172
+ echo -e " ${BLUE}测试本地版本:${NC}"
173
+ if ./soke-cli learning-profile +list --help &>/dev/null; then
174
+ echo -e "${GREEN} ✓ learning-profile +list 命令可用${NC}"
175
+ else
176
+ echo -e "${RED} ✗ learning-profile +list 命令不可用${NC}"
177
+ exit 1
178
+ fi
179
+
180
+ if ./soke-cli contact +search-dept --help &>/dev/null; then
181
+ echo -e "${GREEN} ✓ contact +search-dept 命令可用${NC}"
182
+ else
183
+ echo -e "${RED} ✗ contact +search-dept 命令不可用${NC}"
184
+ exit 1
185
+ fi
186
+
187
+ if ./soke-cli contact +search-user --help &>/dev/null; then
188
+ echo -e "${GREEN} ✓ contact +search-user 命令可用${NC}"
189
+ else
190
+ echo -e "${RED} ✗ contact +search-user 命令不可用${NC}"
191
+ exit 1
192
+ fi
193
+
194
+ # 测试全局版本(如果已安装)
195
+ if [ "$SKIP_GLOBAL" = false ] && [ -n "$GLOBAL_CLI" ]; then
196
+ echo ""
197
+ echo -e " ${BLUE}测试全局版本:${NC}"
198
+ if $GLOBAL_CLI learning-profile +list --help &>/dev/null; then
199
+ echo -e "${GREEN} ✓ learning-profile +list 命令可用${NC}"
200
+ else
201
+ echo -e "${RED} ✗ learning-profile +list 命令不可用${NC}"
202
+ echo -e "${YELLOW} 提示: 全局安装可能未成功更新${NC}"
203
+ fi
204
+
205
+ if $GLOBAL_CLI contact +search-dept --help &>/dev/null; then
206
+ echo -e "${GREEN} ✓ contact +search-dept 命令可用${NC}"
207
+ else
208
+ echo -e "${RED} ✗ contact +search-dept 命令不可用${NC}"
209
+ echo -e "${YELLOW} 提示: 全局安装可能未成功更新${NC}"
210
+ fi
211
+
212
+ if $GLOBAL_CLI contact +search-user --help &>/dev/null; then
213
+ echo -e "${GREEN} ✓ contact +search-user 命令可用${NC}"
214
+ else
215
+ echo -e "${RED} ✗ contact +search-user 命令不可用${NC}"
216
+ echo -e "${YELLOW} 提示: 全局安装可能未成功更新${NC}"
217
+ fi
218
+ fi
219
+ echo ""
220
+
221
+ # 完成
222
+ echo -e "${GREEN}========================================${NC}"
223
+ echo -e "${GREEN} 本地测试完成! ✓${NC}"
224
+ echo -e "${GREEN}========================================${NC}"
225
+
package/scripts/push.sh CHANGED
@@ -236,13 +236,3 @@ fi
236
236
 
237
237
  echo " - Aliyun (origin): master 分支已更新"
238
238
  echo " - GitHub (github): master 和 main 分支已更新"
239
-
240
- if [[ "$IS_RELEASE" == true ]]; then
241
- echo ""
242
- print_highlight "📦 下一步操作:"
243
- echo " 1. 编译二进制文件: make build"
244
- echo " 2. 发布到 NPM: npm publish"
245
- echo " 3. 创建 GitHub Release (可选)"
246
- fi
247
-
248
- echo ""
@@ -0,0 +1,223 @@
1
+ ---
2
+ name: soke-learning-profile
3
+ summary: 学员学习档案查询
4
+ version: 1.0.0
5
+ description: "学员学习档案查询:查询学员的完整学习记录,包括课程学习、考试成绩、证书获取、学分积分等。当用户需要查询学员学习档案、查看学员学习情况、统计学员学习数据、查询学员综合学习信息时使用。"
6
+ metadata:
7
+ requires:
8
+ bins: ["soke-cli"]
9
+ cliHelp: "soke-cli learning-profile --help"
10
+ ---
11
+
12
+ **CRITICAL — 开始前 MUST 先用 Read 工具读取 [`../soke-shared/SKILL.md`](../soke-shared/SKILL.md),其中包含认证、配置、权限处理**
13
+
14
+ ## 核心概念
15
+
16
+ - **LearningProfile(学习档案)**: 学员的完整学习记录,包含课程、考试、证书、培训等多维度数据
17
+ - **DeptUser(部门用户)**: 企业内的学员,通过 `dept_user_id` 标识
18
+ - **Department(部门)**: 组织架构单元,通过 `dept_id` 标识
19
+
20
+ ## 资源关系
21
+
22
+ ```
23
+ LearningProfile (学习档案)
24
+ ├── DeptUser (学员)
25
+ │ ├── dept_user_id (学员ID)
26
+ │ ├── dept_user_name (学员姓名)
27
+ │ └── dept_names (所属部门)
28
+ ├── CourseData (课程数据)
29
+ │ ├── required_learning/finished (必修课程)
30
+ │ ├── optional_learning/finished (选修课程)
31
+ │ └── learn_time (学习时长)
32
+ ├── ExamData (考试数据)
33
+ │ ├── not_attempt (未开始)
34
+ │ ├── passed (通过)
35
+ │ ├── notpassed (未通过)
36
+ │ └── reviewing (批阅中)
37
+ ├── CertificateData (证书数据)
38
+ │ └── certificate_number (证书数量)
39
+ ├── PointsAndCredits (积分学分)
40
+ │ ├── points (积分)
41
+ │ └── credits (学分)
42
+ └── TrainingData (培训数据)
43
+ ├── training_finished (线下培训)
44
+ ├── learning_map_finished (学习地图)
45
+ └── training_class_finished (培训班)
46
+ ```
47
+
48
+ ## Shortcuts(推荐优先使用)
49
+
50
+ | Shortcut | 说明 |
51
+ |----------|------|
52
+ | [`+list`](#list) | 查询学员学习档案列表 |
53
+
54
+ ## 辅助命令(contact 模块)
55
+
56
+ | Shortcut | 说明 |
57
+ |----------|------|
58
+ | `contact +search-user` | 根据姓名搜索学员 |
59
+ | `contact +search-dept` | 根据名称搜索部门 |
60
+
61
+ ---
62
+
63
+ ## 命令详解
64
+
65
+ ### +list
66
+
67
+ 查询学员学习档案列表,支持按部门、学员ID筛选。
68
+
69
+ **命令格式**:
70
+ ```bash
71
+ soke-cli learning-profile +list \
72
+ [--dept-user-ids <user_id1,user_id2,...>] \
73
+ [--dept-ids <dept_id1,dept_id2,...>] \
74
+ [--is-new <0|1>] \
75
+ [--offset <offset>] \
76
+ [--page-size <size>]
77
+ ```
78
+
79
+ **参数说明**:
80
+ - `--dept-user-ids`: 学员ID列表,多个ID用逗号分隔(可选)
81
+ - `--dept-ids`: 部门ID列表,多个ID用逗号分隔(可选)
82
+ - `--is-new`: 是否新员工,0-否,1-是(可选)
83
+ - `--offset`: 偏移量,默认从0开始(可选)
84
+ - `--page-size`: 每页条数,最大100,默认10(可选)
85
+
86
+ **返回字段**(表格显示关键字段):
87
+ - `姓名`: 学员姓名
88
+ - `部门`: 所属部门
89
+ - `职位`: 职位
90
+ - `必修完成`: 必修课程完成情况(完成数/总数)
91
+ - `选修完成`: 选修课程完成情况(完成数/总数)
92
+ - `考试通过`: 考试通过数
93
+ - `学习时长`: 学习时长(格式化为"X小时Y分钟")
94
+ - `证书数`: 获得证书数量
95
+ - `学分`: 学分
96
+ - `积分`: 积分
97
+
98
+ **JSON 输出包含完整字段**(30+ 字段):
99
+ - 基础信息:`dept_user_id`, `dept_user_name`, `dept_names`, `position`, `job_number`, `avatar`, `is_leave`, `hired_date`
100
+ - 课程学习:`optional_learning`, `optional_finished`, `required_learning`, `required_finished`, `learn_time`
101
+ - 考试情况:`not_attempt`, `passed`, `notpassed`, `reviewing`
102
+ - 证书积分:`certificate_number`, `points`, `credits`
103
+ - 培训情况:`training_not_attempt`, `training_finished`, `class_length`
104
+ - 学习地图:`leaning_map_attempt`, `learning_map_finished`
105
+ - 培训班:`training_class_attempt`, `training_class_finished`
106
+ - 其他:`live_learn_time`, `external_training_time`, `knowledge_number`, `evaluation_score`
107
+
108
+ **示例**:
109
+ ```bash
110
+ # 查询所有学员学习档案
111
+ soke-cli learning-profile +list --offset 0 --page-size 20
112
+
113
+ # 查询特定学员(单个)
114
+ soke-cli learning-profile +list --dept-user-ids user123
115
+
116
+ # 查询多个学员
117
+ soke-cli learning-profile +list --dept-user-ids user123,user456,user789
118
+
119
+ # 查询特定部门的学员
120
+ soke-cli learning-profile +list --dept-ids dept456
121
+
122
+ # 查询多个部门的学员
123
+ soke-cli learning-profile +list --dept-ids dept456,dept789
124
+
125
+ # 查询新员工的学习档案
126
+ soke-cli learning-profile +list --is-new 1 --page-size 50
127
+
128
+ # 分页查询(使用 offset)
129
+ soke-cli learning-profile +list --offset 0 --page-size 10 # 第1页
130
+ soke-cli learning-profile +list --offset 10 --page-size 10 # 第2页
131
+ soke-cli learning-profile +list --offset 20 --page-size 10 # 第3页
132
+ ```
133
+
134
+ **权限要求**: `learningProfile:readonly`
135
+
136
+ **使用场景**:
137
+ - 当用户询问"查询学员学习档案"时使用
138
+ - 当用户需要查看学员学习情况、统计学习数据时使用
139
+ - 当用户需要导出学员学习报表时使用
140
+
141
+ ---
142
+
143
+ ## 权限表
144
+
145
+ | 命令 | 所需权限 | 说明 |
146
+ |------|----------|------|
147
+ | `+list` | `learningProfile:readonly` | 查询学员学习档案 |
148
+ | `contact +search-user` | `contact:user:readonly` | 搜索学员 |
149
+ | `contact +search-dept` | `contact:department:readonly` | 搜索部门 |
150
+
151
+ ---
152
+
153
+ ## 常见工作流
154
+
155
+ ### 工作流1: 根据姓名查询学员学习档案
156
+
157
+ 当用户询问"查询张三的学习档案"时:
158
+
159
+ **步骤1**: 搜索学员获取 dept_user_id
160
+ ```bash
161
+ soke-cli contact +search-user --dept-user-name "张三"
162
+ ```
163
+
164
+ **步骤2**: 使用 dept_user_id 查询学习档案
165
+ ```bash
166
+ soke-cli learning-profile +list --dept-user-ids <从步骤1获取的dept_user_id>
167
+ ```
168
+
169
+ **注意**: 学习档案接口不支持按姓名直接查询,必须先通过 contact 模块获取 dept_user_id。
170
+
171
+ ### 工作流2: 查询部门所有学员的学习档案
172
+
173
+ 当用户询问"查询技术部所有学员的学习情况"时:
174
+
175
+ **步骤1**: 搜索部门获取 dept_id
176
+ ```bash
177
+ soke-cli contact +search-dept --dept-name "技术部"
178
+ ```
179
+
180
+ **步骤2**: 使用 dept_id 查询该部门学员学习档案
181
+ ```bash
182
+ soke-cli learning-profile +list --dept-ids <从步骤1获取的dept_id> --page-size 100
183
+ ```
184
+
185
+ ### 工作流3: 批量导出学习档案
186
+
187
+ 当用户需要导出学习档案数据时:
188
+
189
+ ```bash
190
+ # 使用 JSON 格式输出并保存到文件
191
+ soke-cli learning-profile +list --page-size 100 --format json > learning_profiles.json
192
+ ```
193
+
194
+ ---
195
+
196
+ ## 注意事项
197
+
198
+ 1. **时间格式**: `learn_time`, `class_length` 等时长字段单位为秒,表格输出时会自动格式化为"X小时Y分钟"
199
+ 2. **分页**: 使用 `offset` 和 `page_size` 进行分页,默认每页10条,最大100条
200
+ 3. **数组参数**: `dept_user_ids` 和 `dept_ids` 是数组类型,多个ID用逗号分隔
201
+ 4. **姓名查询**: 学习档案接口不支持按姓名查询,需要先通过 `contact +search-user` 获取 dept_user_id
202
+ 5. **权限**: 需要 `learningProfile:readonly` 权限,如遇权限错误参考 soke-shared
203
+ 6. **数据完整性**: 表格输出仅显示关键字段,完整数据请使用 `--format json`
204
+
205
+ ---
206
+
207
+ ## 错误处理
208
+
209
+ ### 权限不足
210
+ 如果遇到权限错误,参考 [`../soke-shared/SKILL.md`](../soke-shared/SKILL.md)
211
+
212
+ ### 参数错误
213
+ 使用 `--help` 查看命令参数说明:
214
+ ```bash
215
+ soke-cli learning-profile +list --help
216
+ ```
217
+
218
+ ### 数据为空
219
+ 如果查询结果为空,检查:
220
+ 1. 筛选条件是否正确(dept_ids, dept_user_ids, is_new)
221
+ 2. 学员是否有学习记录
222
+ 3. 是否有权限查看该部门/学员的数据
223
+ 4. 注意:学习档案接口不支持按姓名查询,需要先获取 dept_user_id