@starlink-awaken/agentmesh 1.4.0 → 1.5.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 (38) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/dist/src/cli/release.d.ts +2 -0
  3. package/dist/src/cli/release.js +94 -0
  4. package/dist/src/cli.js +117 -31
  5. package/dist/src/core/agent-registry.d.ts +2 -0
  6. package/dist/src/core/agent-registry.js +12 -154
  7. package/dist/src/core/agents.default.d.ts +7 -0
  8. package/dist/src/core/agents.default.js +154 -0
  9. package/dist/src/core/config.d.ts +21 -0
  10. package/dist/src/core/context-manager.d.ts +2 -0
  11. package/dist/src/core/context-manager.js +4 -0
  12. package/dist/src/core/gateway.d.ts +79 -0
  13. package/dist/src/core/gateway.js +223 -0
  14. package/dist/src/core/pipeline.d.ts +21 -0
  15. package/dist/src/core/pipeline.js +48 -0
  16. package/dist/src/core/router.d.ts +2 -1
  17. package/dist/src/core/scheduler.d.ts +28 -0
  18. package/dist/src/core/scheduler.js +68 -0
  19. package/dist/src/core/store.d.ts +18 -0
  20. package/dist/src/core/store.js +77 -0
  21. package/dist/src/core/task-manager.d.ts +19 -27
  22. package/dist/src/core/task-manager.js +89 -80
  23. package/dist/src/core/vector-store.d.ts +2 -0
  24. package/dist/src/core/vector-store.js +4 -0
  25. package/dist/src/hermes/routes.d.ts +13 -0
  26. package/dist/src/hermes/routes.js +115 -0
  27. package/dist/src/index.js +76 -50
  28. package/dist/src/model-gateway/rate-limit.js +9 -0
  29. package/dist/src/model-gateway/routes.js +5 -5
  30. package/dist/src/routes/api.js +71 -7
  31. package/dist/src/routes/dashboard.d.ts +2 -0
  32. package/dist/src/routes/dashboard.js +113 -0
  33. package/dist/src/routes/sse.d.ts +2 -0
  34. package/dist/src/routes/sse.js +64 -0
  35. package/dist/src/types/index.d.ts +0 -19
  36. package/dist/src/types/index.js +2 -0
  37. package/dist/tests/model-gateway/routes.test.js +4 -4
  38. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,36 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to this project will be documented in this file.
3
+ ## [1.5.0] 2026-05-17
4
+
5
+ ### Added
6
+ - **GatewayContainer**: Unified DI lifecycle manager wrapping all core singletons (`init → reload → dispose`)
7
+ - **Task Persistence**: bun:sqlite backend, WAL mode, tasks survive restarts
8
+ - **Task Cancellation**: `POST /v1/tasks/:id/cancel` + `agentmesh cancel <id>`
9
+ - **Agent Hot Reload**: edit `config/gateway.yaml`, agents auto-reload within 3s
10
+ - **Web Dashboard**: `GET /dashboard` — real-time status with Dark theme, auto-refresh
11
+ - **Scheduled Tasks**: cron-based scheduler via `POST /v1/scheduler` + cron-parser
12
+ - **Agent Pipeline**: multi-agent sequential execution via `POST /v1/pipeline`
13
+ - **Graceful Shutdown**: SIGTERM/SIGINT → dispose + fastify.close
14
+ - **Detailed Health**: `GET /v1/health/detailed` with circuit breakers, config, uptime
15
+ - **CLI Table Output**: Unicode box-drawing + ANSI colors for agents/tasks/models/health
16
+
17
+ ### Changed
18
+ - **API Versioning**: All routes unified under `/v1/` prefix (model-gateway management included)
19
+ - **Routes renamed**: `websocket.ts` → `sse.ts` (was always SSE, never WebSocket)
20
+ - **Type cleanup**: Duplicate `GatewayConfig`/`RoutingRule` removed from types/index.ts
21
+ - **Agent configs**: 25+ hardcoded defaults extracted to `src/core/agents.default.ts`
22
+ - **Config injection**: `(config as any).models` replaced with typed `ModelsSection` + YAML→TS mapping
23
+ - **Logger unified**: Pino bridge via `initLogger({ pino: fastify.log })`
24
+ - **Error handling**: Global `setErrorHandler` + consistent `{error: {code, message}}` format
25
+ - **Rate limiter**: Now configurable from YAML `models.defaults.rate_limit`
26
+ - **Storage paths**: Derived from `config.dataDir` instead of hardcoded `./data/`
27
+ - **cron-parser**: Replaces hand-rolled 40-line cron implementation
28
+
29
+ ### Fixed
30
+ - `purgeCompleted` count overwrite bug when store is present
31
+ - `startConfigWatcher` file watcher leak on dispose
32
+ - `reloadAgents` unconditional re-registration of unchanged agents
33
+ - `TaskManager` removes stale JSDoc cruft, uses single `_save()` path
4
34
 
