feat(issue): add body field to IssueItem type and implement issue creation and completion routes

- Added 'body' field to IssueItem type in index.ts
- Created new routes for issue creation and completion in issue.ts
- Implemented validation for required parameters in issue creation and completion
- Added a new list route for issues in list.ts
This commit is contained in:
xiongxiao
2026-01-29 02:50:28 +08:00
parent 8e1880a343
commit 20fcf2dca8
7 changed files with 648 additions and 44 deletions

View File

@@ -5,8 +5,8 @@ import './workspace/index.ts'
import './call/index.ts'
import './cnb-env/index.ts'
import './knowledge/index.ts'
import './issues/index.ts'
import { isEqual } from 'es-toolkit'
/**
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
* @param {any} ctx - 上下文对象,可能包含 appId 属性

View File

@@ -0,0 +1,2 @@
import './list.ts'
import './issue.ts'

View File

@@ -0,0 +1,80 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
// 创建cnb issue, 仓库为 kevisual/kevisual 标题为 "自动化测试创建issue", 内容为 "这是通过API创建的issue用于测试目的", body: "这是通过API创建的issue用于测试目的"
app.route({
path: 'cnb',
key: 'create-issue',
description: '创建 Issue, 参数 repo, title, body, assignees, labels, priority',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'create-issue',
title: '创建 Issue',
args: {
repo: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
title: tool.schema.string().describe('Issue 标题'),
body: tool.schema.string().optional().describe('Issue 描述内容'),
assignees: tool.schema.array(tool.schema.string()).optional().describe('指派人列表'),
labels: tool.schema.array(tool.schema.string()).optional().describe('标签列表'),
priority: tool.schema.string().optional().describe('优先级'),
},
summary: '创建一个新的 Issue',
})
}
}).define(async (ctx) => {
const repo = ctx.query?.repo;
const title = ctx.query?.title;
const body = ctx.query?.body;
const assignees = ctx.query?.assignees;
const labels = ctx.query?.labels;
const priority = ctx.query?.priority;
if (!repo || !title) {
ctx.throw(400, '缺少参数 repo 或 title');
}
const res = await cnb.issue.createIssue(repo, {
title,
body,
assignees,
labels,
priority,
});
ctx.forward(res);
}).addTo(app);
// 完成 issue 8 仓库是 kevisual/kevisaul
app.route({
path: 'cnb',
key: 'complete-issue',
description: '完成 Issue, 参数 repo, issueNumber',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'complete-issue',
title: '完成 Issue',
args: {
repo: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
issueNumber: tool.schema.union([tool.schema.string(), tool.schema.number()]).describe('Issue 编号'),
state: tool.schema.string().optional().describe('Issue 状态,默认为 closed'),
},
summary: '完成一个 Issue将 state 改为 closed',
})
}
}).define(async (ctx) => {
const repo = ctx.query?.repo;
const issueNumber = ctx.query?.issueNumber;
const state = ctx.query?.state ?? 'closed';
if (!repo || !issueNumber) {
ctx.throw(400, '缺少参数 repo 或 issueNumber');
}
const res = await cnb.issue.updateIssue(repo, issueNumber, {
state: state,
});
ctx.forward(res);
}).addTo(app);

View File

@@ -0,0 +1,3 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';