feat: 更新依赖项,添加 OpenCode 支持,重构代理和路由逻辑,新增 AGENTS 文档
This commit is contained in:
6
assistant/src/main.ts
Normal file
6
assistant/src/main.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { app, assistantConfig } from './app.ts';
|
||||
|
||||
import './routes/index.ts';
|
||||
import './routes-simple/index.ts';
|
||||
|
||||
export { app, assistantConfig };
|
||||
@@ -9,8 +9,11 @@ import './user/index.ts';
|
||||
// TODO: 移除
|
||||
// import './hot-api/key-sender/index.ts';
|
||||
|
||||
import './opencode/index.ts';
|
||||
|
||||
import os from 'node:os';
|
||||
import { authCache } from '@/module/cache/auth.ts';
|
||||
import { createSkill } from '@kevisual/router';
|
||||
const getTokenUser = async (token: string) => {
|
||||
const query = assistantConfig.query
|
||||
const res = await query.post({
|
||||
@@ -101,6 +104,9 @@ app
|
||||
description: '获取当前登录用户信息, 第一个登录的用户为管理员用户',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
if (!ctx.query?.token && ctx.appId === app.appId) {
|
||||
return;
|
||||
}
|
||||
const authResult = await checkAuth(ctx);
|
||||
if (authResult.code !== 200) {
|
||||
ctx.throw(authResult.code, authResult.message);
|
||||
@@ -115,6 +121,9 @@ app
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
console.log('query', ctx.query);
|
||||
if (!ctx.query?.token && ctx.appId === app.appId) {
|
||||
return;
|
||||
}
|
||||
const authResult = await checkAuth(ctx, true);
|
||||
if (authResult.code !== 200) {
|
||||
ctx.throw(authResult.code, authResult.message);
|
||||
@@ -152,6 +161,14 @@ app
|
||||
path: 'client',
|
||||
key: 'system',
|
||||
description: '获取系统信息',
|
||||
metadata: {
|
||||
tags: ['opencode'],
|
||||
...createSkill({
|
||||
skill: 'view-system-info',
|
||||
title: '查看系统信息',
|
||||
summary: '获取服务器操作系统平台、架构和版本信息',
|
||||
})
|
||||
}
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const { platform, arch, release } = os;
|
||||
|
||||
1
assistant/src/routes/opencode/index.ts
Normal file
1
assistant/src/routes/opencode/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
import './ls.ts'
|
||||
40
assistant/src/routes/opencode/ls.ts
Normal file
40
assistant/src/routes/opencode/ls.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { useKey } from "@kevisual/use-config";
|
||||
import { app } from '@/app.ts'
|
||||
import { createSkill } from "@kevisual/router";
|
||||
import { opencodeManager } from './module/open.js'
|
||||
|
||||
app.route({
|
||||
path: 'opencode',
|
||||
key: 'create',
|
||||
middleware: ['auth'],
|
||||
description: '创建 OpenCode 客户端',
|
||||
metadata: {
|
||||
tags: ['opencode'],
|
||||
...createSkill({
|
||||
skill: 'create-opencode-client',
|
||||
title: '创建 OpenCode 客户端',
|
||||
summary: '创建 OpenCode 客户端,如果存在则复用',
|
||||
args: {
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
}).define(async (ctx) => {
|
||||
const client = await opencodeManager.getClient();
|
||||
ctx.body = { success: true, url: opencodeManager.url, message: 'OpenCode 客户端已就绪' };
|
||||
}).addTo(app);
|
||||
|
||||
// 调用 path: opencode key: ls-projects
|
||||
app.route({
|
||||
path: 'opencode',
|
||||
key: 'ls-projects'
|
||||
}).define(async (ctx) => {
|
||||
const client = await opencodeManager.getClient();
|
||||
const projects = await client.project.list();
|
||||
const currentProject = await client.project.current();
|
||||
ctx.body = {
|
||||
projects,
|
||||
currentProject
|
||||
};
|
||||
}).addTo(app);
|
||||
|
||||
56
assistant/src/routes/opencode/module/open.ts
Normal file
56
assistant/src/routes/opencode/module/open.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { createOpencode, OpencodeClient } from "@opencode-ai/sdk";
|
||||
|
||||
export class OpencodeManager {
|
||||
private static instance: OpencodeManager | null = null;
|
||||
private client: OpencodeClient | null = null;
|
||||
private server: { url: string; close(): void } | null = null;
|
||||
private isInitializing: boolean = false;
|
||||
|
||||
public url: string = '';
|
||||
private constructor() {}
|
||||
|
||||
static getInstance(): OpencodeManager {
|
||||
if (!OpencodeManager.instance) {
|
||||
OpencodeManager.instance = new OpencodeManager();
|
||||
}
|
||||
return OpencodeManager.instance;
|
||||
}
|
||||
|
||||
async getClient(): Promise<OpencodeClient> {
|
||||
// 如果已经有 client,直接返回
|
||||
if (this.client) {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
// 如果正在初始化,等待初始化完成
|
||||
if (this.isInitializing) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
return this.getClient();
|
||||
}
|
||||
|
||||
// 开始初始化
|
||||
this.isInitializing = true;
|
||||
try {
|
||||
const result = await createOpencode({
|
||||
hostname: '0.0.0.0',
|
||||
});
|
||||
console.log('OpencodeManager: OpenCode 服务已启动', result.server.url);
|
||||
this.url = result.server.url;
|
||||
this.client = result.client;
|
||||
this.server = result.server;
|
||||
return this.client;
|
||||
} finally {
|
||||
this.isInitializing = false;
|
||||
}
|
||||
}
|
||||
|
||||
close(): void {
|
||||
if (this.server) {
|
||||
this.server.close();
|
||||
this.server = null;
|
||||
}
|
||||
this.client = null;
|
||||
}
|
||||
}
|
||||
|
||||
export const opencodeManager = OpencodeManager.getInstance();
|
||||
@@ -111,6 +111,10 @@ export const proxyRoute = async (req: http.IncomingMessage, res: http.ServerResp
|
||||
logger.debug('handle by router', { url: req.url });
|
||||
return;
|
||||
}
|
||||
if (pathname.startsWith('/router') || pathname.startsWith('/opencode')) {
|
||||
logger.debug('handle by router (opencode/router)', { url: req.url });
|
||||
return;
|
||||
}
|
||||
// client, api, v1, serve 开头的拦截
|
||||
const apiProxy = _assistantConfig?.api?.proxy || [];
|
||||
const defaultApiProxy = createApiProxy(_assistantConfig?.app?.url || 'https://kevisual.cn');
|
||||
|
||||
Reference in New Issue
Block a user