5
35
  ## [1.2.0] — 2026-05-16
6
36
 
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export declare function runRelease(level?: string): Promise<string>;
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env bun
2
+ // agentmesh release — 一键发版:check → test → build → bump → commit → push → publish
3
+ import { readFileSync, writeFileSync } from 'node:fs';
4
+ import { join, dirname } from 'node:path';
5
+ // logger 由 cli 入口统一初始化,此模块不需要
6
+ const PROJECT_ROOT = dirname(dirname(import.meta.dir || import.meta.dirname || '.'));
7
+ class ReleaseError extends Error {
8
+ }
9
+ async function sh(cmd, cwd) {
10
+ const proc = Bun.spawn(cmd, { cwd: cwd || PROJECT_ROOT, stdout: 'pipe', stderr: 'pipe' });
11
+ const out = await new Response(proc.stdout).text();
12
+ await proc.exited;
13
+ if (proc.exitCode !== 0) {
14
+ const err = await new Response(proc.stderr).text();
15
+ throw new ReleaseError(`${cmd.join(' ')} failed (exit ${proc.exitCode}): ${err || out}`);
16
+ }
17
+ return out.trim();
18
+ }
19
+ function bumpVersion(current, level) {
20
+ const parts = current.split('.').map(Number);
21
+ if (parts.length !== 3)
22
+ throw new ReleaseError(`Invalid version: ${current}`);
23
+ switch (level) {
24
+ case 'major':
25
+ parts[0]++;
26
+ parts[1] = 0;
27
+ parts[2] = 0;
28
+ break;
29
+ case 'minor':
30
+ parts[1]++;
31
+ parts[2] = 0;
32
+ break;
33
+ case 'patch':
34
+ parts[2]++;
35
+ break;
36
+ default: throw new ReleaseError(`Unknown bump level: ${level}`);
37
+ }
38
+ return parts.join('.');
39
+ }
40
+ function updateVersionFiles(newVer) {
41
+ const pkgPath = join(PROJECT_ROOT, 'package.json');
42
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
43
+ pkg.version = newVer;
44
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
45
+ const cliPath = join(PROJECT_ROOT, 'src', 'cli.ts');
46
+ let cli = readFileSync(cliPath, 'utf-8');
47
+ cli = cli.replace(/const VERSION = '[^']+'/, `const VERSION = '${newVer}'`);
48
+ writeFileSync(cliPath, cli);
49
+ }
50
+ export async function runRelease(level = 'patch') {
51
+ const pkg = JSON.parse(readFileSync(join(PROJECT_ROOT, 'package.json'), 'utf-8'));
52
+ const oldVer = pkg.version;
53
+ const newVer = bumpVersion(oldVer, level);
54
+ console.log(`\n 🚀 Release: ${oldVer} → ${newVer} (${level})\n`);
55
+ // 1. Typecheck
56
+ console.log(' [1/6] Typecheck...');
57
+ await sh(['bun', 'run', 'typecheck']);
58
+ console.log(' ✅ Typecheck passed');
59
+ // 2. Test
60
+ console.log(' [2/6] Test...');
61
+ await sh(['bun', 'test']);
62
+ console.log(' ✅ Tests passed');
63
+ // 3. Build
64
+ console.log(' [3/6] Build...');
65
+ await sh(['bun', 'run', 'build']);
66
+ console.log(' ✅ Build done');
67
+ // 4. Bump version
68
+ console.log(` [4/6] Bump version: ${oldVer} → ${newVer}`);
69
+ updateVersionFiles(newVer);
70
+ console.log(' ✅ Version updated');
71
+ // 5. Commit + Push
72
+ console.log(' [5/6] Commit + Push...');
73
+ await sh(['git', 'add', '-A']);
74
+ await sh(['git', 'commit', '-m', `Release v${newVer}`]);
75
+ await sh(['git', 'push', 'origin', 'main']);
76
+ console.log(' ✅ Pushed to GitHub');
77
+ // 6. Publish to npm
78
+ console.log(' [6/7] Publish to npm...');
79
+ const pubOut = await sh(['npm', 'publish']);
80
+ console.log(` ✅ Published: ${pubOut}`);
81
+ // 7. Install latest globally
82
+ console.log(' [7/7] Install latest...');
83
+ await sh(['npm', 'install', '-g', `@starlink-awaken/agentmesh@${newVer}`]);
84
+ console.log(' ✅ Installed globally');
85
+ console.log(`\n 🎉 v${newVer} released & installed!\n`);
86
+ return newVer;
87
+ }
88
+ if (import.meta.main) {
89
+ const level = Bun.argv[2] || 'patch';
90
+ runRelease(level).catch(err => {
91
+ console.error(`\n ❌ Release failed: ${err.message}\n`);
92
+ process.exit(1);
93
+ });
94
+ }
package/dist/src/cli.js CHANGED
@@ -7,7 +7,7 @@ import { existsSync, readFileSync } from 'node:fs';
7
7
  import { resolve, dirname, join } from 'node:path';
