diff --git a/.cnb.yml b/.cnb.yml index cac0d77..877bf9b 100644 --- a/.cnb.yml +++ b/.cnb.yml @@ -8,6 +8,18 @@ include: imports: - https://cnb.cool/kevisual/env/-/blob/main/.env.development +.npc: &npc + - docker: + image: docker.cnb.cool/kevisual/dev-env/bun:latest + services: + - docker + env: !reference [.common_env, env] + imports: !reference [.common_env, imports] + stages: + - name: "task" + script: | + bun install + bun run agent/npc.ts $: vscode: - docker: @@ -18,15 +30,6 @@ $: env: !reference [.common_env, env] imports: !reference [.common_env, imports] - issue.comment@npc: - - docker: - image: docker.cnb.cool/kevisual/dev-env/bun:latest - services: - - docker - env: !reference [.common_env, env] - imports: !reference [.common_env, imports] - stages: - - name: "task" - script: | - bun install - bun run agent/npc.ts \ No newline at end of file + issue.comment@npc: *npc + issue.open@npc: *npc + issue.reopen@npc: *npc \ No newline at end of file diff --git a/agent/npc.ts b/agent/npc.ts index 051d1a7..73f7b20 100644 --- a/agent/npc.ts +++ b/agent/npc.ts @@ -3,6 +3,13 @@ import { app } from './index.ts'; import { useIssueEnv, useCommentEnv, useRepoInfoEnv } from '../src/index.ts' import { pick } from 'es-toolkit'; +const writeToProcess = (message: string) => { + if (process.send) { + process.send(message); + } else { + console.log(message); + } +} const main = async () => { const repoInfoEnv = useRepoInfoEnv(); const commentEnv = useCommentEnv(); @@ -10,10 +17,17 @@ const main = async () => { const pickCommentEnv = pick(commentEnv, ['commentId', 'commentIdLabel']); const pickIssueEnv = pick(issueEnv, ['issueId', 'issueIdLabel', 'issueIid', 'issueIidLabel', 'issueTitle', 'issueTitleLabel', 'issueDescription', 'issueDescriptionLabel']); const pickRepoInfoEnv = pick(repoInfoEnv, ['repoId', 'repoIdLabel', 'repoName', 'repoNameLabel', 'repoSlug', 'repoSlugLabel']); + const issueLabels = issueEnv.issueLabels || []; + const isComment = !!commentEnv.commentId; + if (!isComment && !issueLabels.includes('Run')) { + writeToProcess('当前 Issue 不包含 Run 标签,跳过执行'); + process.exit(0); + } + const messages = [ { role: 'system', - content: `你是一个智能的代码助手, 根据用户提供的上下文信息,提供有用的建议和帮助, 如果用户的要求和执行工具不一致,请说出你不能这么做。并把最后的结果提交一个评论到对应的issue中。用户提供的上下文信息如下:` + content: `你是一个智能的代码助手, 根据用户提供的上下文信息,提供有用的建议和帮助, 如果用户的要求和执行工具不一致,请说出你不能这么做。并把最后的结果提交一个评论到对应的issue中,提交的内容必须不能包含 @ 提及。用户提供的上下文信息如下:` }, { role: 'system', @@ -33,10 +47,11 @@ const main = async () => { }, { appId: app.appId }) if (result.code === 200) { let _message = result.data.message || [] - console.log('执行完成', JSON.stringify(_message, null, 2)) + writeToProcess('执行完成') + writeToProcess(JSON.stringify(_message, null, 2)) process.exit(0) } else { - console.log(result.message || '执行错误') + writeToProcess(result.message || '执行错误') process.exit(1) } } diff --git a/agent/routes/issues/comments.ts b/agent/routes/issues/comments.ts index fba0f82..f1d2ae3 100644 --- a/agent/routes/issues/comments.ts +++ b/agent/routes/issues/comments.ts @@ -59,6 +59,7 @@ app.route({ repo: tool.schema.string().optional().describe('代码仓库名称, 如 my-user/my-repo'), issueNumber: tool.schema.number().describe('Issue 编号'), body: tool.schema.string().describe('评论内容'), + clearAt: tool.schema.boolean().optional().describe('是否清除评论内容中的 @ 提及,默认: true'), }, summary: '创建 Issue 评论', }) @@ -67,7 +68,8 @@ app.route({ const cnb = await cnbManager.getContext(ctx); let repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE'); const issueNumber = ctx.query?.issueNumber; - const body = ctx.query?.body; + let body = ctx.query?.body; + const clearAt = ctx.query?.clearAt ?? true; if (!repo) { ctx.throw(400, '缺少参数 repo'); @@ -78,6 +80,10 @@ app.route({ if (!body) { ctx.throw(400, '缺少参数 body'); } + if (clearAt && body) { + // 清除评论内容中的 @ 提及 + body = body.replace(/@/g, ''); + } const res = await cnb.issue.createComment(repo, issueNumber, body); ctx.forward(res); @@ -138,6 +144,7 @@ app.route({ issueNumber: tool.schema.number().describe('Issue 编号'), commentId: tool.schema.number().describe('评论 ID'), body: tool.schema.string().describe('评论内容'), + clearAt: tool.schema.boolean().optional().describe('是否清除评论内容中的 @ 提及,默认: true'), }, summary: '修改 Issue 评论', }) @@ -147,8 +154,8 @@ app.route({ let repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE'); const issueNumber = ctx.query?.issueNumber; const commentId = ctx.query?.commentId; - const body = ctx.query?.body; - + let body = ctx.query?.body; + const clearAt = ctx.query?.clearAt ?? true; if (!repo) { ctx.throw(400, '缺少参数 repo'); } @@ -161,7 +168,10 @@ app.route({ if (!body) { ctx.throw(400, '缺少参数 body'); } - + if (clearAt && body) { + // 清除评论内容中的 @ 提及 + body = body.replace(/@/g, ''); + } const res = await cnb.issue.updateComment(repo, issueNumber, commentId, body); ctx.forward(res); }).addTo(app); diff --git a/src/issue/npc/env.ts b/src/issue/npc/env.ts index 4935280..15cbf23 100644 --- a/src/issue/npc/env.ts +++ b/src/issue/npc/env.ts @@ -182,10 +182,10 @@ export const useIssueEnv = () => { issueAssigneesLabel: "Issue 处理人列表", /** * @key CNB_ISSUE_LABELS - * @description:Issue 标签列表 + * @description:Issue 标签列表, 多个以 , 分隔。 */ issueLabels, - issueLabelsLabel: "Issue 标签列表", + issueLabelsLabel: "Issue 标签列表, 多个以 , 分隔。", /** * @key CNB_ISSUE_PRIORITY * @description:Issue 优先级