@meet-im/lxcli 0.0.8 → 0.0.10
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.
|
@@ -240,7 +240,7 @@ metadata:
|
|
|
240
240
|
}
|
|
241
241
|
return lines.join('\n');
|
|
242
242
|
}
|
|
243
|
-
async function generateServiceSkills(skillsDir, serviceName) {
|
|
243
|
+
async function generateServiceSkills(skillsDir, serviceName, force) {
|
|
244
244
|
// 目前只支持 kb 服务
|
|
245
245
|
if (serviceName !== 'kb') {
|
|
246
246
|
logger.info(`Service "${serviceName}" is not supported. Supported services: kb`);
|
|
@@ -252,14 +252,16 @@ async function generateServiceSkills(skillsDir, serviceName) {
|
|
|
252
252
|
const skillName = `lxcli-${serviceName}-${method}`;
|
|
253
253
|
const skillDir = path.join(skillsDir, skillName);
|
|
254
254
|
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
255
|
+
// 检查是否已有 SKILL.md(非 --force 时跳过已有文件)
|
|
256
|
+
if (!force) {
|
|
257
|
+
try {
|
|
258
|
+
await fs.access(skillPath);
|
|
259
|
+
logger.info(`Skipped ${skillName}: SKILL.md already exists (use --force to overwrite)`);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
// 不存在,生成新的
|
|
264
|
+
}
|
|
263
265
|
}
|
|
264
266
|
await fs.mkdir(skillDir, { recursive: true });
|
|
265
267
|
const content = renderSkillMd(method, version);
|
|
@@ -272,7 +274,8 @@ export function registerGenerateSkillsCommand(program) {
|
|
|
272
274
|
.command('generate-skills')
|
|
273
275
|
.description('生成 skills 索引文件')
|
|
274
276
|
.option('-o, --output <path>', '输出文件路径', DEFAULT_OUTPUT)
|
|
275
|
-
.option('-s, --service <name>', '
|
|
277
|
+
.option('-s, --service <name>', '为指定服务生成 SKILL.md 文件(如 kb, meet)')
|
|
278
|
+
.option('-f, --force', '配合 --service 使用,覆盖已有 SKILL.md')
|
|
276
279
|
.action(async (options) => {
|
|
277
280
|
try {
|
|
278
281
|
const stat = await fs.stat(API_ROOT);
|
|
@@ -287,10 +290,10 @@ export function registerGenerateSkillsCommand(program) {
|
|
|
287
290
|
const outputPath = path.resolve(options.output);
|
|
288
291
|
await fs.mkdir(skillsDir, { recursive: true });
|
|
289
292
|
logger.info(`Scanning skills from ${skillsDir}`);
|
|
290
|
-
// 如果指定了 --service
|
|
293
|
+
// 如果指定了 --service,生成 SKILL.md
|
|
291
294
|
if (options.service) {
|
|
292
|
-
logger.info(`Generating
|
|
293
|
-
await generateServiceSkills(skillsDir, options.service);
|
|
295
|
+
logger.info(`Generating ${options.service} SKILL.md files...`);
|
|
296
|
+
await generateServiceSkills(skillsDir, options.service, options.force);
|
|
294
297
|
}
|
|
295
298
|
const entries = await scanSkills(skillsDir);
|
|
296
299
|
logger.info(`Found ${entries.length} skills`);
|
|
@@ -87,15 +87,30 @@ export function createKbAction(method) {
|
|
|
87
87
|
}
|
|
88
88
|
params = { task_id: taskId };
|
|
89
89
|
}
|
|
90
|
-
else if (method === 'createTask' && options.title && options.project_id
|
|
90
|
+
else if (method === 'createTask' && options.title && options.project_id) {
|
|
91
91
|
const projectId = parseTaskId(options.project_id);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (projectId === null || ownerId === null || categoryId === null) {
|
|
95
|
-
outputCliError('PARAM_INVALID', '--project_id, --owner_id and --category_id must be positive integers');
|
|
92
|
+
if (projectId === null) {
|
|
93
|
+
outputCliError('PARAM_INVALID', '--project_id must be a positive integer');
|
|
96
94
|
return;
|
|
97
95
|
}
|
|
98
|
-
params = { title: options.title, project_id: projectId
|
|
96
|
+
params = { title: options.title, project_id: projectId };
|
|
97
|
+
// 可选快捷参数
|
|
98
|
+
if (options.owner_id) {
|
|
99
|
+
const ownerId = parseTaskId(options.owner_id);
|
|
100
|
+
if (ownerId === null) {
|
|
101
|
+
outputCliError('PARAM_INVALID', '--owner_id must be a positive integer');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
params.owner_id = ownerId;
|
|
105
|
+
}
|
|
106
|
+
if (options.category_id) {
|
|
107
|
+
const categoryId = parseTaskId(options.category_id);
|
|
108
|
+
if (categoryId === null) {
|
|
109
|
+
outputCliError('PARAM_INVALID', '--category_id must be a positive integer');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
params.category_id = categoryId;
|
|
113
|
+
}
|
|
99
114
|
}
|
|
100
115
|
else if (method === 'searchTasks' && options.project_id && options.query) {
|
|
101
116
|
const projectId = parseTaskId(options.project_id);
|
|
@@ -225,7 +240,7 @@ export function createKbAction(method) {
|
|
|
225
240
|
else {
|
|
226
241
|
const shortcuts = {
|
|
227
242
|
getTask: '--task_id',
|
|
228
|
-
createTask: '--title
|
|
243
|
+
createTask: '--title and --project_id',
|
|
229
244
|
searchTasks: '--project_id and --query',
|
|
230
245
|
searchSubtasks: '--project_id, --iteration_id, --user_id, --page',
|
|
231
246
|
getAllActiveIterations: '--project_id',
|
|
@@ -38,15 +38,15 @@ const kbService = {
|
|
|
38
38
|
.option('--user <user>', 'Specify user')
|
|
39
39
|
.option('--gateway <url>', 'Override kanboard gateway')
|
|
40
40
|
.action(createKbAction('getTask'));
|
|
41
|
-
// createTask 支持快捷参数 --title / --project_id
|
|
41
|
+
// createTask 支持快捷参数 --title / --project_id(必填),--owner_id / --category_id(可选),且 --params 仍然可用
|
|
42
42
|
cmd
|
|
43
43
|
.command('createTask')
|
|
44
44
|
.description(METHOD_DESCRIPTIONS.createTask)
|
|
45
45
|
.option('--params <json>', 'JSON/JSON5 params; CLI fills jsonrpc/method/id')
|
|
46
|
-
.option('--title <title>', 'Task title (shortcut)')
|
|
47
|
-
.option('--project_id <id>', 'Project ID (shortcut)')
|
|
48
|
-
.option('--owner_id <id>', 'Owner user ID (shortcut)')
|
|
49
|
-
.option('--category_id <id>', 'Category ID (shortcut)')
|
|
46
|
+
.option('--title <title>', 'Task title (shortcut, required)')
|
|
47
|
+
.option('--project_id <id>', 'Project ID (shortcut, required)')
|
|
48
|
+
.option('--owner_id <id>', 'Owner user ID (shortcut, optional)')
|
|
49
|
+
.option('--category_id <id>', 'Category ID (shortcut, optional)')
|
|
50
50
|
.option('--user <user>', 'Specify user')
|
|
51
51
|
.option('--gateway <url>', 'Override kanboard gateway')
|
|
52
52
|
.action(createKbAction('createTask'));
|
|
@@ -36,15 +36,22 @@ export const PARAM_DEFS = {
|
|
|
36
36
|
],
|
|
37
37
|
// 写入方法
|
|
38
38
|
createTask: [
|
|
39
|
-
{ name: 'title', type: 'string', required: true, description: '
|
|
40
|
-
{ name: 'project_id', type: 'integer', required: true, description: '
|
|
41
|
-
{ name: '
|
|
42
|
-
{ name: '
|
|
43
|
-
{ name: '
|
|
44
|
-
{ name: 'category_id', type: 'integer', required:
|
|
45
|
-
{ name: 'iteration_id', type: 'integer', required: false, description: '迭代 ID' },
|
|
46
|
-
{ name: '
|
|
39
|
+
{ name: 'title', type: 'string', required: true, description: '需求/bug 标题' },
|
|
40
|
+
{ name: 'project_id', type: 'integer', required: true, description: '所属项目 ID。接口按项目检查创建权限。' },
|
|
41
|
+
{ name: 'description', type: 'string', required: false, description: '描述内容' },
|
|
42
|
+
{ name: 'owner_id', type: 'integer', required: false, description: '处理人 Kanboard 用户 ID。处理人必须可分配到该项目。' },
|
|
43
|
+
{ name: 'creator_id', type: 'integer', required: false, description: '创建人 Kanboard 用户 ID。登录态存在时创建人会使用当前用户。' },
|
|
44
|
+
{ name: 'category_id', type: 'integer', required: false, description: '分类 ID。服务端会根据分类和 bug 类型选择泳道。' },
|
|
45
|
+
{ name: 'iteration_id', type: 'integer', required: false, description: '迭代 ID;未传或为 0 时由服务端选择需求池或首个迭代。' },
|
|
46
|
+
{ name: 'date_due', type: 'string', required: false, description: '截止日期,建议使用 YYYY-MM-DD' },
|
|
47
|
+
{ name: 'date_started', type: 'string', required: false, description: '开始日期,建议使用 YYYY-MM-DD' },
|
|
48
|
+
{ name: 'priority', type: 'integer', required: false, description: '优先级' },
|
|
49
|
+
{ name: 'score', type: 'integer', required: false, description: '复杂度/分值' },
|
|
50
|
+
{ name: 'tags', type: 'array<string>', required: false, description: '标签列表,例如 ["Meet", "Sky", "Co"]' },
|
|
47
51
|
{ name: 'cc_id', type: 'array<string>', required: false, description: '抄送人列表。数组元素格式为 用户ID-用户名称,例如 ["22-Alice", "33-Bob"];未传时不设置抄送人。' },
|
|
52
|
+
{ name: 'is_bug', type: 'integer', required: false, description: '是否为 bug,1 表示 bug,0 表示需求' },
|
|
53
|
+
{ name: 'platform', type: 'string', required: false, description: 'bug 平台,例如 Server,未传时保存为空字符串' },
|
|
54
|
+
{ name: 'related_task_id', type: 'integer', required: false, description: '关联需求 ID。创建 bug 时可传入对应的需求 ID,建立 bug 与需求的关联;未传时不关联。' },
|
|
48
55
|
],
|
|
49
56
|
createSubtask: [
|
|
50
57
|
{ name: 'task_id', type: 'integer', required: true, description: '父需求/bug ID' },
|
|
@@ -56,23 +63,34 @@ export const PARAM_DEFS = {
|
|
|
56
63
|
],
|
|
57
64
|
updateTask: [
|
|
58
65
|
{ name: 'id', type: 'integer', required: true, description: '需求/bug ID' },
|
|
59
|
-
{ name: 'title', type: 'string', required: false, description: '
|
|
60
|
-
{ name: '
|
|
61
|
-
{ name: '
|
|
66
|
+
{ name: 'title', type: 'string', required: false, description: '标题' },
|
|
67
|
+
{ name: 'description', type: 'string', required: false, description: '描述,支持 Kanboard 当前配置下的 Markdown/文本内容。' },
|
|
68
|
+
{ name: 'owner_id', type: 'integer', required: false, description: '处理人用户 ID。目标用户必须可分配到该项目。' },
|
|
62
69
|
{ name: 'category_id', type: 'integer', required: false, description: '分类 ID' },
|
|
63
|
-
{ name: 'iteration_id', type: 'integer', required: false, description: '迭代 ID' },
|
|
64
|
-
{ name: '
|
|
70
|
+
{ name: 'iteration_id', type: 'integer', required: false, description: '迭代 ID。传入后修改需求/bug 所属迭代;未传时保持原迭代不变。' },
|
|
71
|
+
{ name: 'date_due', type: 'string', required: false, description: '截止日期,建议使用 YYYY-MM-DD' },
|
|
72
|
+
{ name: 'date_started', type: 'string', required: false, description: '开始日期,建议使用 YYYY-MM-DD' },
|
|
73
|
+
{ name: 'priority', type: 'integer', required: false, description: '优先级' },
|
|
74
|
+
{ name: 'score', type: 'integer', required: false, description: '复杂度/分值' },
|
|
75
|
+
{ name: 'color_id', type: 'string', required: false, description: '颜色 ID,例如 yellow、blue、green' },
|
|
76
|
+
{ name: 'reference', type: 'string', required: false, description: '外部引用编号' },
|
|
77
|
+
{ name: 'tags', type: 'array<string>', required: false, description: '标签列表,例如 ["Meet", "Sky", "Co"]' },
|
|
65
78
|
{ name: 'cc_id', type: 'array<string>', required: false, description: '抄送人列表。数组元素格式为 用户ID-用户名称,例如 ["22-Alice", "33-Bob"];传空数组 [] 表示清空抄送人,未传则保持不变。' },
|
|
79
|
+
{ name: 'related_task_id', type: 'integer', required: false, description: '修改 bug 时可传入要关联的需求 ID。仅当前任务是 bug 时生效;目标必须是已存在的需求(is_bug = 0)。' },
|
|
80
|
+
{ name: 'time_spent', type: 'number', required: false, description: '已花费时间' },
|
|
81
|
+
{ name: 'time_estimated', type: 'number', required: false, description: '预估时间' },
|
|
66
82
|
],
|
|
67
83
|
updateSubtask: [
|
|
68
84
|
{ name: 'id', type: 'integer', required: true, description: '子任务 ID' },
|
|
69
|
-
{ name: 'task_id', type: 'integer', required: true, description: '父需求/bug ID' },
|
|
85
|
+
{ name: 'task_id', type: 'integer', required: true, description: '父需求/bug ID。接口按该任务检查项目权限。' },
|
|
70
86
|
{ name: 'title', type: 'string', required: false, description: '子任务标题' },
|
|
71
|
-
{ name: 'user_id', type: 'integer', required: false, description: '
|
|
72
|
-
{ name: 'time_estimated', type: 'number', required: false, description: '
|
|
73
|
-
{ name: 'time_spent', type: 'number', required: false, description: '
|
|
74
|
-
{ name: 'status', type: 'integer', required: false, description: '
|
|
87
|
+
{ name: 'user_id', type: 'integer', required: false, description: '子任务处理人 Kanboard 用户 ID。传 0 表示未分配。' },
|
|
88
|
+
{ name: 'time_estimated', type: 'number', required: false, description: '预估时间,最多保留两位小数' },
|
|
89
|
+
{ name: 'time_spent', type: 'number', required: false, description: '已花费时间,最多保留两位小数' },
|
|
90
|
+
{ name: 'status', type: 'integer', required: false, description: '子任务状态:0 未开始,1 进行中,2 已完成' },
|
|
75
91
|
{ name: 'position', type: 'integer', required: false, description: '子任务排序位置' },
|
|
92
|
+
{ name: 'plan_begin_time', type: 'string', required: false, description: '计划开始时间,格式 YYYY-MM-DD' },
|
|
93
|
+
{ name: 'plan_end_time', type: 'string', required: false, description: '计划结束时间,格式 YYYY-MM-DD' },
|
|
76
94
|
],
|
|
77
95
|
createComment: [
|
|
78
96
|
{ name: 'task_id', type: 'integer', required: true, description: '需求/bug ID' },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const METHOD_SHORTCUT_PARAMS = {
|
|
2
2
|
getTask: ['task_id'],
|
|
3
|
-
createTask: ['title', 'project_id'
|
|
3
|
+
createTask: ['title', 'project_id'],
|
|
4
4
|
searchTasks: ['project_id', 'query'],
|
|
5
5
|
searchSubtasks: ['project_id', 'iteration_id', 'user_id', 'page'],
|
|
6
6
|
getAllActiveIterations: ['project_id'],
|