8
8
  import { initLogger } from './core/logger.js';
9
9
  const PROJECT_ROOT = resolve(dirname(import.meta.dir), '..');
10
- const VERSION = '1.4.0';
10
+ const VERSION = '1.5.0';
11
11
  const BANNER = `
12
12
  █████╗ ██████╗ ███████╗███╗ ██╗████████╗
13
13
  ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝
@@ -17,6 +17,19 @@ const BANNER = `
17
17
  ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝
18
18
  𝙼 𝙴 𝚂 𝙷 𝙶 𝙰 𝚃 𝙴 𝚆 𝙰 𝚈 v${VERSION}
19
19
  `;
20
+ const C = { reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', cyan: '\x1b[36m' };
21
+ const ICON = { ok: '✅', fail: '❌', warn: '⚠️', dot: '⚫' };
22
+ const STATUS_ICON = { completed: '🎯', failed: '❌', running: '🔄', pending: '🕐', assigned: '⚫' };
23
+ function table(headers, rows) {
24
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map(r => (r[i] || '').length)));
25
+ const sep = '─'.repeat(widths.reduce((a, b) => a + b, 0) + widths.length * 3 + 1);
26
+ let out = `╭${sep}╮\n│ ${headers.map((h, i) => C.bold + h.padEnd(widths[i]) + C.reset).join(' │ ')} │\n├${sep}┤\n`;
27
+ for (const row of rows) {
28
+ out += `│ ${row.map((cell, i) => cell.padEnd(widths[i])).join(' │ ')} │\n`;
29
+ }
30
+ out += `╰${sep}╯`;
31
+ return out;
32
+ }
20
33
  const BASE_URL = () => {
21
34
  const host = Bun.env.AGENT_GATEWAY_HOST || '127.0.0.1';
22
35
  const port = Bun.env.AGENT_GATEWAY_PORT || '3000';
@@ -98,6 +111,7 @@ ${BANNER}
98
111
  接入命令:
99
112
  connect [tool] 一键接入 AI 工具 (--dry-run 预览)
100
113
  disconnect [tool] 恢复工具配置到接入前状态
114
+ hermes setup 配置 Hermes 双向通路 (手机↔网关)
101
115
 
102
116
  查询命令:
103
117
  health, status 健康检查
@@ -105,6 +119,7 @@ ${BANNER}
105
119
  quota 查看配额状态
106
120
  agents 列出已注册 Agent
107
121
  tasks 列出任务列表
122
+ cancel <id> 取消指定任务
108
123
 
109
124
  配置命令:
110
125
  config show 显示当前配置
@@ -140,10 +155,10 @@ async function cmdStart(args) {
140
155
  console.log(`${BANNER}
