添加仓库管理功能,包括创建、删除和列出代码仓库,更新依赖安装逻辑,修复环境变量配置
This commit is contained in:
@@ -109,6 +109,12 @@
|
|||||||
echo "文件不存在"
|
echo "文件不存在"
|
||||||
fi
|
fi
|
||||||
printenv > ~/.env
|
printenv > ~/.env
|
||||||
|
if [ -f "package.json" ]; then
|
||||||
|
echo "📦 开始安装前端页面"
|
||||||
|
pnpm install
|
||||||
|
else
|
||||||
|
echo "🔍 非前端项目,跳过安装"
|
||||||
|
fi
|
||||||
init_stages:
|
init_stages:
|
||||||
- name: '安装依赖'
|
- name: '安装依赖'
|
||||||
script: |
|
script: |
|
||||||
@@ -153,6 +159,7 @@
|
|||||||
include:
|
include:
|
||||||
- "docs/**.md"
|
- "docs/**.md"
|
||||||
- "blogs/**.md"
|
- "blogs/**.md"
|
||||||
|
- "data/**.md"
|
||||||
|
|
||||||
.dev_vscode_template: &dev_vscode_template
|
.dev_vscode_template: &dev_vscode_template
|
||||||
vscode:
|
vscode:
|
||||||
|
|||||||
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"code-runner.executorMap": {
|
||||||
|
"ts": "opencode run $selectedText"
|
||||||
|
},
|
||||||
|
"code-runner.runInTerminal": true
|
||||||
|
}
|
||||||
32
agent/routes/call/index.ts
Normal file
32
agent/routes/call/index.ts
Normal 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)
|
||||||
1
agent/routes/call/tempCodeRunnerFile.ts
Normal file
1
agent/routes/call/tempCodeRunnerFile.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
调用 path: cnb key: get-repo-list payload: { page: 1, per_page: 10 }
|
||||||
@@ -2,6 +2,8 @@ import { app, appId } from '../app.ts';
|
|||||||
import './user/check.ts'
|
import './user/check.ts'
|
||||||
import './repo/index.ts'
|
import './repo/index.ts'
|
||||||
import './workspace/index.ts'
|
import './workspace/index.ts'
|
||||||
|
import './call/index.ts'
|
||||||
|
|
||||||
import { isEqual } from 'es-toolkit'
|
import { isEqual } from 'es-toolkit'
|
||||||
/**
|
/**
|
||||||
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
|
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
|
||||||
|
|||||||
@@ -1,108 +1,2 @@
|
|||||||
import { app, cnb } from '../../app.ts';
|
import './list.ts'
|
||||||
import { createSkill, Skill } from '@kevisual/router'
|
import './repo.ts'
|
||||||
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);
|
|
||||||
37
agent/routes/repo/list.ts
Normal file
37
agent/routes/repo/list.ts
Normal 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
108
agent/routes/repo/repo.ts
Normal 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);
|
||||||
0
bun.config.ts
Normal file
0
bun.config.ts
Normal file
@@ -1,14 +0,0 @@
|
|||||||
import { CNB } from './src/index.ts';
|
|
||||||
|
|
||||||
const cnb = new CNB({
|
|
||||||
token: 'cIDfLOOIr1Trt15cdnwfndupEZG',
|
|
||||||
cookie: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const res = await cnb.repo.createRepo('kevisual', {
|
|
||||||
name: 'exam-kevisual',
|
|
||||||
description: 'exam repository for kevisual',
|
|
||||||
visibility: 'public'
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Result:', JSON.stringify(res, null, 2));
|
|
||||||
@@ -89,10 +89,15 @@ export class Repo extends CNBCore {
|
|||||||
}): Promise<Result<RepoItem[]>> {
|
}): Promise<Result<RepoItem[]>> {
|
||||||
const url = '/user/repos';
|
const url = '/user/repos';
|
||||||
let _params = {
|
let _params = {
|
||||||
|
role: 'developer',
|
||||||
|
status: 'active',
|
||||||
...params,
|
...params,
|
||||||
page: params.page || 1,
|
page: params.page || 1,
|
||||||
page_size: params.page_size || 999,
|
page_size: params.page_size || 999,
|
||||||
}
|
}
|
||||||
|
if(!_params.search) {
|
||||||
|
delete _params.search;
|
||||||
|
}
|
||||||
return this.get({ url, params: _params });
|
return this.get({ url, params: _params });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import dotenv from "dotenv";
|
|||||||
import util from 'node:util';
|
import util from 'node:util';
|
||||||
import { useConfig, useKey } from "@kevisual/use-config";
|
import { useConfig, useKey } from "@kevisual/use-config";
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
export const token = useKey("CNB_TOKEN") as string || '';
|
export const token = useKey("CNB_API_KEY") as string || '';
|
||||||
export const cookie = useKey("CNB_COOKIE") as string || '';
|
export const cookie = useKey("CNB_COOKIE") as string || '';
|
||||||
console.log('token', token)
|
console.log('token', token)
|
||||||
import { app } from '../agent/index.ts'
|
import { app } from '../agent/index.ts'
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ import { token, showMore, cookie } from "./common.ts";
|
|||||||
const repo = new Repo({ token: token, cookie: cookie });
|
const repo = new Repo({ token: token, cookie: cookie });
|
||||||
|
|
||||||
|
|
||||||
const listRes = await repo.getRepoList({ page: 1, page_size: 10 });
|
const listRes = await repo.getRepoList({ page: 1, page_size: 999, role: 'developer' });
|
||||||
|
|
||||||
console.log("listRes", showMore(listRes));
|
console.log("listRes", showMore(listRes), listRes.data?.length);
|
||||||
Reference in New Issue
Block a user