添加仓库管理功能,包括创建、删除和列出代码仓库,更新依赖安装逻辑,修复环境变量配置

This commit is contained in:
xiongxiao
2026-01-19 04:10:20 +08:00
parent c099c7b67f
commit da7b06e519
13 changed files with 203 additions and 125 deletions

View File

@@ -0,0 +1,32 @@
import { createSkill } from '@kevisual/router'
import { app } from '../../app.ts'
import { tool } from '@opencode-ai/plugin/tool'
// "调用 path: cnb key: list-repos"
app.route({
path: 'call',
key: '',
description: '调用',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'call-app',
title: '调用app应用',
summary: '调用router的应用, 参数path, key, payload',
args: {
path: tool.schema.string().describe('应用路径,例如 cnb'),
key: tool.schema.string().optional().describe('应用key例如 list-repos'),
payload: tool.schema.object({}).optional().describe('调用参数'),
}
})
},
}).define(async (ctx) => {
const { path, key } = ctx.query;
console.log('call app', ctx.query);
if (!path) {
ctx.throw('路径path不能为空');
}
const res = await ctx.run({ path, key, payload: ctx.query.payload || {} });
ctx.forward(res);
}).addTo(app)

View File

@@ -0,0 +1 @@
path: cnb key: get-repo-list payload: { page: 1, per_page: 10 }

View File

@@ -2,6 +2,8 @@ import { app, appId } from '../app.ts';
import './user/check.ts'
import './repo/index.ts'
import './workspace/index.ts'
import './call/index.ts'
import { isEqual } from 'es-toolkit'
/**
* 验证上下文中的 App ID 是否与指定的 App ID 匹配

View File

@@ -1,108 +1,2 @@
import { app, cnb } from '../../app.ts';
import { createSkill, Skill } from '@kevisual/router'
import { tool } from "@opencode-ai/plugin/tool"
app.route({
path: 'cnb',
key: 'create-repo',
description: '创建代码仓库, 参数name, visibility, description',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'create-repo',
title: '创建代码仓库',
args: {
name: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
visibility: tool.schema.string().describe('代码仓库可见性, public 或 private').default('public'),
description: tool.schema.string().describe('代码仓库描述'),
},
summary: '创建一个新的代码仓库',
})
}
}).define(async (ctx) => {
const name = ctx.query?.name;
const visibility = ctx.query?.visibility ?? 'public';
const description = ctx.query?.description ?? '';
if (!name) {
ctx.throw(400, '缺少参数 name');
}
try {
const res = await cnb.repo.createRepo({
name,
visibility,
description,
});
ctx.forward(res);
} catch (error) {
ctx.code = 200
ctx.body = { content: 'JS仓库可能已存在' }
}
}).addTo(app);
app.route({
path: 'cnb',
key: 'create-repo-file',
description: '在代码仓库中创建文件, repoName, filePath, content, encoding',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'create-repo-file',
title: '在代码仓库中创建文件',
summary: `在代码仓库中创建文件, encoding 可选,默认 raw`,
args: {
repoName: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
filePath: tool.schema.string().describe('文件路径, 如 src/index.ts'),
content: tool.schema.string().describe('文本的字符串的内容'),
encoding: tool.schema.string().describe('编码方式,如 raw').optional(),
},
})
}
}).define(async (ctx) => {
const repoName = ctx.query?.repoName;
const filePath = ctx.query?.filePath;
const content = ctx.query?.content;
const encoding = ctx.query?.encoding ?? 'raw';
if (!repoName || !filePath || !content) {
ctx.throw(400, '缺少参数 repoName, filePath 或 content');
}
const res = await cnb.repo.createCommit(repoName, {
message: `添加文件 ${filePath} 通过 API `,
files: [
{ path: filePath, 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);
import './list.ts'
import './repo.ts'

37
agent/routes/repo/list.ts Normal file
View File

@@ -0,0 +1,37 @@
import { createSkill } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { tool } from "@opencode-ai/plugin/tool"
app.route({
path: 'cnb',
key: 'list-repos',
description: '列出我的代码仓库',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'list-repos',
title: '列出代码仓库',
summary: '列出代码仓库',
args: {
search: tool.schema.string().optional().describe('搜索关键词'),
pageSize: tool.schema.number().optional().describe('每页数量默认999'),
},
})
}
}).define(async (ctx) => {
const search = ctx.query?.search;
const pageSize = ctx.query?.pageSize || 9999;
const res = await cnb.repo.getRepoList({ search, page_size: pageSize, role: 'developer' });
if (res.code === 200) {
const repos = res.data.map((item) => ({
name: item.name,
path: item.path,
description: item.description,
web_url: item.web_url,
}));
ctx.body = { content: JSON.stringify(repos) };
} else {
ctx.throw(500, '获取仓库列表失败');
}
}).addTo(app);

108
agent/routes/repo/repo.ts Normal file
View File

@@ -0,0 +1,108 @@
import { app, cnb } from '../../app.ts';
import { createSkill, Skill } from '@kevisual/router'
import { tool } from "@opencode-ai/plugin/tool"
app.route({
path: 'cnb',
key: 'create-repo',
description: '创建代码仓库, 参数name, visibility, description',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'create-repo',
title: '创建代码仓库',
args: {
name: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
visibility: tool.schema.string().describe('代码仓库可见性, public 或 private').default('public'),
description: tool.schema.string().describe('代码仓库描述'),
},
summary: '创建一个新的代码仓库',
})
}
}).define(async (ctx) => {
const name = ctx.query?.name;
const visibility = ctx.query?.visibility ?? 'public';
const description = ctx.query?.description ?? '';
if (!name) {
ctx.throw(400, '缺少参数 name');
}
try {
const res = await cnb.repo.createRepo({
name,
visibility,
description,
});
ctx.forward(res);
} catch (error) {
ctx.code = 200
ctx.body = { content: 'JS仓库可能已存在' }
}
}).addTo(app);
app.route({
path: 'cnb',
key: 'create-repo-file',
description: '在代码仓库中创建文件, repoName, filePath, content, encoding',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'create-repo-file',
title: '在代码仓库中创建文件',
summary: `在代码仓库中创建文件, encoding 可选,默认 raw`,
args: {
repoName: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
filePath: tool.schema.string().describe('文件路径, 如 src/index.ts'),
content: tool.schema.string().describe('文本的字符串的内容'),
encoding: tool.schema.string().describe('编码方式,如 raw').optional(),
},
})
}
}).define(async (ctx) => {
const repoName = ctx.query?.repoName;
const filePath = ctx.query?.filePath;
const content = ctx.query?.content;
const encoding = ctx.query?.encoding ?? 'raw';
if (!repoName || !filePath || !content) {
ctx.throw(400, '缺少参数 repoName, filePath 或 content');
}
const res = await cnb.repo.createCommit(repoName, {
message: `添加文件 ${filePath} 通过 API `,
files: [
{ path: filePath, 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);