@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.
Files changed (104) hide show
  1. package/README.md +70 -0
  2. package/dist/agent/conversation.d.ts +39 -0
  3. package/dist/agent/conversation.js +60 -0
  4. package/dist/agent/conversation.js.map +1 -0
  5. package/dist/agent/loop.d.ts +41 -0
  6. package/dist/agent/loop.js +203 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/session.d.ts +63 -0
  9. package/dist/agent/session.js +135 -0
  10. package/dist/agent/session.js.map +1 -0
  11. package/dist/cli/commands.d.ts +52 -0
  12. package/dist/cli/commands.js +667 -0
  13. package/dist/cli/commands.js.map +1 -0
  14. package/dist/cli/logger.d.ts +38 -0
  15. package/dist/cli/logger.js +79 -0
  16. package/dist/cli/logger.js.map +1 -0
  17. package/dist/cli/output.d.ts +75 -0
  18. package/dist/cli/output.js +305 -0
  19. package/dist/cli/output.js.map +1 -0
  20. package/dist/cli/prompt.d.ts +30 -0
  21. package/dist/cli/prompt.js +196 -0
  22. package/dist/cli/prompt.js.map +1 -0
  23. package/dist/cli/repl.d.ts +27 -0
  24. package/dist/cli/repl.js +485 -0
  25. package/dist/cli/repl.js.map +1 -0
  26. package/dist/commands/init.d.ts +4 -0
  27. package/dist/commands/init.js +170 -0
  28. package/dist/commands/init.js.map +1 -0
  29. package/dist/commands/model.d.ts +10 -0
  30. package/dist/commands/model.js +270 -0
  31. package/dist/commands/model.js.map +1 -0
  32. package/dist/config/manager.d.ts +67 -0
  33. package/dist/config/manager.js +194 -0
  34. package/dist/config/manager.js.map +1 -0
  35. package/dist/config/types.d.ts +98 -0
  36. package/dist/config/types.js +2 -0
  37. package/dist/config/types.js.map +1 -0
  38. package/dist/errors.d.ts +37 -0
  39. package/dist/errors.js +54 -0
  40. package/dist/errors.js.map +1 -0
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.js +185 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/llm/anthropic.d.ts +27 -0
  45. package/dist/llm/anthropic.js +189 -0
  46. package/dist/llm/anthropic.js.map +1 -0
  47. package/dist/llm/factory.d.ts +47 -0
  48. package/dist/llm/factory.js +163 -0
  49. package/dist/llm/factory.js.map +1 -0
  50. package/dist/llm/openai-codex.d.ts +45 -0
  51. package/dist/llm/openai-codex.js +398 -0
  52. package/dist/llm/openai-codex.js.map +1 -0
  53. package/dist/llm/openai.d.ts +16 -0
  54. package/dist/llm/openai.js +288 -0
  55. package/dist/llm/openai.js.map +1 -0
  56. package/dist/llm/provider.d.ts +19 -0
  57. package/dist/llm/provider.js +2 -0
  58. package/dist/llm/provider.js.map +1 -0
  59. package/dist/llm/types.d.ts +102 -0
  60. package/dist/llm/types.js +2 -0
  61. package/dist/llm/types.js.map +1 -0
  62. package/dist/mcp/bridge.d.ts +30 -0
  63. package/dist/mcp/bridge.js +73 -0
  64. package/dist/mcp/bridge.js.map +1 -0
  65. package/dist/mcp/config.d.ts +6 -0
  66. package/dist/mcp/config.js +26 -0
  67. package/dist/mcp/config.js.map +1 -0
  68. package/dist/mcp/manager.d.ts +54 -0
  69. package/dist/mcp/manager.js +171 -0
  70. package/dist/mcp/manager.js.map +1 -0
  71. package/dist/prompts/system.d.ts +14 -0
  72. package/dist/prompts/system.js +194 -0
  73. package/dist/prompts/system.js.map +1 -0
  74. package/dist/skills/loader.d.ts +7 -0
  75. package/dist/skills/loader.js +81 -0
  76. package/dist/skills/loader.js.map +1 -0
  77. package/dist/skills/registry.d.ts +48 -0
  78. package/dist/skills/registry.js +104 -0
  79. package/dist/skills/registry.js.map +1 -0
  80. package/dist/skills/sync.d.ts +34 -0
  81. package/dist/skills/sync.js +179 -0
  82. package/dist/skills/sync.js.map +1 -0
  83. package/dist/skills/types.d.ts +29 -0
  84. package/dist/skills/types.js +2 -0
  85. package/dist/skills/types.js.map +1 -0
  86. package/dist/tools/ask.d.ts +16 -0
  87. package/dist/tools/ask.js +57 -0
  88. package/dist/tools/ask.js.map +1 -0
  89. package/dist/tools/registry.d.ts +54 -0
  90. package/dist/tools/registry.js +114 -0
  91. package/dist/tools/registry.js.map +1 -0
  92. package/dist/tools/shell.d.ts +10 -0
  93. package/dist/tools/shell.js +131 -0
  94. package/dist/tools/shell.js.map +1 -0
  95. package/dist/tools/ssh.d.ts +40 -0
  96. package/dist/tools/ssh.js +302 -0
  97. package/dist/tools/ssh.js.map +1 -0
  98. package/dist/tools/types.d.ts +20 -0
  99. package/dist/tools/types.js +2 -0
  100. package/dist/tools/types.js.map +1 -0
  101. package/dist/utils/retry.d.ts +20 -0
  102. package/dist/utils/retry.js +33 -0
  103. package/dist/utils/retry.js.map +1 -0
  104. package/package.json +51 -0