141
156
  🚀 Starting Agent Mesh Gateway...
142
157
  ═══════════════════════════════════════
143
- HTTP: http://${host}:${port}
144
- Health: http://${host}:${port}/health
158
+ API v1: http://${host}:${port}/v1
159
+ Health: http://${host}:${port}/v1/health
145
160
  Models: http://${host}:${port}/v1/models
146
- Quota: http://${host}:${port}/model-gateway/quota
161
+ Quota: http://${host}:${port}/v1/model-gateway/quota
147
162
  Docs: http://${host}:${port}/docs
148
163
  ═══════════════════════════════════════
149
164
  `);
@@ -153,40 +168,41 @@ async function cmdStart(args) {
153
168
  }
154
169
  async function cmdHealth() {
155
170
  try {
156
- const data = await apiRequest('/health');
157
- console.log(`\n Gateway Running`);
158
- console.log(` Status: ${data.status}`);
159
- console.log(` Agents: ${data.agents?.length || 0}`);
160
- console.log(` Timestamp: ${new Date(data.timestamp).toISOString()}\n`);
171
+ const data = await apiRequest('/v1/health');
172
+ console.log(`\n ${C.green}${ICON.ok} Gateway Running${C.reset}`);
173
+ console.log(` Status: ${C.bold}${data.status}${C.reset} Uptime: ${C.cyan}${data.uptime_seconds}s${C.reset} Agents: ${C.green}${data.agents?.online || data.agents?.length || 0} online${C.reset} / ${data.agents?.total || data.agents?.length || 0} total`);
174
+ if (data.tasks) {
175
+ console.log(` Tasks: ${C.yellow}${data.tasks.pending}pending${C.reset} ${C.cyan}${data.tasks.running}running${C.reset} ${C.green}${data.tasks.completed}done${C.reset} ${C.red}${data.tasks.failed}failed${C.reset}`);
176
+ }
177
+ console.log('');
161
178
  }
162
179
  catch (err) {
163
- console.error(`\n Gateway not reachable at ${BASE_URL()}`);
164
- console.error(` Error: ${err.message}`);
165
- console.log(`\n Start it with: agentmesh start\n`);
180
+ console.error(`\n ${C.red}${ICON.fail} Gateway not reachable at ${BASE_URL()}${C.reset}`);
181
+ console.error(` ${C.dim}Error: ${err.message}${C.reset}`);
182
+ console.log(`\n Start it with: ${C.cyan}agentmesh start${C.reset}\n`);
166
183
  }
167
184
  }
168
185
  async function cmdModels() {
169
186
  try {
170
187
  const data = await apiRequest('/v1/models');
171
- console.log('\n 📋 Available Models:\n');
172
188
  const byProvider = {};
173
189
  for (const m of data.data || []) {
174
190
  (byProvider[m.owned_by] ??= []).push(m.id);
175
191
  }
192
+ const rows = [];
176
193
  for (const [provider, models] of Object.entries(byProvider)) {
177
- console.log(` ${provider}:`);
178
- models.forEach(m => console.log(` - ${m}`));
179
- console.log('');
194
+ rows.push([`${C.cyan}${provider}${C.reset}`, models.join(', ')]);
180
195
  }
196
+ console.log('\n ' + table(['Provider', 'Models'], rows) + '\n');
181
197
  }
182
198
  catch (err) {
183
- console.error(`\n ${err.message}\n`);
199
+ console.error(`\n ${C.red}${ICON.fail} ${err.message}${C.reset}\n`);
184
200
  }
185
201
  }
186
202
  async function cmdQuota() {
187
203
  try {
188
204
  console.log('\n ⏳ Fetching quota data (may take ~15s)...');
189
- const data = await apiRequest('/model-gateway/quota', { signal: AbortSignal.timeout(60_000) });
205
+ const data = await apiRequest('/v1/model-gateway/quota', { signal: AbortSignal.timeout(60_000) });
190
206
  console.log('\n 📊 Provider Quota Status:\n');
191
207
  if (!data || Object.keys(data).length === 0) {
192
208
  console.log(' No quota data available. Is codexbar installed?\n');
@@ -204,27 +220,46 @@ async function cmdQuota() {
204
220
  }
205
221
  async function cmdAgents() {
206
222
  try {
207
- const data = await apiRequest('/agents');
208
- console.log('\n 📋 Registered Agents:\n');
209
- data.forEach(a => console.log(` ${a.status === 'online' ? '🟢' : '⚫'} ${a.id.padEnd(18)} ${a.name.padEnd(22)} [${a.status}]\n ${(a.capabilities || []).join(', ')}\n`));
223
+ const data = await apiRequest('/v1/agents');
224
+ const rows = data.map(a => [
225
+ a.status === 'online' ? `${C.green}●${C.reset}` : `${C.dim}○${C.reset}`,
226
+ a.id,
227
+ a.name,
228
+ a.status,
229
+ (a.capabilities || []).slice(0, 3).join(', '),
230
+ ]);
231
+ console.log('\n ' + table(['', 'ID', 'Name', 'Status', 'Capabilities (top 3)'], rows) + '\n');
210
232
  }
211
233
  catch (err) {
212
- console.error(`\n ${err.message}\n`);
234
+ console.error(`\n ${C.red}${ICON.fail} ${err.message}${C.reset}\n`);
235
+ }
236
+ }
237
+ async function cmdCancel(taskId) {
238
+ try {
239
+ const data = await apiRequest(`/v1/tasks/${taskId}/cancel`, { method: 'POST' });
240
+ console.log(`\n ${C.green}${ICON.ok} Task ${data.task_id} cancelled${C.reset}\n`);
241
+ }
242
+ catch (err) {
243
+ console.error(`\n ${C.red}${ICON.fail} ${err.message}${C.reset}\n`);
213
244
  }
214
245
  }
215
246
  async function cmdTasks() {
216
247
  try {
217
- const tasks = await apiRequest('/tasks');
218
- console.log('\n 📋 Tasks:\n');
248
+ const tasks = await apiRequest('/v1/tasks');
219
249
  if (!tasks.length) {
220
- console.log(' (none)\n');
250
+ console.log(`\n ${C.dim}(no tasks)${C.reset}\n`);
221
251
  return;
222
252
  }
223
- tasks.forEach(t => console.log(` ${t.id?.slice(0, 8)}... ${t.status?.padEnd(10)} ${new Date(t.created_at).toLocaleString()}`));
224
- console.log('');
253
+ const rows = tasks.map(t => [
254
+ (STATUS_ICON[t.status] || ICON.dot) + ' ' + t.status,
255
+ t.id?.slice(0, 8) || '-',
256
+ String(t.assigned_agents?.length || 0),
257
+ new Date(t.created_at).toLocaleString(),
258
+ ]);
259
+ console.log('\n ' + table(['Status', 'ID', 'Agents', 'Created'], rows) + '\n');
225
260
  }
226
261
  catch (err) {
227
- console.error(`\n ${err.message}\n`);
262
+ console.error(`\n ${C.red}${ICON.fail} ${err.message}${C.reset}\n`);
228
263
  }
229
264
  }
230
265
  async function cmdConfig(args) {
@@ -253,9 +288,9 @@ async function cmdConfig(args) {
253
288
  async function cmdStatus() {
254
289
  try {
255
290
  const [health, models, stats] = await Promise.all([
256
- apiRequest('/health'),
291
+ apiRequest('/v1/health'),
257
292
  apiRequest('/v1/models').catch(() => ({ data: [] })),
258
- apiRequest('/model-gateway/stats').catch(() => null),
293
+ apiRequest('/v1/model-gateway/stats').catch(() => null),
259
294
  ]);
260
295
  console.log(`
