更新代码仓库相关功能,修改 API 参数,添加删除仓库功能,更新文档和测试用例

This commit is contained in:
xiongxiao
2026-01-16 03:46:14 +08:00
parent d85f42d38b
commit f10f588ea5
10 changed files with 208 additions and 45 deletions

View File

@@ -6,9 +6,8 @@ import { nanoid } from 'nanoid';
export const config = useConfig()
export const cnb = useContextKey<CNB>('cnb', () => {
const token = useKey('CNB_TOKEN') as string
const token = useKey('CNB_API_KEY') as string
const cookie = useKey('CNB_COOKIE') as string
return new CNB({ token: token, cookie: cookie });
})
export const appId = nanoid();

View File

@@ -3,6 +3,7 @@ import { type Plugin } from "@opencode-ai/plugin"
import { app, cnb, appId } from './index.ts';
import { } from 'es-toolkit'
import { Skill } from "@kevisual/router";
const routes = app.routes.filter(r => {
const metadata = r.metadata as Skill
if (metadata && metadata.tags && metadata.tags.includes('opencode')) {
@@ -10,30 +11,46 @@ const routes = app.routes.filter(r => {
}
return false
})
const toolSkills = routes.reduce((acc, route) => {
const metadata = route.metadata as Skill
acc[metadata.skill!] = {
name: metadata.title || metadata.skill,
description: metadata.summary || '',
args: metadata.args || {},
async execute(args: Record<string, any>) {
const res = await app.run({
path: route.path,
key: route.key,
payload: args
}, { appId });
return res.data?.content || res.data || res;
}
}
return acc;
}, {} as Record<string, any>);
console.log('CnbPlugin loaded skills:', Object.keys(toolSkills));
// opencode run "请使用 cnb-login-verify 工具验证登录信信息,检查cookie"
export const CnbPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
'tool': {
...toolSkills
...routes.reduce((acc, route) => {
const metadata = route.metadata as Skill
acc[metadata.skill!] = {
name: metadata.title || metadata.skill,
description: metadata.summary || '',
args: metadata.args || {},
async execute(args: Record<string, any>) {
console.log(`Executing skill ${metadata.skill} with args:`, args);
await client.app.log({
body: {
service: 'cnb',
level: 'info',
message: `Executing skill ${metadata.skill} with args: ${JSON.stringify(args)}`
}
});
const res = await app.run({
path: route.path,
key: route.key,
payload: args
}, { appId });
if (res.code === 200) {
if (res.data?.content) {
return res.data.content;
}
const str = JSON.stringify(res.data || res, null, 2);
if (str.length > 5000) {
return str.slice(0, 5000) + '... (truncated)';
}
return str;
}
return `Error: ${res?.message || '无法获取结果'}`;
}
}
return acc;
}, {} as Record<string, any>)
},
'tool.execute.before': async (opts) => {
// console.log('CnbPlugin: tool.execute.before', opts.tool);

View File

@@ -12,7 +12,8 @@ app.route({
skill: 'create-repo',
title: '创建代码仓库',
args: {
name: tool.schema.string().describe('代码仓库名称'),
name: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
visibility: tool.schema.string().describe('代码仓库可见性, public 或 private').default('public'),
description: tool.schema.string().describe('代码仓库描述'),
},
summary: '创建一个新的代码仓库',
@@ -20,14 +21,14 @@ app.route({
}
}).define(async (ctx) => {
const name = ctx.query?.name;
const visibility = ctx.query?.visibility ?? 'private';
const visibility = ctx.query?.visibility ?? 'public';
const description = ctx.query?.description ?? '';
if (!name) {
ctx.throw(400, '缺少参数 name');
}
const res = await cnb.repo.createRepo(cnb.group, {
const res = await cnb.repo.createRepo({
name,
visibility,
description,
@@ -38,7 +39,7 @@ app.route({
app.route({
path: 'cnb',
key: 'create-repo-file',
description: '在代码仓库中创建文件, 参数repoName, path, content, encoding',
description: '在代码仓库中创建文件, name, path, content, encoding',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
@@ -46,7 +47,7 @@ app.route({
skill: 'create-repo-file',
title: '在代码仓库中创建文件',
args: {
repoName: tool.schema.string().describe('代码仓库名称'),
name: tool.schema.string().describe('代码仓库名称'),
path: tool.schema.string().describe('文件路径, 如 src/index.ts'),
content: tool.schema.string().describe('文件内容'),
encoding: tool.schema.string().describe('编码方式, 默认为 raw').optional(),
@@ -55,20 +56,48 @@ app.route({
})
}
}).define(async (ctx) => {
const repoName = ctx.query?.repoName;
const name = ctx.query?.name;
const path = ctx.query?.path;
const content = ctx.query?.content;
const encoding = ctx.query?.encoding ?? 'raw';
if (!repoName || !path || !content) {
ctx.throw(400, '缺少参数 repoName, path 或 content');
if (!name || !path || !content) {
ctx.throw(400, '缺少参数 name, path 或 content');
}
const res = await cnb.repo.createCommit(repoName, {
const res = await cnb.repo.createCommit(name, {
message: `添加文件 ${path} 通过 API `,
files: [
{ path, content, encoding },
],
});
ctx.forward(res);
}).addTo(app);
app.route({
path: 'cnb',
key: 'delete-repo',
description: '删除代码仓库, 参数name',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'delete-repo',
title: '删除代码仓库',
args: {
name: tool.schema.string().describe('代码仓库名称'),
},
summary: '删除一个代码仓库',
})
}
}).define(async (ctx) => {
const name = ctx.query?.name;
if (!name) {
ctx.throw(400, '缺少参数 name');
}
const res = await cnb.repo.deleteRepo(name);
ctx.forward(res);
}).addTo(app);