@@ -0,0 +1,40 @@
1
+ import { Client } from 'ssh2';
2
+ import type { Tool } from './types.js';
3
+ /**
4
+ * 解析后的服务器信息
5
+ */
6
+ interface ServerInfo {
7
+ host: string;
8
+ port: number;
9
+ user: string;
10
+ authType: 'password' | 'ssh-key';
11
+ identityFile: string;
12
+ password?: string;
13
+ }
14
+ /**
15
+ * SSH 连接池,复用同一 host 的连接
16
+ */
17
+ export declare class SSHConnectionPool {
18
+ private connections;
19
+ /**
20
+ * 生成连接缓存 key
21
+ */
22
+ private getKey;
23
+ /**
24
+ * 获取连接(存在且可用则复用,否则创建新连接)
25
+ */
26
+ getConnection(server: ServerInfo): Promise<Client>;
27
+ /**
28
+ * 创建新 SSH 连接
29
+ */
30
+ private createConnection;
31
+ /**
32
+ * 关闭所有连接
33
+ */
34
+ closeAll(): Promise<void>;
35
+ }
36
+ /**
37
+ * 创建 SSH 远程执行工具
38
+ */
39
+ export declare function createSSHTool(pool: SSHConnectionPool): Tool;
40
+ export {};
@@ -0,0 +1,302 @@
1
+ import { Client } from 'ssh2';
2
+ import { readFileSync, existsSync, appendFileSync, mkdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { loadServers, getLogsDir } from '../config/manager.js';
6
+ import { truncateOutput } from './shell.js';
7
+ const DEFAULT_TIMEOUT_SECONDS = 60;
8
+ const DEFAULT_SSH_PORT = 22;
9
+ const DEFAULT_SSH_USER = 'root';
10
+ const DEFAULT_KEY_PATH = '~/.ssh/id_rsa';
11
+ /**
12
+ * 展开路径中的 ~ 为 home 目录
13
+ */
14
+ function expandPath(p) {
15
+ if (p.startsWith('~/') || p === '~') {
16
+ return join(homedir(), p.slice(1));
17
+ }
18
+ return p;
19
+ }
20
+ /**
21
+ * 写入 SSH 执行日志到 ~/.seno/logs/ssh.log
22
+ */
23
+ function logSSHExecution(host, user, port, command, exitCode, durationMs) {
24
+ try {
25
+ const logsDir = getLogsDir();
26
+ mkdirSync(logsDir, { recursive: true });
27
+ const logPath = join(logsDir, 'ssh.log');
28
+ const timestamp = new Date().toISOString();
29
+ const line = `[${timestamp}] [SSH] command="${command}" user=${user} host=${host}:${port} exitCode=${exitCode} duration=${durationMs}ms\n`;
30
+ appendFileSync(logPath, line, 'utf-8');
31
+ }
32
+ catch {
33
+ // 日志写入失败不影响命令执行
34
+ }
35
+ }
36
+ /**
37
+ * 解析主机名或 IP,从 servers.json 查找匹配的服务器配置
38
+ */
39
+ async function resolveHost(hostOrName, userOverride) {
40
+ const config = await loadServers();
41
+ // 查找匹配的服务器名称
42
+ const server = config.servers.find((s) => s.name === hostOrName);
43
+ if (server) {
44
+ return {
45
+ host: server.host,
46
+ port: server.port || DEFAULT_SSH_PORT,
47
+ user: userOverride || server.user || DEFAULT_SSH_USER,
48
+ authType: server.auth_type || 'ssh-key',
49
+ identityFile: server.identity_file || DEFAULT_KEY_PATH,
50
+ password: server.password,
51
+ };
52
+ }
53
+ // 未找到则视为 IP 地址,使用默认配置
54
+ return {
55
+ host: hostOrName,
56
+ port: DEFAULT_SSH_PORT,
57
+ user: userOverride || DEFAULT_SSH_USER,
58
+ authType: 'ssh-key',
59
+ identityFile: DEFAULT_KEY_PATH,
60
+ };
61
+ }
62
+ /**
63
+ * SSH 连接池,复用同一 host 的连接
64
+ */
65
+ export class SSHConnectionPool {
66
+ connections = new Map();
67
+ /**
68
+ * 生成连接缓存 key
69
+ */
70
+ getKey(server) {
71
+ return `${server.user}@${server.host}:${server.port}`;
72
+ }
73
+ /**
74
+ * 获取连接(存在且可用则复用,否则创建新连接)
75
+ */
76
+ async getConnection(server) {
77
+ const key = this.getKey(server);
78
+ const existing = this.connections.get(key);
79
+ // 检查缓存的连接是否仍然可用
80
+ if (existing) {
81
+ // ssh2 Client 没有显式 isConnected 属性,
82
+ // 如果连接断开会在 close 事件中被移除
83
+ return existing;
84
+ }
85
+ // 创建新连接
86
+ const client = await this.createConnection(server);
87
+ // 连接断开时自动从缓存移除
88
+ client.on('close', () => {
89
+ this.connections.delete(key);
90
+ });
91
+ client.on('error', () => {
92
+ this.connections.delete(key);
93
+ });
94
+ this.connections.set(key, client);
95
+ return client;
96
+ }
97
+ /**
98
+ * 创建新 SSH 连接
99
+ */
100
+ createConnection(server) {
101
+ return new Promise((resolve, reject) => {
102
+ const client = new Client();
103
+ // 构建认证选项
104
+ const connectOptions = {
105
+ host: server.host,
106
+ port: server.port,
107
+ username: server.user,
108
+ };
109
+ if (server.authType === 'password' && server.password) {
110
+ // 密码认证
111
+ connectOptions.password = server.password;
112
+ }
113
+ else {
114
+ // SSH Key 认证:密钥文件 → SSH Agent
115
+ const keyPath = expandPath(server.identityFile);
116
+ if (existsSync(keyPath)) {
117
+ try {
118
+ connectOptions.privateKey = readFileSync(keyPath);
119
+ }
120
+ catch {
121
+ // 密钥读取失败,尝试 Agent
122
+ }
123
+ }
124
+ // SSH Agent 作为回退
125
+ if (!connectOptions.privateKey && process.env.SSH_AUTH_SOCK) {
126
+ connectOptions.agent = process.env.SSH_AUTH_SOCK;
127
+ }
128
+ // 如果既无密钥也无 Agent,报错
129
+ if (!connectOptions.privateKey && !connectOptions.agent) {
130
+ reject(new Error(`SSH 认证失败:密钥文件 ${keyPath} 不存在,且未检测到 SSH Agent`));
131
+ return;
132
+ }
133
+ }
134
+ client.on('ready', () => resolve(client));
135
+ client.on('error', (err) => {
136
+ reject(new Error(`SSH 连接失败 (${server.host}): ${err.message}`));
137
+ });
138
+ client.connect(connectOptions);
139
+ });
140
+ }
141
+ /**
142
+ * 关闭所有连接
143
+ */
144
+ async closeAll() {
145
+ for (const [key, client] of this.connections) {
146
+ try {
147
+ client.end();
148
+ }
149
+ catch {
150
+ // 忽略关闭错误
151
+ }
152
+ this.connections.delete(key);
153
+ }
154
+ }
155
+ }
156
+ /**
157
+ * 在远程服务器执行命令
158
+ */
159
+ function sshExecute(client, command, options) {
160
+ const timeoutSeconds = options.timeout || DEFAULT_TIMEOUT_SECONDS;
161
+ return new Promise((resolve, reject) => {
162
+ let output = '';
163
+ let finished = false;
164
+ let timedOut = false;
165
+ const execOptions = options.tty ? { pty: true } : {};
166
+ client.exec(command, execOptions, (err, stream) => {
167
+ if (err) {
168
+ reject(new Error(`SSH 命令执行失败: ${err.message}`));
169
+ return;
170
+ }
171
+ // 超时处理
172
+ const timer = setTimeout(() => {
173
+ if (!finished) {
174
+ timedOut = true;
175
+ stream.close();
176
+ }
177
+ }, timeoutSeconds * 1000);
178
+ // 收集输出
179
+ stream.on('data', (data) => {
180
+ output += data.toString();
181
+ });
182
+ stream.stderr?.on('data', (data) => {
183
+ output += data.toString();
184
+ });
185
+ stream.on('close', (code) => {
186
+ finished = true;
187
+ clearTimeout(timer);
188
+ if (timedOut) {
189
+ resolve({ output, exitCode: null });
190
+ }
191
+ else {
192
+ resolve({ output, exitCode: code });
193
+ }
194
+ });
195
+ stream.on('error', (streamErr) => {
196
+ finished = true;
197
+ clearTimeout(timer);
198
+ reject(new Error(`SSH 命令流错误: ${streamErr.message}`));
199
+ });
200
+ });
201
+ });
202
+ }
203
+ /**
204
+ * 创建 SSH 远程执行工具
205
+ */
206
+ export function createSSHTool(pool) {
207
+ return {
208
+ name: 'ssh_execute',
209
+ description: '通过 SSH 在远程服务器上执行命令。支持通过 IP 地址或预配置的服务器名称连接。',
210
+ inputSchema: {
211
+ type: 'object',
212
+ properties: {
213
+ host: {
214
+ type: 'string',
215
+ description: '目标服务器地址(IP 或在 servers.json 中配置的服务器名称)',
216
+ },
217
+ command: {
218
+ type: 'string',
219
+ description: '要在远程服务器上执行的命令',
220
+ },
221
+ user: {
222
+ type: 'string',
223
+ description: '登录用户名,默认 root',
224
+ },
225
+ tty: {
226
+ type: 'boolean',
227
+ description: '是否分配 TTY(某些交互式命令需要),默认 false',
228
+ },
229
+ },
230
+ required: ['host', 'command'],
231
+ },
232
+ execute: async (args) => {
233
+ const hostOrName = args.host;
234
+ const command = args.command;
235
+ const userOverride = args.user;
236
+ const tty = args.tty || false;
237
+ const startTime = Date.now();
238
+ // 1. 解析服务器信息
239
+ let server;
240
+ try {
241
+ server = await resolveHost(hostOrName, userOverride);
242
+ }
243
+ catch (error) {
244
+ return {
245
+ content: `服务器解析失败: ${error instanceof Error ? error.message : String(error)}`,
246
+ isError: true,
247
+ };
248
+ }
249
+ // 2. 获取连接
250
+ let client;
251
+ try {
252
+ client = await pool.getConnection(server);
253
+ }
254
+ catch (error) {
255
+ const durationMs = Date.now() - startTime;
256
+ logSSHExecution(server.host, server.user, server.port, command, null, durationMs);
257
+ const msg = error instanceof Error ? error.message : String(error);
258
+ return {
259
+ content: `[致命错误] ${msg}\n无法连接到目标服务器,请立即停止当前任务。`,
260
+ isError: true,
261
+ };
262
+ }
263
+ // 3. 执行命令
264
+ try {
265
+ const result = await sshExecute(client, command, { tty });
266
+ const durationMs = Date.now() - startTime;
267
+ logSSHExecution(server.host, server.user, server.port, command, result.exitCode, durationMs);
268
+ // 超时情况
269
+ if (result.exitCode === null && result.output !== undefined) {
270
+ const partialOutput = truncateOutput(result.output);
271
+ return {
272
+ content: `命令执行超时(${DEFAULT_TIMEOUT_SECONDS}秒)\n\n已收集的部分输出:\n${partialOutput}`,
273
+ isError: true,
274
+ };
275
+ }
276
+ const truncated = truncateOutput(result.output);
277
+ if (result.exitCode === 0) {
278
+ return {
279
+ content: truncated || '(命令执行成功,无输出)',
280
+ };
281
+ }
282
+ else {
283
+ return {
284
+ content: `命令退出码: ${result.exitCode}\n\n${truncated}`,
285
+ isError: true,
286
+ };
287
+ }
288
+ }
289
+ catch (error) {
290
+ const durationMs = Date.now() - startTime;
291
+ logSSHExecution(server.host, server.user, server.port, command, null, durationMs);
292
+ // 连接可能已断开,从池中移除以便下次重连
293
+ pool['connections'].delete(`${server.user}@${server.host}:${server.port}`);
294
+ return {
295
+ content: error instanceof Error ? error.message : String(error),
296
+ isError: true,
297
+ };
298
+ }
299
+ },
300
+ };
301
+ }
302
+ //# sourceMappingURL=ssh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../src/tools/ssh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 工具执行结果
3
+ */
4
+ export interface ToolResult {
5
+ content: string;
6
+ isError?: boolean;
7
+ }
8
+ /**
9
+ * 统一工具接口
10
+ */
11
+ export interface Tool {
12
+ /** 工具名称(含服务器前缀,如 ones__who_am_i) */
13
+ name: string;
14
+ /** 工具描述 */
15
+ description: string;
16
+ /** JSON Schema 参数定义 */
17
+ inputSchema: Record<string, unknown>;
18
+ /** 执行工具 */
19
+ execute(args: Record<string, unknown>): Promise<ToolResult>;
20
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 重试选项
3
+ */
4
+ export interface RetryOptions {
5
+ /** 最大重试次数 */
6
+ maxRetries: number;
7
+ /** 基础延迟(毫秒),每次重试翻倍 */
8
+ baseDelayMs: number;
9
+ /** 最大延迟上限(毫秒) */
10
+ maxDelayMs?: number;
11
+ /** 判断错误是否可重试,返回 false 则立即抛出 */
12
+ shouldRetry?: (error: unknown) => boolean;
13
+ }
14
+ /**
15
+ * 通用重试函数(指数退避)
16
+ *
17
+ * 首次执行 fn(),失败后按 baseDelayMs * 2^attempt 间隔重试,
18
+ * 直到成功或达到 maxRetries 次。
19
+ */
20
+ export declare function withRetry<T>(fn: () => Promise<T>, options: RetryOptions): Promise<T>;
@@ -0,0 +1,33 @@
1
+ import { logger } from '../cli/logger.js';
2
+ /**
3
+ * 通用重试函数(指数退避)
4
+ *
5
+ * 首次执行 fn(),失败后按 baseDelayMs * 2^attempt 间隔重试,
6
+ * 直到成功或达到 maxRetries 次。
7
+ */
8
+ export async function withRetry(fn, options) {
9
+ const { maxRetries, baseDelayMs, maxDelayMs = 10000, shouldRetry } = options;
10
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
11
+ try {
12
+ return await fn();
13
+ }
14
+ catch (error) {
15
+ // 最后一次尝试 or 不可重试 → 直接抛出
16
+ if (attempt === maxRetries)
17
+ throw error;
18
+ if (shouldRetry && !shouldRetry(error))
19
+ throw error;
20
+ // 指数退避
21
+ const delay = Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
22
+ const message = error instanceof Error ? error.message : String(error);
23
+ logger.debug('retry', `Attempt ${attempt + 1}/${maxRetries} failed: ${message}, retrying in ${delay}ms`);
24
+ await sleep(delay);
25
+ }
26
+ }
27
+ // TypeScript 需要(实际不会到达)
28
+ throw new Error('Unreachable');
29
+ }
30
+ function sleep(ms) {
31
+ return new Promise((resolve) => setTimeout(resolve, ms));
32
+ }
33
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAgB1C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,OAAqB;IAErB,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,GAAG,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAE7E,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wBAAwB;YACxB,IAAI,OAAO,KAAK,UAAU;gBAAE,MAAM,KAAK,CAAC;YACxC,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAC;YAEpD,OAAO;YACP,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;YACvE,MAAM,OAAO,GACX,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACzD,MAAM,CAAC,KAAK,CACV,OAAO,EACP,WAAW,OAAO,GAAG,CAAC,IAAI,UAAU,YAAY,OAAO,iBAAiB,KAAK,IAAI,CAClF,CAAC;YACF,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@seandong/seno",
3
+ "version": "0.1.0",
4
+ "description": "ONES AI Agent CLI",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "seno": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18.0.0"
16
+ },
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "prebuild": "rm -rf dist",
20
+ "prepublishOnly": "npm run build",
21
+ "start": "node dist/index.js",
22
+ "dev": "bun --watch src/index.ts",
23
+ "typecheck": "tsc --noEmit"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/seandong/ones-agent-cli.git"
28
+ },
29
+ "homepage": "https://seno.help",
30
+ "keywords": ["cli", "ai", "agent", "ones", "mcp"],
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "@anthropic-ai/sdk": "^0.39.0",
34
+ "@modelcontextprotocol/sdk": "^1.8.0",
35
+ "chalk": "^5.4.1",
36
+ "commander": "^13.1.0",
37
+ "dotenv": "^16.4.7",
38
+ "gray-matter": "^4.0.3",
39
+ "marked": "^17.0.4",
40
+ "marked-terminal": "^7.3.0",
41
+ "openai": "^6.27.0",
42
+ "ora": "^8.2.0",
43
+ "ssh2": "^1.17.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/marked-terminal": "^6.1.1",
47
+ "@types/node": "^22.13.0",
48
+ "@types/ssh2": "^1.15.5",
49
+ "typescript": "^5.7.3"
50
+ }
51
+ }