261
296
  ╔═══════════════════════════════════════════════════╗
@@ -330,7 +365,7 @@ async function cmdDoctor() {
330
365
  }
331
366
  // Gateway status
332
367
  try {
333
- await apiRequest('/health');
368
+ await apiRequest('/v1/health');
334
369
  console.log(` ✅ Gateway Running at ${BASE_URL()}`);
335
370
  }
336
371
  catch {
@@ -382,6 +417,13 @@ async function main() {
382
417
  case 'tasks':
383
418
  await cmdTasks();
384
419
  break;
420
+ case 'cancel':
421
+ if (!rest[0]) {
422
+ console.error(`\n ${C.red}Usage: agentmesh cancel <task-id>${C.reset}\n`);
423
+ break;
424
+ }
425
+ await cmdCancel(rest[0]);
426
+ break;
385
427
  case 'config':
386
428
  await cmdConfig(rest);
387
429
  break;
@@ -434,6 +476,50 @@ async function main() {
434
476
  }
435
477
  break;
436
478
  }
479
+ case 'release':
480
+ const { runRelease } = await import('./cli/release.js');
481
+ await runRelease(rest[0] || 'patch');
482
+ break;
483
+ case 'hermes':
484
+ if (rest[0] === 'setup') {
485
+ console.log(`
486
+ ╔═══════════════════════════════════════════════════╗
487
+ ║ Hermes ↔ Agent Mesh 双向通路设置 ║
488
+ ╚═══════════════════════════════════════════════════╝
489
+
490
+ Hermes 网关已在运行(Discord + Weixin 已连接)。
491
+ 现在只需添加一个 webhook 订阅,让 Hermes 能调用本网关。
492
+
493
+ 方式 1: 手动订阅 (推荐)
494
+ hermes webhook subscribe \\
495
+ --name agentmesh \\
496
+ --url http://127.0.0.1:3000/hermes/task \\
497
+ --event message.received \\
498
+ --format '{"prompt":"{{message}}","model":"deepseek-chat"}'
499
+
500
+ 方式 2: 从 Discord/Weixin 用 !task 命令触发
501
+ 在 Hermes 的 skills 目录创建 agentmesh skill:
502
+ ~/.hermes/skills/agentmesh.md
503
+ 内容: "当用户发送 !task <描述> 时,POST 到 http://127.0.0.1:3000/hermes/task"
504
+
505
+ 当前网关端点:
506
+ POST /hermes/task 提交任务 (手机 → 网关)
507
+ GET /hermes/task/:id 查询结果 (网关 → 手机)
508
+ GET /hermes/health Hermes 健康检查
509
+
510
+ 使用流程:
511
+ 📱 手机 Discord/Weixin 发消息
512
+ → Hermes Gateway 接收
513
+ → Webhook → POST :3000/hermes/task
514
+ → Agent Mesh 执行
515
+ → 结果返回 Hermes
516
+ → 📱 手机收到回复
517
+ `);
518
+ }
519
+ else {
520
+ console.log('\n agentmesh hermes setup Hermes 双向通路设置指南\n');
521
+ }
522
+ break;
437
523
  case 'doctor':
438
524
  case 'check':
439
525
  await cmdDoctor();
@@ -12,6 +12,8 @@ export declare class AgentRegistry {
12
12
  * 从配置注册所有 Agent
13
13
  */
14
14
  private registerAllFromConfig;
15
+ /** 热重载:清空后重新从配置加载所有适配器 */
16
+ reload(): void;
15
17
  /**
16
18
  * 注册自定义适配器
17
19
  */
@@ -2,160 +2,7 @@ import { ProcessAdapter } from '../adapters/process.js';
2
2
  import { ClaudeCodeAdapter } from '../adapters/claude-code.js';
3
3
  import { OpenClawAdapter } from '../adapters/openclaw.js';
4
4
  import { getAllAgentConfigs } from './config.js';
5
- // 默认 Agent 配置
6
- const DEFAULT_AGENT_CONFIGS = {
7
- 'claude-code': {
8
- name: 'Claude Code',
9
- capabilities: ['code-generation', 'code-review', 'debugging', 'refactoring', 'documentation', 'file-operations'],
10
- command: 'claude',
11
- args: ['-p']
12
- },
13
- 'openclaw': {
14
- name: 'OpenClaw',
15
- capabilities: ['browser-automation', 'web-scraping', 'form-filling', 'ui-testing'],
16
- command: 'openclaw',
17
- args: ['--task']
18
- },
19
- 'opencode': {
20
- name: 'OpenCode',
21
- capabilities: ['code-completion', 'code-generation', 'refactoring', 'debugging'],
22
- command: 'opencode',
23
- args: ['--task']
24
- },
25
- 'gemini': {
26
- name: 'Google Gemini CLI',
27
- capabilities: ['code-generation', 'multimodal', 'reasoning', 'analysis'],
28
- command: 'gemini',
29
- args: ['--prompt']
30
- },
31
- 'codex': {
32
- name: 'OpenAI Codex',
33
- capabilities: ['code-generation', 'code-explanation', 'refactoring'],
34
- command: 'codex',
35
- args: ['complete']
36
- },
37
- 'github-copilot': {
38
- name: 'GitHub Copilot',
39
- capabilities: ['code-completion', 'code-suggestions', 'refactoring'],
40
- command: 'copilot',
41
- args: ['--ask']
42
- },
43
- 'qwen-code': {
44
- name: 'Qwen Code',
45
- capabilities: ['code-generation', 'code-review', 'multilingual'],
46
- command: 'qwen-code',
47
- args: ['--task']
48
- },
49
- 'crush': {
50
- name: 'CRUSH AI',
51
- capabilities: ['code-generation', 'debugging', 'security-analysis'],
52
- command: 'crush',
53
- args: ['run']
54
- },
55
- 'droid': {
56
- name: 'Droid Agent',
57
- capabilities: ['android-development', 'mobile-debugging', 'device-control'],
58
- command: 'droid',
59
- args: ['--task']
60
- },
61
- 'factory': {
62
- name: 'Factory AI',
63
- capabilities: ['code-generation', 'testing', 'documentation', 'refactoring'],
64
- command: 'factory',
65
- args: ['--task']
66
- },
67
- 'cursor': {
68
- name: 'Cursor',
69
- capabilities: ['code-completion', 'code-generation', 'refactoring', 'chat'],
70
- command: 'cursor',
71
- args: ['--task']
72
- },
73
- 'windsurf': {
74
- name: 'Windsurf',
75
- capabilities: ['code-generation', 'agentic-coding', 'flow-state'],
76
- command: 'windsurf',
77
- args: ['--task']
78
- },
79
- 'zed': {
80
- name: 'Zed AI',
81
- capabilities: ['code-generation', 'collaboration', 'high-performance'],
82
- command: 'zed',
83
- args: ['--ai-task']
84
- },
85
- 'aider': {
86
- name: 'Aider',
87
- capabilities: ['git-based-editing', 'code-refactoring', 'multi-file-changes'],
88
- command: 'aider',
89
- args: ['--message']
90
- },
91
- 'cline': {
92
- name: 'Cline',
93
- capabilities: ['autonomous-coding', 'file-operations', 'command-execution'],
94
- command: 'cline',
95
- args: ['--task']
96
- },
97
- 'roo-code': {
98
- name: 'Roo Code',
99
- capabilities: ['code-generation', 'agentic-mode', 'workspace-awareness'],
100
- command: 'roo-code',
101
- args: ['--task']
102
- },
103
- // 2026 新增 Agent
104
- 'perplexity': {
105
- name: 'Perplexity',
106
- capabilities: ['research', 'web-search', 'fact-checking', 'analysis'],
107
- command: 'perplexity',
108
- args: ['--query']
109
- },
110
- 'grok': {
111
- name: 'xAI Grok',
112
- capabilities: ['reasoning', 'humor', 'code-generation', 'analysis'],
113
- command: 'grok',
114
- args: ['--prompt']
115
- },
116
- 'phind': {
117
- name: 'Phind',
118
- capabilities: ['developer-search', 'code-search', 'documentation-search'],
119
- command: 'phind',
120
- args: ['--search']
121
- },
122
- 'you': {
123
- name: 'You.com AI',
124
- capabilities: ['web-search', 'code-search', 'general-assistant'],
125
- command: 'you',
126
- args: ['--query']
127
- },
128
- 'lepton': {
129
- name: 'Lepton AI',
130
- capabilities: ['code-generation', 'conversation', 'analysis'],
131
- command: 'lepton',
132
- args: ['--prompt']
133
- },
134
- 'ollama': {
135
- name: 'Ollama',
136
- capabilities: ['local-llm', 'code-generation', 'privacy-focused'],
137
- command: 'ollama',
138
- args: ['run']
139
- },
140
- 'llama': {
141
- name: 'Meta Llama',
142
- capabilities: ['code-generation', 'reasoning', 'open-source'],
143
- command: 'llama',
144
- args: ['--prompt']
145
- },
146
- 'mistral': {
147
- name: 'Mistral AI',
148
- capabilities: ['code-generation', 'reasoning', 'multilingual'],
149
- command: 'mistral',
150
- args: ['--task']
151
- },
152
- 'anthropic': {
153
- name: 'Anthropic CLI',
154
- capabilities: ['conversation', 'reasoning', 'code-generation'],
155
- command: 'anthropic',
156
- args: ['--prompt']
157
- }
158
- };
5
+ import { DEFAULT_AGENT_CONFIGS } from './agents.default.js';
159
6
  export class AgentRegistry {
160
7
  adapters = new Map();
161
8
  initialized = false;
@@ -211,6 +58,17 @@ export class AgentRegistry {
211
58
  console.log(`[AgentRegistry] Registered default: ${id}`);
212
59
  }
213
60
  }
61
+ /** 热重载:清空后重新从配置加载所有适配器 */
62
+ reload() {
63
+ // 保留内置适配器(ClaudeCode, OpenClaw),清除其余
64
+ const preserved = new Set(['claude-code', 'openclaw']);
65
+ for (const key of this.adapters.keys()) {
66
+ if (!preserved.has(key))
67
+ this.adapters.delete(key);
68
+ }
69
+ this.initialized = false;
70
+ this.initialize();
71
+ }
214
72
  /**
215
73
  * 注册自定义适配器
216
74
  */
@@ -0,0 +1,7 @@
1
+ export declare const DEFAULT_AGENT_CONFIGS: Record<string, {
2
+ name: string;
3
+ capabilities: string[];
4
+ command: string;
5
+ args?: string[];
6
+ env?: Record<string, string>;
7
+ }>;