feat: 重构为 Monorepo 架构并实现 HTTP Server
架构变更: - 采用 pnpm workspaces 实现 Monorepo 结构 - 将现有代码迁移到 packages/core - 新增 packages/server HTTP 服务层 Server 功能: - REST API: 会话管理、工具管理、配置管理 - WebSocket: 实时双向通信支持 - SSE: 服务端事件推送 - Hono + Bun 作为运行时 API 端点: - GET/POST /api/sessions - 会话 CRUD - GET/POST /api/sessions/:id/messages - 消息管理 - GET /api/sessions/:id/events - SSE 事件流 - WS /api/ws/:sessionId - WebSocket 连接 - GET/POST /api/tools - 工具管理 - GET/PUT /api/config - 配置管理
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
import type {
|
||||
AgentPermission,
|
||||
AgentFilePermission,
|
||||
AgentBashPermission,
|
||||
AgentGitPermission,
|
||||
PermissionAction,
|
||||
PermissionRule,
|
||||
} from './types.js';
|
||||
|
||||
/**
|
||||
* 系统默认权限配置
|
||||
*/
|
||||
export const SYSTEM_DEFAULT_PERMISSION: AgentPermission = {
|
||||
file: {
|
||||
read: 'allow',
|
||||
write: 'ask',
|
||||
edit: 'ask',
|
||||
delete: 'ask',
|
||||
},
|
||||
bash: {
|
||||
enabled: true,
|
||||
default: 'ask',
|
||||
rules: [
|
||||
// 安全命令
|
||||
{ pattern: 'ls *', action: 'allow' },
|
||||
{ pattern: 'pwd', action: 'allow' },
|
||||
{ pattern: 'cat *', action: 'allow' },
|
||||
{ pattern: 'head *', action: 'allow' },
|
||||
{ pattern: 'tail *', action: 'allow' },
|
||||
{ pattern: 'wc *', action: 'allow' },
|
||||
{ pattern: 'echo *', action: 'allow' },
|
||||
{ pattern: 'which *', action: 'allow' },
|
||||
{ pattern: 'type *', action: 'allow' },
|
||||
// 危险命令
|
||||
{ pattern: 'rm -rf *', action: 'deny' },
|
||||
{ pattern: 'rm -fr *', action: 'deny' },
|
||||
{ pattern: 'sudo *', action: 'deny' },
|
||||
{ pattern: 'chmod 777 *', action: 'deny' },
|
||||
],
|
||||
},
|
||||
web: 'ask',
|
||||
git: {
|
||||
read: 'allow',
|
||||
write: 'ask',
|
||||
dangerous: 'deny',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 合并单个权限值
|
||||
* 优先级: agent > global > system
|
||||
*/
|
||||
function mergeAction(
|
||||
system: PermissionAction | undefined,
|
||||
global: PermissionAction | undefined,
|
||||
agent: PermissionAction | undefined
|
||||
): PermissionAction {
|
||||
return agent ?? global ?? system ?? 'ask';
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并规则数组
|
||||
* Agent 规则优先,然后是 global,最后是 system
|
||||
*/
|
||||
function mergeRules(
|
||||
system: PermissionRule[] | undefined,
|
||||
global: PermissionRule[] | undefined,
|
||||
agent: PermissionRule[] | undefined
|
||||
): PermissionRule[] {
|
||||
return [
|
||||
...(agent ?? []),
|
||||
...(global ?? []),
|
||||
...(system ?? []),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并文件权限配置
|
||||
*/
|
||||
function mergeFilePermission(
|
||||
system: AgentFilePermission | undefined,
|
||||
global: AgentFilePermission | undefined,
|
||||
agent: AgentFilePermission | undefined
|
||||
): AgentFilePermission {
|
||||
return {
|
||||
read: mergeAction(system?.read, global?.read, agent?.read),
|
||||
write: mergeAction(system?.write, global?.write, agent?.write),
|
||||
edit: mergeAction(system?.edit, global?.edit, agent?.edit),
|
||||
delete: mergeAction(system?.delete, global?.delete, agent?.delete),
|
||||
sensitivePaths: mergeRules(
|
||||
system?.sensitivePaths,
|
||||
global?.sensitivePaths,
|
||||
agent?.sensitivePaths
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并 Bash 权限配置
|
||||
*/
|
||||
function mergeBashPermission(
|
||||
system: AgentBashPermission | undefined,
|
||||
global: AgentBashPermission | undefined,
|
||||
agent: AgentBashPermission | undefined
|
||||
): AgentBashPermission {
|
||||
// 如果 agent 显式禁用,直接返回
|
||||
if (agent?.enabled === false) {
|
||||
return { enabled: false };
|
||||
}
|
||||
|
||||
// 如果 global 禁用且 agent 没有覆盖
|
||||
if (global?.enabled === false && agent?.enabled === undefined) {
|
||||
return { enabled: false };
|
||||
}
|
||||
|
||||
return {
|
||||
enabled: agent?.enabled ?? global?.enabled ?? system?.enabled ?? true,
|
||||
rules: mergeRules(system?.rules, global?.rules, agent?.rules),
|
||||
default: mergeAction(system?.default, global?.default, agent?.default),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并 Git 权限配置
|
||||
*/
|
||||
function mergeGitPermission(
|
||||
system: AgentGitPermission | undefined,
|
||||
global: AgentGitPermission | undefined,
|
||||
agent: AgentGitPermission | undefined
|
||||
): AgentGitPermission {
|
||||
return {
|
||||
read: mergeAction(system?.read, global?.read, agent?.read),
|
||||
write: mergeAction(system?.write, global?.write, agent?.write),
|
||||
dangerous: mergeAction(system?.dangerous, global?.dangerous, agent?.dangerous),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并完整的权限配置
|
||||
* 优先级: Agent 配置 > 全局默认 > 系统默认
|
||||
*/
|
||||
export function mergePermissions(
|
||||
systemDefault: AgentPermission,
|
||||
globalConfig: AgentPermission | undefined,
|
||||
agentConfig: AgentPermission | undefined
|
||||
): AgentPermission {
|
||||
return {
|
||||
file: mergeFilePermission(
|
||||
systemDefault.file,
|
||||
globalConfig?.file,
|
||||
agentConfig?.file
|
||||
),
|
||||
bash: mergeBashPermission(
|
||||
systemDefault.bash,
|
||||
globalConfig?.bash,
|
||||
agentConfig?.bash
|
||||
),
|
||||
web: mergeAction(systemDefault.web, globalConfig?.web, agentConfig?.web),
|
||||
git: mergeGitPermission(
|
||||
systemDefault.git,
|
||||
globalConfig?.git,
|
||||
agentConfig?.git
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查命令是否匹配规则
|
||||
* 支持通配符 * 匹配任意字符
|
||||
*/
|
||||
export function matchRule(command: string, pattern: string): boolean {
|
||||
// 将通配符模式转换为正则表达式
|
||||
const regexPattern = pattern
|
||||
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // 转义特殊字符
|
||||
.replace(/\*/g, '.*') // * 转换为 .*
|
||||
.replace(/\?/g, '.'); // ? 转换为 .
|
||||
|
||||
const regex = new RegExp(`^${regexPattern}$`, 'i');
|
||||
return regex.test(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据规则列表检查命令权限
|
||||
*/
|
||||
export function checkBashPermission(
|
||||
command: string,
|
||||
permission: AgentBashPermission
|
||||
): PermissionAction {
|
||||
// 如果禁用,直接拒绝
|
||||
if (permission.enabled === false) {
|
||||
return 'deny';
|
||||
}
|
||||
|
||||
// 按顺序检查规则
|
||||
for (const rule of permission.rules ?? []) {
|
||||
if (matchRule(command, rule.pattern)) {
|
||||
return rule.action;
|
||||
}
|
||||
}
|
||||
|
||||
// 返回默认策略
|
||||
return permission.default ?? 'ask';
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据规则列表检查文件路径权限
|
||||
*/
|
||||
export function checkFilePathPermission(
|
||||
filePath: string,
|
||||
sensitivePaths: PermissionRule[] | undefined
|
||||
): PermissionAction | null {
|
||||
if (!sensitivePaths) return null;
|
||||
|
||||
for (const rule of sensitivePaths) {
|
||||
if (matchRule(filePath, rule.pattern)) {
|
||||
return rule.action;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user