@seandong/seno 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/dist/agent/conversation.d.ts +39 -0
- package/dist/agent/conversation.js +60 -0
- package/dist/agent/conversation.js.map +1 -0
- package/dist/agent/loop.d.ts +41 -0
- package/dist/agent/loop.js +203 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/session.d.ts +63 -0
- package/dist/agent/session.js +135 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/cli/commands.d.ts +52 -0
- package/dist/cli/commands.js +667 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/logger.d.ts +38 -0
- package/dist/cli/logger.js +79 -0
- package/dist/cli/logger.js.map +1 -0
- package/dist/cli/output.d.ts +75 -0
- package/dist/cli/output.js +305 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/prompt.d.ts +30 -0
- package/dist/cli/prompt.js +196 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/repl.d.ts +27 -0
- package/dist/cli/repl.js +485 -0
- package/dist/cli/repl.js.map +1 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +170 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/model.d.ts +10 -0
- package/dist/commands/model.js +270 -0
- package/dist/commands/model.js.map +1 -0
- package/dist/config/manager.d.ts +67 -0
- package/dist/config/manager.js +194 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/types.d.ts +98 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/errors.d.ts +37 -0
- package/dist/errors.js +54 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +185 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/anthropic.d.ts +27 -0
- package/dist/llm/anthropic.js +189 -0
- package/dist/llm/anthropic.js.map +1 -0
- package/dist/llm/factory.d.ts +47 -0
- package/dist/llm/factory.js +163 -0
- package/dist/llm/factory.js.map +1 -0
- package/dist/llm/openai-codex.d.ts +45 -0
- package/dist/llm/openai-codex.js +398 -0
- package/dist/llm/openai-codex.js.map +1 -0
- package/dist/llm/openai.d.ts +16 -0
- package/dist/llm/openai.js +288 -0
- package/dist/llm/openai.js.map +1 -0
- package/dist/llm/provider.d.ts +19 -0
- package/dist/llm/provider.js +2 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/llm/types.d.ts +102 -0
- package/dist/llm/types.js +2 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/mcp/bridge.d.ts +30 -0
- package/dist/mcp/bridge.js +73 -0
- package/dist/mcp/bridge.js.map +1 -0
- package/dist/mcp/config.d.ts +6 -0
- package/dist/mcp/config.js +26 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/manager.d.ts +54 -0
- package/dist/mcp/manager.js +171 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/prompts/system.d.ts +14 -0
- package/dist/prompts/system.js +194 -0
- package/dist/prompts/system.js.map +1 -0
- package/dist/skills/loader.d.ts +7 -0
- package/dist/skills/loader.js +81 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/registry.d.ts +48 -0
- package/dist/skills/registry.js +104 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/skills/sync.d.ts +34 -0
- package/dist/skills/sync.js +179 -0
- package/dist/skills/sync.js.map +1 -0
- package/dist/skills/types.d.ts +29 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/ask.d.ts +16 -0
- package/dist/tools/ask.js +57 -0
- package/dist/tools/ask.js.map +1 -0
- package/dist/tools/registry.d.ts +54 -0
- package/dist/tools/registry.js +114 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/shell.d.ts +10 -0
- package/dist/tools/shell.js +131 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/tools/ssh.d.ts +40 -0
- package/dist/tools/ssh.js +302 -0
- package/dist/tools/ssh.js.map +1 -0
- package/dist/tools/types.d.ts +20 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/retry.d.ts +20 -0
- package/dist/utils/retry.js +33 -0
- package/dist/utils/retry.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { mkdir, readFile, writeFile, access, chmod } from 'node:fs/promises';
|
|
4
|
+
const CONFIG_DIR_NAME = '.seno';
|
|
5
|
+
const CONFIG_FILE_NAME = 'config.json';
|
|
6
|
+
const SERVERS_FILE_NAME = 'servers.json';
|
|
7
|
+
const LOGS_DIR_NAME = 'logs';
|
|
8
|
+
/**
|
|
9
|
+
* 获取配置目录路径 ~/.seno/
|
|
10
|
+
*/
|
|
11
|
+
export function getConfigDir() {
|
|
12
|
+
return join(homedir(), CONFIG_DIR_NAME);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 获取配置文件路径 ~/.seno/config.json
|
|
16
|
+
*/
|
|
17
|
+
export function getConfigPath() {
|
|
18
|
+
return join(getConfigDir(), CONFIG_FILE_NAME);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 获取服务器配置文件路径 ~/.seno/servers.json
|
|
22
|
+
*/
|
|
23
|
+
export function getServersPath() {
|
|
24
|
+
return join(getConfigDir(), SERVERS_FILE_NAME);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 获取日志目录路径 ~/.seno/logs/
|
|
28
|
+
*/
|
|
29
|
+
export function getLogsDir() {
|
|
30
|
+
return join(getConfigDir(), LOGS_DIR_NAME);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 确保配置目录存在(包括 logs 子目录)
|
|
34
|
+
*/
|
|
35
|
+
export async function ensureConfigDir() {
|
|
36
|
+
const configDir = getConfigDir();
|
|
37
|
+
await mkdir(configDir, { recursive: true });
|
|
38
|
+
await mkdir(getLogsDir(), { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 检查文件是否存在
|
|
42
|
+
*/
|
|
43
|
+
async function fileExists(path) {
|
|
44
|
+
try {
|
|
45
|
+
await access(path);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 解析 "provider/model_name" 格式的模型 ID
|
|
54
|
+
*/
|
|
55
|
+
export function parseModelId(modelId) {
|
|
56
|
+
const slashIndex = modelId.indexOf('/');
|
|
57
|
+
if (slashIndex === -1) {
|
|
58
|
+
// 无前缀时为旧版 anthropic 配置
|
|
59
|
+
return { provider: 'anthropic', model: modelId };
|
|
60
|
+
}
|
|
61
|
+
const provider = modelId.slice(0, slashIndex);
|
|
62
|
+
const model = modelId.slice(slashIndex + 1);
|
|
63
|
+
return { provider, model };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 拼接 provider 和 model 为 "provider/model_name"
|
|
67
|
+
*/
|
|
68
|
+
export function formatModelId(provider, model) {
|
|
69
|
+
return `${provider}/${model}`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 从 config 中获取当前活跃的 provider 信息
|
|
73
|
+
* @returns null 表示未配置或凭证缺失
|
|
74
|
+
*/
|
|
75
|
+
export function getActiveProvider(config) {
|
|
76
|
+
if (!config.model)
|
|
77
|
+
return null;
|
|
78
|
+
const { provider, model } = parseModelId(config.model);
|
|
79
|
+
const providerConfig = config.llm?.providers?.[provider];
|
|
80
|
+
if (!providerConfig)
|
|
81
|
+
return null;
|
|
82
|
+
// 验证凭证:api_key 模式需要有 key,oauth 模式只需模式声明
|
|
83
|
+
if (providerConfig.mode === 'api_key' && !providerConfig.api_key)
|
|
84
|
+
return null;
|
|
85
|
+
return { name: provider, model, providerConfig };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 迁移旧格式配置到新格式
|
|
89
|
+
* 检测存在 anthropic_api_key 且无 model 字段时自动迁移
|
|
90
|
+
*/
|
|
91
|
+
function migrateConfig(config) {
|
|
92
|
+
// 已有新格式字段,无需迁移
|
|
93
|
+
if (config.model) {
|
|
94
|
+
return { config, migrated: false };
|
|
95
|
+
}
|
|
96
|
+
// 没有旧字段,也无需迁移
|
|
97
|
+
if (!config.anthropic_api_key) {
|
|
98
|
+
return { config, migrated: false };
|
|
99
|
+
}
|
|
100
|
+
// 旧版配置迁移:仅用于 anthropic 单 provider 时代的配置
|
|
101
|
+
const modelName = config.default_model || 'claude-sonnet-4-20250514';
|
|
102
|
+
const migrated = {
|
|
103
|
+
...config,
|
|
104
|
+
model: formatModelId('anthropic', modelName),
|
|
105
|
+
llm: {
|
|
106
|
+
providers: {
|
|
107
|
+
anthropic: {
|
|
108
|
+
mode: 'api_key',
|
|
109
|
+
api_key: config.anthropic_api_key,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
return { config: migrated, migrated: true };
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 读取配置文件 ~/.seno/config.json
|
|
118
|
+
* 自动检测并迁移旧格式配置
|
|
119
|
+
* @returns 配置对象,文件不存在返回 null
|
|
120
|
+
*/
|
|
121
|
+
export async function loadConfig() {
|
|
122
|
+
const configPath = getConfigPath();
|
|
123
|
+
if (!(await fileExists(configPath))) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const content = await readFile(configPath, 'utf-8');
|
|
128
|
+
const raw = JSON.parse(content);
|
|
129
|
+
// 自动迁移旧配置
|
|
130
|
+
const { config, migrated } = migrateConfig(raw);
|
|
131
|
+
if (migrated) {
|
|
132
|
+
await saveConfig(config);
|
|
133
|
+
}
|
|
134
|
+
return config;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 保存配置文件 ~/.seno/config.json
|
|
142
|
+
* 文件权限设置为 0o600(仅用户可读写)
|
|
143
|
+
*/
|
|
144
|
+
export async function saveConfig(config) {
|
|
145
|
+
await ensureConfigDir();
|
|
146
|
+
const configPath = getConfigPath();
|
|
147
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
148
|
+
await chmod(configPath, 0o600);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 检查是否已完成初始化
|
|
152
|
+
* 配置文件存在且包含必需字段即视为已初始化
|
|
153
|
+
* 兼容新格式(model + llm.providers)和旧格式(anthropic_api_key)
|
|
154
|
+
*/
|
|
155
|
+
export async function isInitialized() {
|
|
156
|
+
const config = await loadConfig();
|
|
157
|
+
if (!config)
|
|
158
|
+
return false;
|
|
159
|
+
if (!config.ones_mcp_url)
|
|
160
|
+
return false;
|
|
161
|
+
// 新格式:model 字段存在
|
|
162
|
+
if (config.model)
|
|
163
|
+
return true;
|
|
164
|
+
// 旧格式:anthropic_api_key 存在(loadConfig 会自动迁移,但防御性检查)
|
|
165
|
+
if (config.anthropic_api_key)
|
|
166
|
+
return true;
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* 读取 SSH 服务器配置 ~/.seno/servers.json
|
|
171
|
+
* @returns 服务器列表,文件不存在返回空列表
|
|
172
|
+
*/
|
|
173
|
+
export async function loadServers() {
|
|
174
|
+
const serversPath = getServersPath();
|
|
175
|
+
if (!(await fileExists(serversPath))) {
|
|
176
|
+
return { servers: [] };
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const content = await readFile(serversPath, 'utf-8');
|
|
180
|
+
return JSON.parse(content);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return { servers: [] };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 保存 SSH 服务器配置 ~/.seno/servers.json
|
|
188
|
+
*/
|
|
189
|
+
export async function saveServers(config) {
|
|
190
|
+
await ensureConfigDir();
|
|
191
|
+
const serversPath = getServersPath();
|
|
192
|
+
await writeFile(serversPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/config/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server 配置
|
|
3
|
+
*/
|
|
4
|
+
export interface McpServerConfig {
|
|
5
|
+
/** 服务器名称标识,如 'ones', 'context7' */
|
|
6
|
+
name: string;
|
|
7
|
+
/** 启动命令,如 'npx' */
|
|
8
|
+
command: string;
|
|
9
|
+
/** 命令参数 */
|
|
10
|
+
args: string[];
|
|
11
|
+
/** 环境变量 */
|
|
12
|
+
env?: Record<string, string>;
|
|
13
|
+
/** 是否为必需服务器(启动失败则退出) */
|
|
14
|
+
required: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* SSH 目标服务器配置
|
|
18
|
+
*/
|
|
19
|
+
export interface SshServerConfig {
|
|
20
|
+
/** 服务器名称标识,如 'staging-1' */
|
|
21
|
+
name: string;
|
|
22
|
+
/** 主机地址 */
|
|
23
|
+
host: string;
|
|
24
|
+
/** SSH 用户名 */
|
|
25
|
+
user: string;
|
|
26
|
+
/** SSH 端口 */
|
|
27
|
+
port: number;
|
|
28
|
+
/** 认证方式 */
|
|
29
|
+
auth_type: 'password' | 'ssh-key';
|
|
30
|
+
/** SSH 密钥文件路径(auth_type = 'ssh-key' 时使用) */
|
|
31
|
+
identity_file?: string;
|
|
32
|
+
/** SSH 密码(auth_type = 'password' 时使用) */
|
|
33
|
+
password?: string;
|
|
34
|
+
/** 服务器描述 */
|
|
35
|
+
description: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 支持的 LLM Provider
|
|
39
|
+
* - anthropic: Anthropic Claude (API Key)
|
|
40
|
+
* - openai: OpenAI GPT (API Key)
|
|
41
|
+
* - openai-codex: OpenAI via Codex OAuth
|
|
42
|
+
*/
|
|
43
|
+
export type LLMProviderName = 'anthropic' | 'openai' | 'openai-codex';
|
|
44
|
+
/**
|
|
45
|
+
* 认证模式
|
|
46
|
+
*/
|
|
47
|
+
export type AuthMode = 'api_key' | 'oauth';
|
|
48
|
+
/**
|
|
49
|
+
* 单个 Provider 的凭证配置
|
|
50
|
+
*/
|
|
51
|
+
export interface ProviderConfig {
|
|
52
|
+
/** 认证模式 */
|
|
53
|
+
mode: AuthMode;
|
|
54
|
+
/** API Key(mode='api_key' 时使用) */
|
|
55
|
+
api_key?: string;
|
|
56
|
+
/** 自定义 API 端点(预留) */
|
|
57
|
+
base_url?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* LLM Providers 配置
|
|
61
|
+
*/
|
|
62
|
+
export interface LLMProvidersConfig {
|
|
63
|
+
providers: Partial<Record<LLMProviderName, ProviderConfig>>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Seno 全局配置(~/.seno/config.json)
|
|
67
|
+
*/
|
|
68
|
+
export interface SenoConfig {
|
|
69
|
+
/** @deprecated 迁移至 llm.providers.anthropic.api_key */
|
|
70
|
+
anthropic_api_key?: string;
|
|
71
|
+
/** @deprecated 迁移至 model 字段 */
|
|
72
|
+
default_model?: string;
|
|
73
|
+
/** 当前活跃模型,格式: "provider/model_name" */
|
|
74
|
+
model?: string;
|
|
75
|
+
/** ONES MCP 服务器地址 */
|
|
76
|
+
ones_mcp_url: string;
|
|
77
|
+
/** 是否开启 debug 模式 */
|
|
78
|
+
debug: boolean;
|
|
79
|
+
/** LLM providers 凭证配置 */
|
|
80
|
+
llm?: LLMProvidersConfig;
|
|
81
|
+
/** Skills 配置 */
|
|
82
|
+
ones_skills?: OnesSkillsConfig;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Skills 配置
|
|
86
|
+
*/
|
|
87
|
+
export interface OnesSkillsConfig {
|
|
88
|
+
/** Skills Git 仓库地址 */
|
|
89
|
+
repository: string;
|
|
90
|
+
/** 上次同步时间 (ISO 8601) */
|
|
91
|
+
last_updated_at?: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* SSH 服务器列表配置(~/.seno/servers.json)
|
|
95
|
+
*/
|
|
96
|
+
export interface ServersConfig {
|
|
97
|
+
servers: SshServerConfig[];
|
|
98
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":""}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SENO CLI 统一错误基类
|
|
3
|
+
*
|
|
4
|
+
* 提供结构化的错误类型体系,用于错误分类、重试判断和用户友好提示。
|
|
5
|
+
*/
|
|
6
|
+
export declare class SenoError extends Error {
|
|
7
|
+
readonly code: string;
|
|
8
|
+
constructor(message: string, code: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* LLM API 错误
|
|
12
|
+
*
|
|
13
|
+
* 携带 HTTP 状态码和可重试标记,便于重试逻辑判断。
|
|
14
|
+
*/
|
|
15
|
+
export declare class LLMError extends SenoError {
|
|
16
|
+
readonly statusCode?: number | undefined;
|
|
17
|
+
readonly retryable: boolean;
|
|
18
|
+
constructor(message: string, statusCode?: number | undefined, retryable?: boolean);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* MCP 服务器错误
|
|
22
|
+
*
|
|
23
|
+
* 携带服务器名称,便于定位问题。
|
|
24
|
+
*/
|
|
25
|
+
export declare class MCPError extends SenoError {
|
|
26
|
+
readonly serverName: string;
|
|
27
|
+
constructor(message: string, serverName: string);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 用户中断错误(Ctrl+C)
|
|
31
|
+
*
|
|
32
|
+
* 用于在 ask_user 等交互式工具中传播用户中断信号,
|
|
33
|
+
* 使 Agent 循环能够优雅终止当前任务。
|
|
34
|
+
*/
|
|
35
|
+
export declare class UserInterruptError extends SenoError {
|
|
36
|
+
constructor();
|
|
37
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SENO CLI 统一错误基类
|
|
3
|
+
*
|
|
4
|
+
* 提供结构化的错误类型体系,用于错误分类、重试判断和用户友好提示。
|
|
5
|
+
*/
|
|
6
|
+
export class SenoError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(message, code) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.name = 'SenoError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* LLM API 错误
|
|
16
|
+
*
|
|
17
|
+
* 携带 HTTP 状态码和可重试标记,便于重试逻辑判断。
|
|
18
|
+
*/
|
|
19
|
+
export class LLMError extends SenoError {
|
|
20
|
+
statusCode;
|
|
21
|
+
retryable;
|
|
22
|
+
constructor(message, statusCode, retryable = false) {
|
|
23
|
+
super(message, 'LLM_ERROR');
|
|
24
|
+
this.statusCode = statusCode;
|
|
25
|
+
this.retryable = retryable;
|
|
26
|
+
this.name = 'LLMError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* MCP 服务器错误
|
|
31
|
+
*
|
|
32
|
+
* 携带服务器名称,便于定位问题。
|
|
33
|
+
*/
|
|
34
|
+
export class MCPError extends SenoError {
|
|
35
|
+
serverName;
|
|
36
|
+
constructor(message, serverName) {
|
|
37
|
+
super(message, 'MCP_ERROR');
|
|
38
|
+
this.serverName = serverName;
|
|
39
|
+
this.name = 'MCPError';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 用户中断错误(Ctrl+C)
|
|
44
|
+
*
|
|
45
|
+
* 用于在 ask_user 等交互式工具中传播用户中断信号,
|
|
46
|
+
* 使 Agent 循环能够优雅终止当前任务。
|
|
47
|
+
*/
|
|
48
|
+
export class UserInterruptError extends SenoError {
|
|
49
|
+
constructor() {
|
|
50
|
+
super('用户中断 (Ctrl+C)', 'USER_INTERRUPT');
|
|
51
|
+
this.name = 'UserInterruptError';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGhB;IAFlB,YACE,OAAe,EACC,IAAY;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,SAAI,GAAJ,IAAI,CAAQ;QAG5B,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,QAAS,SAAQ,SAAS;IAGnB;IACA;IAHlB,YACE,OAAe,EACC,UAAmB,EACnB,YAAqB,KAAK;QAE1C,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAHZ,eAAU,GAAV,UAAU,CAAS;QACnB,cAAS,GAAT,SAAS,CAAiB;QAG1C,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,QAAS,SAAQ,SAAS;IAGnB;IAFlB,YACE,OAAe,EACC,UAAkB;QAElC,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAFZ,eAAU,GAAV,UAAU,CAAQ;QAGlC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,kBAAmB,SAAQ,SAAS;IAC/C;QACE,KAAK,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { dirname, join } from 'path';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { initCommand } from './commands/init.js';
|
|
8
|
+
import { isInitialized, loadConfig, loadServers, getActiveProvider } from './config/manager.js';
|
|
9
|
+
import { getMcpServerConfigs } from './mcp/config.js';
|
|
10
|
+
import { MCPManager } from './mcp/manager.js';
|
|
11
|
+
import { createLLMProvider } from './llm/factory.js';
|
|
12
|
+
import { getCodexAccessToken } from './llm/openai-codex.js';
|
|
13
|
+
import { ToolRegistry } from './tools/registry.js';
|
|
14
|
+
import { AgentLoop } from './agent/loop.js';
|
|
15
|
+
import { printBanner, printError, createSpinner } from './cli/output.js';
|
|
16
|
+
import { startRepl } from './cli/repl.js';
|
|
17
|
+
import { buildSystemPrompt } from './prompts/system.js';
|
|
18
|
+
import { SessionState } from './agent/session.js';
|
|
19
|
+
import { logger } from './cli/logger.js';
|
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
+
const __dirname = dirname(__filename);
|
|
22
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
23
|
+
const program = new Command();
|
|
24
|
+
program
|
|
25
|
+
.name('seno')
|
|
26
|
+
.description('ONES 企业内部 AI Agent CLI')
|
|
27
|
+
.version(pkg.version);
|
|
28
|
+
program.option('--debug', '启用 Debug 模式,输出详细日志');
|
|
29
|
+
// seno init — 首次初始化配置
|
|
30
|
+
program
|
|
31
|
+
.command('init')
|
|
32
|
+
.description('初始化 SENO 配置(~/.seno/)')
|
|
33
|
+
.action(initCommand);
|
|
34
|
+
// 默认行为:无子命令时进入 REPL 对话模式
|
|
35
|
+
program.action(async (_options, command) => {
|
|
36
|
+
if (command.args.length > 0)
|
|
37
|
+
return;
|
|
38
|
+
const debug = program.opts().debug || false;
|
|
39
|
+
logger.setDebugMode(debug);
|
|
40
|
+
// 检查是否已初始化
|
|
41
|
+
if (!(await isInitialized())) {
|
|
42
|
+
console.log(chalk.yellow('\n 尚未初始化,请先运行: seno init\n'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
// 加载配置
|
|
46
|
+
const config = await loadConfig();
|
|
47
|
+
if (!config) {
|
|
48
|
+
console.log(chalk.red('\n 配置文件加载失败,请重新运行: seno init\n'));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
// 连接 MCP 服务器
|
|
52
|
+
const mcpManager = new MCPManager();
|
|
53
|
+
const spinner = createSpinner('连接 MCP 服务器...');
|
|
54
|
+
spinner.start();
|
|
55
|
+
try {
|
|
56
|
+
const servers = getMcpServerConfigs(config);
|
|
57
|
+
await mcpManager.connectAll(servers);
|
|
58
|
+
spinner.succeed('MCP 服务器已连接');
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
spinner.fail('MCP 服务器连接失败');
|
|
62
|
+
printError(error, debug);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
// 4. 同步 Skills
|
|
66
|
+
const { needsSync, syncSkills, getSkillsDir } = await import('./skills/sync.js');
|
|
67
|
+
if (await needsSync(config)) {
|
|
68
|
+
const syncSpinner = createSpinner('同步 Skills...');
|
|
69
|
+
syncSpinner.start();
|
|
70
|
+
try {
|
|
71
|
+
const result = await syncSkills(config);
|
|
72
|
+
if (result.success) {
|
|
73
|
+
syncSpinner.succeed(`Skills 已同步 (${result.skillCount} 个技能)`);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
syncSpinner.warn(`Skills 同步跳过: ${result.error}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
syncSpinner.warn('Skills 同步失败,使用已有版本');
|
|
81
|
+
logger.error('skills', `Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// 5. 初始化 LLM Provider
|
|
85
|
+
if (!config.model) {
|
|
86
|
+
console.log(chalk.yellow('\n LLM 未配置,请先运行: seno init\n'));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const active = getActiveProvider(config);
|
|
90
|
+
if (!active) {
|
|
91
|
+
console.log(chalk.yellow('\n LLM provider 凭证缺失,请运行 /model auth 配置\n'));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
// OAuth 模式:验证 token 有效
|
|
95
|
+
if (active.providerConfig.mode === 'oauth') {
|
|
96
|
+
try {
|
|
97
|
+
await getCodexAccessToken();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
console.log(chalk.yellow('\n OAuth token 无效,请运行 /model auth 重新授权\n'));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const llmProvider = await createLLMProvider(active.providerConfig, active.name);
|
|
105
|
+
// 6. 注册工具
|
|
106
|
+
const toolRegistry = new ToolRegistry();
|
|
107
|
+
toolRegistry.registerNativeTools();
|
|
108
|
+
toolRegistry.registerMCPTools(mcpManager);
|
|
109
|
+
// 7. 加载 Skill 索引
|
|
110
|
+
const skillIndexPath = join(getSkillsDir(), 'index.json');
|
|
111
|
+
try {
|
|
112
|
+
await toolRegistry.loadSkills(skillIndexPath);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
logger.info('skills', 'Skills 索引不存在,跳过加载');
|
|
116
|
+
}
|
|
117
|
+
// 8. 构建 System Prompt
|
|
118
|
+
const systemPrompt = buildSystemPrompt({
|
|
119
|
+
userInfo: mcpManager.userInfo,
|
|
120
|
+
skills: toolRegistry.getSkills(),
|
|
121
|
+
mcpTools: toolRegistry
|
|
122
|
+
.getToolDefinitions()
|
|
123
|
+
.filter((t) => t.name.includes('__'))
|
|
124
|
+
.map((t) => t.name),
|
|
125
|
+
});
|
|
126
|
+
// 9. 创建 Session 和 Agent Loop
|
|
127
|
+
const serversConfig = await loadServers();
|
|
128
|
+
const session = new SessionState(mcpManager.userInfo, serversConfig.servers);
|
|
129
|
+
const agent = new AgentLoop({
|
|
130
|
+
llmProvider,
|
|
131
|
+
toolRegistry,
|
|
132
|
+
systemPrompt,
|
|
133
|
+
chatOptions: { model: active.model },
|
|
134
|
+
session,
|
|
135
|
+
});
|
|
136
|
+
// 10. 全局异常兜底
|
|
137
|
+
process.on('uncaughtException', async (error) => {
|
|
138
|
+
logger.error('system', `Uncaught exception: ${error.message}`, {
|
|
139
|
+
stack: error.stack,
|
|
140
|
+
});
|
|
141
|
+
printError(error, debug);
|
|
142
|
+
try {
|
|
143
|
+
await toolRegistry.cleanup();
|
|
144
|
+
await mcpManager.disconnectAll();
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// 清理失败不阻塞退出
|
|
148
|
+
}
|
|
149
|
+
process.exit(1);
|
|
150
|
+
});
|
|
151
|
+
process.on('unhandledRejection', (reason) => {
|
|
152
|
+
const message = reason instanceof Error ? reason.message : String(reason);
|
|
153
|
+
logger.error('system', `Unhandled rejection: ${message}`);
|
|
154
|
+
});
|
|
155
|
+
// 11. 显示启动横幅
|
|
156
|
+
printBanner(pkg.version, mcpManager.userInfo, mcpManager.getConnectedServers(), {
|
|
157
|
+
count: toolRegistry.getSkills().length,
|
|
158
|
+
lastSync: config.ones_skills?.last_updated_at ?? null,
|
|
159
|
+
}, config.model);
|
|
160
|
+
// 12. 启动 REPL
|
|
161
|
+
const reloadSkills = async () => {
|
|
162
|
+
try {
|
|
163
|
+
await toolRegistry.loadSkills(skillIndexPath);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// 加载失败不阻塞
|
|
167
|
+
}
|
|
168
|
+
return toolRegistry.getSkills();
|
|
169
|
+
};
|
|
170
|
+
try {
|
|
171
|
+
await startRepl({
|
|
172
|
+
agent,
|
|
173
|
+
skills: toolRegistry.getSkills(),
|
|
174
|
+
debug,
|
|
175
|
+
config,
|
|
176
|
+
reloadSkills,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
await toolRegistry.cleanup();
|
|
181
|
+
await mcpManager.disconnectAll();
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
program.parse();
|
|
185
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { LLMProvider } from './provider.js';
|
|
2
|
+
import type { Message, ToolDefinition, ChatOptions, StreamEvent } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Anthropic Claude LLM Provider
|
|
5
|
+
*
|
|
6
|
+
* 使用 @anthropic-ai/sdk 的流式 API,将原始事件转换为统一的 StreamEvent。
|
|
7
|
+
* 支持 API 错误分类和自动重试(429 Rate Limit、5xx Server Error、网络错误)。
|
|
8
|
+
*/
|
|
9
|
+
export declare class AnthropicProvider implements LLMProvider {
|
|
10
|
+
readonly name = "anthropic";
|
|
11
|
+
private client;
|
|
12
|
+
constructor(apiKey: string);
|
|
13
|
+
/**
|
|
14
|
+
* 流式对话调用
|
|
15
|
+
* 使用 AsyncGenerator 模式,逐个 yield StreamEvent。
|
|
16
|
+
*/
|
|
17
|
+
chat(messages: Message[], tools: ToolDefinition[], options?: ChatOptions): AsyncGenerator<StreamEvent>;
|
|
18
|
+
/**
|
|
19
|
+
* 判断 API 错误是否可重试
|
|
20
|
+
* 429 Rate Limit、5xx Server Error、网络错误可重试
|
|
21
|
+
*/
|
|
22
|
+
private isRetryableError;
|
|
23
|
+
/**
|
|
24
|
+
* 将原始错误转换为 LLMError,提供用户友好的错误信息
|
|
25
|
+
*/
|
|
26
|
+
private classifyError;
|
|
27
|
+
}
|