Files
cnb/agent/routes/workspace/index.ts
xiongxiao 50332fe2f4 feat: update package dependencies and add new routes for CNB environment management
- Updated package.json and pnpm-lock.yaml with new dependencies and versions.
- Removed outdated readme files from requirements.
- Enhanced CNB environment configuration in cnb-env.ts with new VS Code remote SSH settings.
- Modified KnowledgeBase class to return structured results.
- Updated Workspace class to return structured results.
- Implemented new routes for managing CNB cookies and VS Code proxy URIs.
- Added AI chat functionality for querying knowledge base.
- Created skills for cleaning up closed workspaces.
2026-01-27 04:02:34 +08:00

168 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import z from 'zod';
import './skills.ts';
// 启动工作空间
app.route({
path: 'cnb',
key: 'start-workspace',
description: '启动开发工作空间, 参数 repo',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'start-workspace',
title: '启动cnb工作空间',
summary: '启动cnb工作空间',
args: {
repo: tool.schema.string().describe('代码仓库路径,例如 user/repo'),
branch: tool.schema.string().optional().describe('分支名称,默认主分支'),
ref: tool.schema.string().optional().describe('提交引用,例如 commit sha'),
},
})
}
}).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);
// 获取cnb工作空间列表
app.route({
path: 'cnb',
key: 'list-workspace',
description: '获取cnb开发工作空间列表可选参数 status=running 获取运行中的环境',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'list-workspace',
title: '列出cnb工作空间',
summary: '列出cnb工作空间列表支持按状态过滤 status 可选值 running 或 closed',
args: {
status: tool.schema.string().optional().describe('开发环境状态running: 运行中closed: 已关闭和停止的'),
page: tool.schema.number().optional().describe('分页页码,默认 1'),
pageSize: tool.schema.number().optional().describe('分页大小,默认 20最大 100'),
slug: tool.schema.string().optional().describe('仓库路径,例如 groupname/reponame'),
branch: tool.schema.string().optional().describe('分支名称'),
},
})
}
}).define(async (ctx) => {
const { status = 'running', page, pageSize, slug, branch } = ctx.query || {};
const res = await cnb.workspace.list({
status: status as 'running' | 'closed' | undefined,
page: page ?? 1,
pageSize: pageSize ?? 100,
});
ctx.forward({ code: 200, message: 'success', data: res });
}).addTo(app);
// 获取工作空间详情
app.route({
path: 'cnb',
key: 'get-workspace',
description: '获取工作空间详情,通过 repo 和 sn 获取',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'get-workspace',
title: '获取工作空间详情',
summary: '获取工作空间详细信息',
args: {
repo: tool.schema.string().describe('代码仓库路径,例如 user/repo'),
sn: tool.schema.string().describe('工作空间流水线的 sn'),
},
})
}
}).define(async (ctx) => {
const repo = ctx.query?.repo;
const sn = ctx.query?.sn;
if (!repo) {
ctx.throw(400, '缺少参数 repo');
}
if (!sn) {
ctx.throw(400, '缺少参数 sn');
}
const res = await cnb.workspace.getDetail(repo, sn);
ctx.forward({ code: 200, message: 'success', data: res });
}).addTo(app);
// 删除工作空间
app.route({
path: 'cnb',
key: 'delete-workspace',
description: '删除工作空间,通过 pipelineId 或 sn',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'delete-workspace',
title: '删除工作空间',
summary: '删除工作空间pipelineId 和 sn 二选一',
args: {
pipelineId: tool.schema.string().optional().describe('流水线 ID优先使用'),
sn: tool.schema.string().optional().describe('流水线构建号'),
sns: tool.schema.array(z.string()).optional().describe('流水线构建号'),
},
})
}
}).define(async (ctx) => {
const pipelineId = ctx.query?.pipelineId;
const sn = ctx.query?.sn;
const sns = ctx.query?.sns;
if (!pipelineId && !sn && (!sns || sns.length === 0)) {
ctx.throw(400, 'pipelineId 和 sn 必须提供其中一个');
}
if (sns && sns.length > 0) {
const results = [];
for (const snItem of sns) {
const res = await cnb.workspace.deleteWorkspace({ sn: snItem });
results.push(res);
}
ctx.forward({ code: 200, message: 'success', data: results });
return;
}
const res = await cnb.workspace.deleteWorkspace({ pipelineId, sn });
ctx.forward(res);
}).addTo(app);
// 停止工作空间
app.route({
path: 'cnb',
key: 'stop-workspace',
description: '停止工作空间,通过 pipelineId 或 sn',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'stop-workspace',
title: '停止工作空间',
summary: '停止运行中的工作空间',
args: {
pipelineId: tool.schema.string().optional().describe('流水线 ID优先使用'),
sn: tool.schema.string().optional().describe('流水线构建号'),
},
})
}
}).define(async (ctx) => {
const pipelineId = ctx.query?.pipelineId;
const sn = ctx.query?.sn;
if (!pipelineId && !sn) {
ctx.throw(400, 'pipelineId 和 sn 必须提供其中一个');
}
const res = await cnb.workspace.stopWorkspace({ pipelineId, sn });
ctx.forward({ code: 200, message: 'success', data: res });
}).addTo(app);