This commit is contained in:
2026-01-12 03:16:35 +08:00
parent c2dcc53018
commit 5310ff28ae
48 changed files with 1349 additions and 254 deletions

14
agent/app.ts Normal file
View File

@@ -0,0 +1,14 @@
import { QueryRouterServer as App } from '@kevisual/router'
import { useContextKey } from '@kevisual/context'
import { useConfig } from '@kevisual/use-config'
import { CNB } from '../src/index.ts';
import { nanoid } from 'nanoid';
export const config = useConfig()
export const cnb = useContextKey<CNB>('cnb', () => {
return new CNB({ token: config.CNB_TOKEN, cookie: config.CNB_COOKIE, group: config.CNB_GROUP });
})
export const appId = nanoid();
export const app = useContextKey<App>('app', () => {
return new App()
})

2
agent/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './app.ts'
import './routes/index.ts'

35
agent/opencode-plugin.ts Normal file
View File

@@ -0,0 +1,35 @@
import { tool } from "@opencode-ai/plugin/tool"
import { type Plugin } from "@opencode-ai/plugin"
import { app, cnb, appId } from './index.ts';
// opencode run "请使用 cnb-login-verify 工具验证登录信信息,检查cookie"
export const CnbPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
'tool': {
"cnb-login-verify": {
name: "CNB 登录验证信息",
description: "验证 CNB 登录信息是否有效",
args: {
checkToken: tool.schema.boolean().describe("是否检查 Token 的有效性").default(true),
checkCookie: tool.schema.boolean().describe("是否检查 Cookie 的有效性").default(false),
},
async execute(args) {
const res = await app.run({
path: 'cnb',
key: 'user-check',
payload: {
...args
}
}, { appId });
if (res.code === 200) {
return res.data?.output;
}
return '无法获取登录状态,请检查配置。';
},
},
},
'tool.execute.before': async (opts) => {
// console.log('CnbPlugin: tool.execute.before', opts.tool);
}
}
}

View File

@@ -0,0 +1 @@
// 根据环境变量获取当前的 cnb 启动环境

36
agent/routes/index.ts Normal file
View File

@@ -0,0 +1,36 @@
import { app, appId } from '@/agent/app.ts';
import './user/check.ts'
const checkAppId = (ctx: any, appId: string) => {
const _appId = ctx?.appId;
if (_appId) {
if (_appId !== appId) {
ctx.throw(403, 'Invalid App ID');
}
return true;
}
return false;
}
if (!app.hasRoute('auth')) {
app.route({
id: 'auth',
path: 'auth',
}).define(async (ctx) => {
// ctx.body = 'Auth Route';
if (checkAppId(ctx, appId)) {
return;
}
}).addTo(app);
app.route({
id: 'admin-auth',
path: 'admin-auth',
middleware: ['auth'],
}).define(async (ctx) => {
// ctx.body = 'Admin Auth Route';
if (checkAppId(ctx, appId)) {
return;
}
}).addTo(app);
}

View File

@@ -0,0 +1,53 @@
import { app, cnb } from '@/agent/app.ts';
app.route({
path: 'cnb',
key: 'repo-create',
description: '创建代码仓库, 参数name, visibility, description',
middleware: ['auth'],
metadata: {
tags: ['opencode']
}
}).define(async (ctx) => {
const name = ctx.query?.name;
const visibility = ctx.query?.visibility ?? 'private';
const description = ctx.query?.description ?? '';
if (!name) {
ctx.throw(400, '缺少参数 name');
}
const res = await cnb.repo.createRepo(cnb.group, {
name,
visibility,
description,
});
ctx.forward(res);
}).addTo(app);
app.route({
path: 'cnb',
key: 'repo-create-file',
description: '在代码仓库中创建文件, 参数repoName, path, content, encoding',
middleware: ['auth'],
metadata: {
tags: ['opencode']
}
}).define(async (ctx) => {
const repoName = ctx.query?.repoName;
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');
}
const res = await cnb.repo.createCommit(repoName, {
message: `添加文件 ${path} 通过 API `,
files: [
{ path, content, encoding },
],
});
ctx.forward(res);
}).addTo(app);

View File

@@ -0,0 +1,33 @@
import { app, cnb } from '@/agent/app.ts';
app.route({
path: 'cnb',
key: 'user-check',
description: '检查用户登录状态参数checkToken,default true; checkCookie, default false',
middleware: ['auth'],
metadata: {
tags: ['opencode']
}
}).define(async (ctx) => {
const checkToken = ctx.query?.checkToken ?? true;
const checkCookie = ctx.query?.checkCookie ?? false;
let output = '';
if (checkToken) {
const res = await cnb.user.getUser();
if (res?.code !== 200) {
output += `Token 无效,请检查 CNB_TOKEN 配置。\n`;
} else {
output += `Token 有效Token用户昵称${res.data?.nickname}\n`;
}
}
if (checkCookie) {
const res = await cnb.user.getCurrentUser();
if (res?.code !== 200) {
output += `Cookie 无效,请检查 CNB_COOKIE 配置。\n`;
} else {
output += `Cookie 有效当前Cookie用户${res.data?.nickname}\n`;
}
}
ctx.body = { output };
}).addTo(app);

View File

@@ -0,0 +1,23 @@
import { app, cnb } from '@/agent/app.ts';
app.route({
path: 'cnb',
key: 'start-workspace',
description: '启动开发工作空间, 参数 repo',
middleware: ['auth'],
metadata: {
tags: ['opencode']
}
}).define(async (ctx) => {
const repo = ctx.query?.repo;
const branch = ctx.query?.branch;
const ref = ctx.query?.ref;
if (!repo) {
ctx.throw(400, '缺少参数 repo');
}
const res = await cnb.workspace.startWorkspace(repo, {
branch,
ref
});
ctx.forward(res);
}).addTo(app);