@ai-setting/roy-agent-cli 1.0.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 (158) hide show
  1. package/README.md +126 -0
  2. package/dist/bin/roy.js +127297 -0
  3. package/dist/roy-agent-darwin-arm64/bin/roy.js +127297 -0
  4. package/dist/roy-agent-darwin-x64/bin/roy.js +127297 -0
  5. package/dist/roy-agent-linux-arm64/bin/roy.js +127297 -0
  6. package/dist/roy-agent-linux-x64/bin/roy.js +127297 -0
  7. package/dist/roy-agent-windows-x64/bin/roy.js +127297 -0
  8. package/package.json +91 -0
  9. package/src/bin/roy.ts +12 -0
  10. package/src/cli.ts +101 -0
  11. package/src/commands/act.ts +480 -0
  12. package/src/commands/commands-add.ts +110 -0
  13. package/src/commands/commands-dirs.ts +70 -0
  14. package/src/commands/commands-info.ts +90 -0
  15. package/src/commands/commands-list.ts +161 -0
  16. package/src/commands/commands-remove.ts +147 -0
  17. package/src/commands/commands.ts +55 -0
  18. package/src/commands/config/config-service.test.ts +449 -0
  19. package/src/commands/config/config-service.ts +312 -0
  20. package/src/commands/config/deep-merge.test.ts +168 -0
  21. package/src/commands/config/deep-merge.ts +63 -0
  22. package/src/commands/config/export.ts +97 -0
  23. package/src/commands/config/filter-history-e2e.test.ts +141 -0
  24. package/src/commands/config/import-preserve-refs.test.ts +212 -0
  25. package/src/commands/config/import.ts +119 -0
  26. package/src/commands/config/index.ts +35 -0
  27. package/src/commands/config/list.ts +281 -0
  28. package/src/commands/config/roy-config-e2e.test.ts +297 -0
  29. package/src/commands/config/types.ts +54 -0
  30. package/src/commands/debug/index.ts +38 -0
  31. package/src/commands/debug/log.test.ts +233 -0
  32. package/src/commands/debug/log.ts +123 -0
  33. package/src/commands/debug/span.test.ts +297 -0
  34. package/src/commands/debug/span.ts +211 -0
  35. package/src/commands/debug/trace.test.ts +254 -0
  36. package/src/commands/debug/trace.ts +140 -0
  37. package/src/commands/eventsource/add.ts +133 -0
  38. package/src/commands/eventsource/index.ts +48 -0
  39. package/src/commands/eventsource/list.ts +194 -0
  40. package/src/commands/eventsource/remove.ts +95 -0
  41. package/src/commands/eventsource/start.ts +103 -0
  42. package/src/commands/eventsource/status.ts +185 -0
  43. package/src/commands/eventsource/stop.ts +89 -0
  44. package/src/commands/index.ts +22 -0
  45. package/src/commands/input-handler.test.ts +76 -0
  46. package/src/commands/input-handler.ts +43 -0
  47. package/src/commands/interactive-esc.test.ts +254 -0
  48. package/src/commands/interactive.shutdown.test.ts +122 -0
  49. package/src/commands/interactive.test.ts +221 -0
  50. package/src/commands/interactive.ts +1015 -0
  51. package/src/commands/lsp/check.ts +92 -0
  52. package/src/commands/lsp/index.ts +32 -0
  53. package/src/commands/lsp/install.ts +126 -0
  54. package/src/commands/lsp/list.ts +64 -0
  55. package/src/commands/mcp/index.ts +27 -0
  56. package/src/commands/mcp/list.ts +116 -0
  57. package/src/commands/mcp/reload.ts +70 -0
  58. package/src/commands/mcp/tools.ts +121 -0
  59. package/src/commands/memory/extract-e2e.test.ts +388 -0
  60. package/src/commands/memory/index.ts +11 -0
  61. package/src/commands/memory/memory-simplified.test.ts +58 -0
  62. package/src/commands/memory/memory.ts +25 -0
  63. package/src/commands/memory/organize.ts +300 -0
  64. package/src/commands/memory/recall.test.ts +120 -0
  65. package/src/commands/memory/recall.ts +88 -0
  66. package/src/commands/memory/record-extract-handle-query.test.ts +385 -0
  67. package/src/commands/memory/record-prompt-component.test.ts +343 -0
  68. package/src/commands/memory/record.test.ts +92 -0
  69. package/src/commands/memory/record.ts +332 -0
  70. package/src/commands/plugin.test.ts +292 -0
  71. package/src/commands/plugin.ts +267 -0
  72. package/src/commands/sessions/active.ts +96 -0
  73. package/src/commands/sessions/add-message.ts +96 -0
  74. package/src/commands/sessions/checkpoints.ts +154 -0
  75. package/src/commands/sessions/compact.test.ts +215 -0
  76. package/src/commands/sessions/compact.ts +269 -0
  77. package/src/commands/sessions/delete.ts +236 -0
  78. package/src/commands/sessions/get.ts +165 -0
  79. package/src/commands/sessions/grep.ts +233 -0
  80. package/src/commands/sessions/index.ts +95 -0
  81. package/src/commands/sessions/list.ts +210 -0
  82. package/src/commands/sessions/messages.test.ts +333 -0
  83. package/src/commands/sessions/messages.ts +248 -0
  84. package/src/commands/sessions/mock.ts +194 -0
  85. package/src/commands/sessions/new.ts +82 -0
  86. package/src/commands/sessions/rename.ts +98 -0
  87. package/src/commands/shared/event-handler.ts +213 -0
  88. package/src/commands/shared/event-message-formatter.ts +295 -0
  89. package/src/commands/shared/index.ts +11 -0
  90. package/src/commands/shared/query-executor.test.ts +434 -0
  91. package/src/commands/shared/query-executor.ts +324 -0
  92. package/src/commands/shared/repl-engine.test.ts +354 -0
  93. package/src/commands/shared/session-manager.test.ts +212 -0
  94. package/src/commands/shared/session-manager.ts +114 -0
  95. package/src/commands/skills/get.ts +90 -0
  96. package/src/commands/skills/index.ts +39 -0
  97. package/src/commands/skills/list.ts +129 -0
  98. package/src/commands/skills/reload.ts +59 -0
  99. package/src/commands/skills/search.ts +132 -0
  100. package/src/commands/skills/show-config.ts +93 -0
  101. package/src/commands/tasks/complete.ts +92 -0
  102. package/src/commands/tasks/create.ts +118 -0
  103. package/src/commands/tasks/delete.ts +86 -0
  104. package/src/commands/tasks/get.ts +116 -0
  105. package/src/commands/tasks/index.ts +53 -0
  106. package/src/commands/tasks/list.ts +140 -0
  107. package/src/commands/tasks/operations.ts +120 -0
  108. package/src/commands/tasks/update.ts +122 -0
  109. package/src/commands/tools/exec-tool.ts +128 -0
  110. package/src/commands/tools/get.ts +114 -0
  111. package/src/commands/tools/index.ts +35 -0
  112. package/src/commands/tools/list.ts +107 -0
  113. package/src/commands/tools/shared/index.ts +7 -0
  114. package/src/commands/tools/shared/schema-helper.ts +111 -0
  115. package/src/commands/workflow/commands/add.ts +315 -0
  116. package/src/commands/workflow/commands/get.ts +193 -0
  117. package/src/commands/workflow/commands/list.ts +137 -0
  118. package/src/commands/workflow/commands/nodes.ts +528 -0
  119. package/src/commands/workflow/commands/remove.ts +94 -0
  120. package/src/commands/workflow/commands/run.ts +398 -0
  121. package/src/commands/workflow/commands/status.ts +147 -0
  122. package/src/commands/workflow/commands/stop.ts +91 -0
  123. package/src/commands/workflow/commands/update.ts +130 -0
  124. package/src/commands/workflow/commands/validate.ts +139 -0
  125. package/src/commands/workflow/commands/workflow-cli.test.ts +196 -0
  126. package/src/commands/workflow/index.ts +65 -0
  127. package/src/commands/workflow/renderers.ts +358 -0
  128. package/src/commands/workflow/validators/index.ts +8 -0
  129. package/src/commands/workflow/validators/node-validator-factory.ts +40 -0
  130. package/src/commands/workflow/validators/node-validator.ts +125 -0
  131. package/src/commands/workflow/validators/nodes/agent-node-validator.ts +58 -0
  132. package/src/commands/workflow/validators/nodes/condition-node-validator.ts +34 -0
  133. package/src/commands/workflow/validators/nodes/decorator-node-validator.ts +45 -0
  134. package/src/commands/workflow/validators/nodes/merge-node-validator.ts +46 -0
  135. package/src/commands/workflow/validators/nodes/skill-node-validator.ts +33 -0
  136. package/src/commands/workflow/validators/nodes/tool-node-validator.ts +54 -0
  137. package/src/commands/workflow/validators/nodes/workflow-node-validator.ts +33 -0
  138. package/src/commands/workflow/validators/types.ts +78 -0
  139. package/src/commands/workflow/validators/workflow-validator.test.ts +273 -0
  140. package/src/commands/workflow/validators/workflow-validator.ts +320 -0
  141. package/src/index.ts +19 -0
  142. package/src/plugin/apply.ts +103 -0
  143. package/src/plugin/discover.ts +219 -0
  144. package/src/plugin/index.ts +45 -0
  145. package/src/plugin/registry.ts +272 -0
  146. package/src/plugin/types.ts +165 -0
  147. package/src/services/context-handler.service.test.ts +501 -0
  148. package/src/services/context-handler.service.ts +372 -0
  149. package/src/services/environment.service.commands-prompt.test.ts +167 -0
  150. package/src/services/environment.service.ts +656 -0
  151. package/src/services/output.service.test.ts +92 -0
  152. package/src/services/output.service.ts +122 -0
  153. package/src/services/quiet-mode.service.test.ts +114 -0
  154. package/src/services/quiet-mode.service.ts +81 -0
  155. package/src/services/stream-output.service.test.ts +214 -0
  156. package/src/services/stream-output.service.ts +323 -0
  157. package/src/util/which.test.ts +101 -0
  158. package/src/util/which.ts +55 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @fileoverview LSP Check Command
3
+ */
4
+
5
+ import { CommandModule } from "yargs";
6
+ import { createInstaller, LSP_PACKAGES, LSPConfigLoader } from "@ai-setting/roy-agent-coder-harness";
7
+
8
+ /**
9
+ * 创建 lsp check 命令
10
+ */
11
+ export const LspCheckCommand: CommandModule = {
12
+ command: "check [server-id]",
13
+ describe: "Check LSP server status and configuration",
14
+
15
+ builder: (yargs) =>
16
+ yargs
17
+ .positional("server-id", {
18
+ describe: "Check specific server (e.g., typescript)",
19
+ type: "string",
20
+ })
21
+ .option("verbose", {
22
+ alias: "v",
23
+ type: "boolean",
24
+ default: false,
25
+ description: "Show detailed information",
26
+ })
27
+ .option("json", {
28
+ type: "boolean",
29
+ default: false,
30
+ description: "Output as JSON",
31
+ }),
32
+
33
+ handler: async (argv) => {
34
+ const installer = createInstaller();
35
+ const configLoader = new LSPConfigLoader();
36
+ const config = configLoader.load();
37
+
38
+ if (argv.json) {
39
+ const servers = argv.serverId
40
+ ? LSP_PACKAGES.filter((p) => p.serverId === argv.serverId)
41
+ : LSP_PACKAGES;
42
+
43
+ const result = {
44
+ config: config.toJSON(),
45
+ servers: servers.map((pkg) => ({
46
+ serverId: pkg.serverId,
47
+ npmPackage: pkg.npmPackage,
48
+ description: pkg.description,
49
+ installed: installer.isInstalled(pkg.npmPackage),
50
+ verify: installer.verify(pkg.serverId),
51
+ })),
52
+ };
53
+ console.log(JSON.stringify(result, null, 2));
54
+ return;
55
+ }
56
+
57
+ console.log("\n⚙️ LSP Configuration\n");
58
+ console.log(` Config Path: ${configLoader.getConfigPath()}`);
59
+ console.log(` Install Path: ${config.installPath}`);
60
+ console.log(` Preload: ${config.preload ? "enabled" : "disabled"}`);
61
+ console.log(` Idle Timeout: ${config.idleTimeout}ms`);
62
+
63
+ const servers = argv.serverId
64
+ ? LSP_PACKAGES.filter((p) => p.serverId === argv.serverId)
65
+ : LSP_PACKAGES;
66
+
67
+ console.log("\n📦 LSP Servers Status\n");
68
+
69
+ let hasIssues = false;
70
+ for (const pkg of servers) {
71
+ const verify = installer.verify(pkg.serverId);
72
+ const installed = verify.installed ? "✓ Installed" : "✗ Not installed";
73
+
74
+ console.log(` ${pkg.serverId.padEnd(12)} ${pkg.description}`);
75
+ console.log(` ${installed}`);
76
+ console.log(` Package: ${pkg.npmPackage}`);
77
+
78
+ if (verify.binary) {
79
+ console.log(` Binary in PATH: ${verify.binary}`);
80
+ } else if (verify.installed) {
81
+ console.log(` Warning: Installed but not in PATH`);
82
+ hasIssues = true;
83
+ }
84
+ }
85
+
86
+ console.log();
87
+ if (hasIssues) {
88
+ console.log("⚠️ Some servers are installed but not in PATH.");
89
+ console.log(" Run 'npm config get prefix' to check npm global path\n");
90
+ }
91
+ },
92
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview LSP Command Group
3
+ */
4
+
5
+ import { CommandModule } from "yargs";
6
+ import { LspInstallCommand } from "./install";
7
+ import { LspListCommand } from "./list";
8
+ import { LspCheckCommand } from "./check";
9
+
10
+ /**
11
+ * LSP Command
12
+ */
13
+ export const LspCommand: CommandModule = {
14
+ command: "lsp",
15
+ describe: "Manage LSP (Language Server Protocol) servers",
16
+
17
+ builder: (yargs) =>
18
+ yargs
19
+ .command(LspInstallCommand)
20
+ .command(LspListCommand)
21
+ .command(LspCheckCommand)
22
+ .demandCommand()
23
+ .help(),
24
+
25
+ handler: () => {
26
+ console.log("Use 'roy lsp --help' for usage information");
27
+ },
28
+ };
29
+
30
+ export { LspInstallCommand } from "./install";
31
+ export { LspListCommand } from "./list";
32
+ export { LspCheckCommand } from "./check";
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @fileoverview LSP Install Command
3
+ */
4
+
5
+ import { CommandModule } from "yargs";
6
+ import { createInstaller, LSP_PACKAGES } from "@ai-setting/roy-agent-coder-harness";
7
+
8
+ /**
9
+ * 创建 lsp install 命令
10
+ */
11
+ export const LspInstallCommand: CommandModule = {
12
+ command: "install [languages...]",
13
+ describe: "Install LSP server dependencies",
14
+
15
+ builder: (yargs) =>
16
+ yargs
17
+ .positional("languages", {
18
+ describe: "Languages to install (e.g., typescript, python)",
19
+ type: "string",
20
+ })
21
+ .option("global", {
22
+ alias: "g",
23
+ type: "boolean",
24
+ default: true,
25
+ description: "Install globally",
26
+ })
27
+ .option("local", {
28
+ alias: "l",
29
+ type: "string",
30
+ description: "Install to local path",
31
+ })
32
+ .option("all", {
33
+ alias: "a",
34
+ type: "boolean",
35
+ default: false,
36
+ description: "Install all available LSP servers",
37
+ })
38
+ .option("check", {
39
+ type: "boolean",
40
+ default: false,
41
+ description: "Only check if installed, don't install",
42
+ })
43
+ .option("verbose", {
44
+ alias: "v",
45
+ type: "boolean",
46
+ default: false,
47
+ description: "Verbose output",
48
+ }),
49
+
50
+ handler: async (argv) => {
51
+ const installer = createInstaller({
52
+ target: argv.local ? "local" : "global",
53
+ installPath: argv.local as string,
54
+ });
55
+
56
+ const languages = argv.languages as string[] | undefined;
57
+
58
+ if (argv.check) {
59
+ // Check mode
60
+ const installed = installer.getInstalledPackages();
61
+ const missing = installer.getMissingDependencies();
62
+
63
+ console.log("\n📦 LSP Server Status\n");
64
+
65
+ for (const pkg of LSP_PACKAGES) {
66
+ const isInstalled = installed.includes(pkg.serverId);
67
+ const status = isInstalled ? "✓ installed" : "✗ not installed";
68
+ console.log(` ${status.padEnd(20)} ${pkg.serverId.padEnd(12)} ${pkg.description}`);
69
+ }
70
+
71
+ console.log(`\n${installed.length}/${LSP_PACKAGES.length} installed\n`);
72
+
73
+ if (missing.length > 0) {
74
+ console.log("Run 'roy lsp install' to install missing servers\n");
75
+ }
76
+ return;
77
+ }
78
+
79
+ if (languages && languages.length > 0) {
80
+ // Install specific languages
81
+ const success: string[] = [];
82
+ const failed: string[] = [];
83
+
84
+ for (const lang of languages) {
85
+ const langLower = lang.toLowerCase();
86
+ if (installer.install(langLower, { verbose: !!argv.verbose })) {
87
+ success.push(langLower);
88
+ } else {
89
+ failed.push(langLower);
90
+ }
91
+ }
92
+
93
+ console.log(`\n📦 Installation Summary\n`);
94
+ if (success.length > 0) {
95
+ console.log(` ✓ Installed: ${success.join(", ")}`);
96
+ }
97
+ if (failed.length > 0) {
98
+ console.log(` ✗ Failed: ${failed.join(", ")}`);
99
+ }
100
+ console.log();
101
+ } else if (argv.all) {
102
+ // Install all
103
+ console.log("\n📦 Installing all LSP servers...\n");
104
+ const result = installer.installAll({ verbose: !!argv.verbose });
105
+
106
+ console.log(`\n📦 Installation Summary\n`);
107
+ if (result.success.length > 0) {
108
+ console.log(` ✓ Installed: ${result.success.join(", ")}`);
109
+ }
110
+ if (result.failed.length > 0) {
111
+ console.log(` ✗ Failed: ${result.failed.join(", ")}`);
112
+ }
113
+ console.log();
114
+ } else {
115
+ // Show available
116
+ console.log("\n📦 Available LSP Servers\n");
117
+ for (const pkg of LSP_PACKAGES) {
118
+ const isInstalled = installer.isInstalled(pkg.npmPackage);
119
+ const status = isInstalled ? "✓" : "○";
120
+ console.log(` ${status} ${pkg.serverId.padEnd(12)} ${pkg.description}`);
121
+ }
122
+ console.log("\n Run 'roy lsp install <language>' to install specific servers");
123
+ console.log(" Run 'roy lsp install --all' to install all servers\n");
124
+ }
125
+ },
126
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview LSP List Command
3
+ */
4
+
5
+ import { CommandModule } from "yargs";
6
+ import { createInstaller, LSP_PACKAGES } from "@ai-setting/roy-agent-coder-harness";
7
+
8
+ /**
9
+ * 创建 lsp list 命令
10
+ */
11
+ export const LspListCommand: CommandModule = {
12
+ command: "list",
13
+ describe: "List installed LSP servers",
14
+
15
+ builder: (yargs) =>
16
+ yargs
17
+ .option("verbose", {
18
+ alias: "v",
19
+ type: "boolean",
20
+ default: false,
21
+ description: "Show detailed information",
22
+ })
23
+ .option("json", {
24
+ type: "boolean",
25
+ default: false,
26
+ description: "Output as JSON",
27
+ }),
28
+
29
+ handler: async (argv) => {
30
+ const installer = createInstaller();
31
+ const installed = installer.getInstalledPackages();
32
+
33
+ if (argv.json) {
34
+ const result = LSP_PACKAGES.map((pkg) => ({
35
+ serverId: pkg.serverId,
36
+ npmPackage: pkg.npmPackage,
37
+ description: pkg.description,
38
+ installed: installed.includes(pkg.serverId),
39
+ }));
40
+ console.log(JSON.stringify(result, null, 2));
41
+ return;
42
+ }
43
+
44
+ console.log("\n📦 LSP Servers\n");
45
+
46
+ for (const pkg of LSP_PACKAGES) {
47
+ const isInstalled = installed.includes(pkg.serverId);
48
+ const status = isInstalled ? "✓" : "○";
49
+ const installedText = isInstalled ? "installed" : "not installed";
50
+
51
+ console.log(` ${status} ${pkg.serverId.padEnd(12)} ${pkg.description}`);
52
+ console.log(` ${pkg.npmPackage} - ${installedText}`);
53
+
54
+ if (argv.verbose && isInstalled) {
55
+ const verify = installer.verify(pkg.serverId);
56
+ if (verify.binary) {
57
+ console.log(` Binary: ${verify.binary}`);
58
+ }
59
+ }
60
+ }
61
+
62
+ console.log(`\n${installed.length}/${LSP_PACKAGES.length} installed\n`);
63
+ },
64
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @fileoverview MCP Commands
3
+ *
4
+ * 命令组:roy mcp
5
+ */
6
+
7
+ import { CommandModule } from "yargs";
8
+ import { ListCommand } from "./list";
9
+ import { ToolsCommand } from "./tools";
10
+ import { ReloadCommand } from "./reload";
11
+
12
+ export const McpCommand: CommandModule<object, {}> = {
13
+ command: "mcp",
14
+ describe: "MCP 服务器管理",
15
+ builder: (yargs) =>
16
+ yargs
17
+ .command(ListCommand)
18
+ .command(ToolsCommand)
19
+ .command(ReloadCommand)
20
+ .demandCommand(1, "请指定一个子命令")
21
+ .help(),
22
+ handler: () => {}, // Required but never called since subcommands handle themselves
23
+ };
24
+
25
+ export { ListCommand } from "./list";
26
+ export { ToolsCommand } from "./tools";
27
+ export { ReloadCommand } from "./reload";
@@ -0,0 +1,116 @@
1
+ /**
2
+ * @fileoverview MCP List Command
3
+ *
4
+ * 命令:roy mcp list
5
+ */
6
+
7
+ import { CommandModule } from "yargs";
8
+ import { EnvironmentService } from "../../services/environment.service";
9
+ import { OutputService } from "../../services/output.service";
10
+ import chalk from "chalk";
11
+ import type { McpComponent } from "@ai-setting/roy-agent-core";
12
+
13
+ interface ListOptions {
14
+ json?: boolean;
15
+ quiet?: boolean;
16
+ config?: string;
17
+ }
18
+
19
+ export const ListCommand: CommandModule<object, ListOptions> = {
20
+ command: "list",
21
+ aliases: ["ls"],
22
+ describe: "列出所有 MCP 服务器及其状态",
23
+
24
+ builder: (yargs) =>
25
+ yargs
26
+ .option("json", {
27
+ alias: "j",
28
+ type: "boolean",
29
+ default: false,
30
+ description: "JSON 输出",
31
+ })
32
+ .option("quiet", {
33
+ alias: "q",
34
+ type: "boolean",
35
+ default: false,
36
+ description: "简洁输出",
37
+ }),
38
+
39
+ async handler(args) {
40
+ const output = new OutputService();
41
+ const envService = new EnvironmentService(output);
42
+
43
+ try {
44
+ await envService.create({ configPath: args.config });
45
+ const env = envService.getEnvironment();
46
+ if (!env) {
47
+ output.error("Failed to create environment");
48
+ process.exit(1);
49
+ }
50
+ const mcpComponent = env.getComponent("mcp") as McpComponent | undefined;
51
+
52
+ if (!mcpComponent) {
53
+ output.error("McpComponent not available");
54
+ process.exit(1);
55
+ }
56
+
57
+ const servers = mcpComponent.listServers();
58
+
59
+ if (args.json) {
60
+ output.json({
61
+ servers: servers.map(s => ({
62
+ name: s.name,
63
+ status: s.status,
64
+ error: s.error,
65
+ toolsCount: s.toolsCount,
66
+ })),
67
+ count: servers.length,
68
+ });
69
+ } else if (args.quiet) {
70
+ servers.forEach(s => output.log(s.name));
71
+ } else {
72
+ if (servers.length === 0) {
73
+ output.log(chalk.yellow("No MCP servers configured"));
74
+ return;
75
+ }
76
+
77
+ const statusColor = (status: string) => {
78
+ switch (status) {
79
+ case "connected": return chalk.green;
80
+ case "connecting": return chalk.yellow;
81
+ case "error": return chalk.red;
82
+ case "disconnected": return chalk.gray;
83
+ default: return chalk.white;
84
+ }
85
+ };
86
+
87
+ const header = [
88
+ chalk.bold("Name"),
89
+ chalk.bold("Status"),
90
+ chalk.bold("Tools"),
91
+ ].join(" | ");
92
+
93
+ const rows = servers.map(s => [
94
+ chalk.cyan(s.name),
95
+ statusColor(s.status)(`[${s.status}]`),
96
+ s.toolsCount !== undefined ? String(s.toolsCount) : "-",
97
+ ].join(" | "));
98
+
99
+ output.log([
100
+ `┌─ MCP Servers ${"─".repeat(40)}┐`,
101
+ `│${header}│`,
102
+ "├" + "─".repeat(header.length + 2) + "┤",
103
+ ...rows.map(r => `│${r}│`),
104
+ "└" + "─".repeat(header.length + 2) + "┘",
105
+ "",
106
+ chalk.gray(`Total: ${servers.length} servers`),
107
+ ].join("\n"));
108
+ }
109
+ } catch (error) {
110
+ output.error(`Failed to list MCP servers: ${error}`);
111
+ process.exit(1);
112
+ } finally {
113
+ await envService.dispose();
114
+ }
115
+ },
116
+ };
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview MCP Reload Command
3
+ *
4
+ * 命令:roy mcp reload
5
+ */
6
+
7
+ import { CommandModule } from "yargs";
8
+ import { EnvironmentService } from "../../services/environment.service";
9
+ import { OutputService } from "../../services/output.service";
10
+ import chalk from "chalk";
11
+ import type { McpComponent } from "@ai-setting/roy-agent-core";
12
+
13
+ interface ReloadOptions {
14
+ config?: string;
15
+ }
16
+
17
+ export const ReloadCommand: CommandModule<object, ReloadOptions> = {
18
+ command: "reload",
19
+ aliases: ["r"],
20
+ describe: "重新加载 MCP 服务器",
21
+
22
+ builder: (yargs) =>
23
+ yargs,
24
+
25
+ async handler(args) {
26
+ const output = new OutputService();
27
+ const envService = new EnvironmentService(output);
28
+
29
+ try {
30
+ await envService.create({ configPath: args.config });
31
+ const env = envService.getEnvironment();
32
+ if (!env) {
33
+ output.error("Failed to create environment");
34
+ process.exit(1);
35
+ }
36
+ const mcpComponent = env.getComponent("mcp") as McpComponent | undefined;
37
+
38
+ if (!mcpComponent) {
39
+ output.error("McpComponent not available");
40
+ process.exit(1);
41
+ }
42
+
43
+ output.log(chalk.cyan("Reloading MCP servers..."));
44
+
45
+ await mcpComponent.reload();
46
+
47
+ const servers = mcpComponent.listServers();
48
+ const connected = servers.filter(s => s.status === "connected").length;
49
+ const errors = servers.filter(s => s.status === "error").length;
50
+
51
+ output.log(chalk.green(`✓ Reloaded ${servers.length} servers`));
52
+
53
+ if (connected > 0) {
54
+ output.log(chalk.green(` • ${connected} connected`));
55
+ }
56
+
57
+ if (errors > 0) {
58
+ output.warn(` • ${errors} failed`);
59
+ for (const server of servers.filter(s => s.status === "error")) {
60
+ output.log(chalk.gray(` - ${server.name}: ${server.error}`));
61
+ }
62
+ }
63
+ } catch (error) {
64
+ output.error(`Failed to reload MCP servers: ${error}`);
65
+ process.exit(1);
66
+ } finally {
67
+ await envService.dispose();
68
+ }
69
+ },
70
+ };
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @fileoverview MCP Tools Command
3
+ *
4
+ * 命令:roy mcp tools
5
+ */
6
+
7
+ import { CommandModule } from "yargs";
8
+ import { EnvironmentService } from "../../services/environment.service";
9
+ import { OutputService } from "../../services/output.service";
10
+ import chalk from "chalk";
11
+ import type { McpComponent } from "@ai-setting/roy-agent-core";
12
+
13
+ interface ToolsOptions {
14
+ server?: string;
15
+ json?: boolean;
16
+ quiet?: boolean;
17
+ config?: string;
18
+ }
19
+
20
+ export const ToolsCommand: CommandModule<object, ToolsOptions> = {
21
+ command: "tools",
22
+ aliases: ["t"],
23
+ describe: "列出所有 MCP 工具",
24
+
25
+ builder: (yargs) =>
26
+ yargs
27
+ .option("server", {
28
+ alias: "s",
29
+ type: "string",
30
+ description: "按服务器筛选",
31
+ })
32
+ .option("json", {
33
+ alias: "j",
34
+ type: "boolean",
35
+ default: false,
36
+ description: "JSON 输出",
37
+ })
38
+ .option("quiet", {
39
+ alias: "q",
40
+ type: "boolean",
41
+ default: false,
42
+ description: "简洁输出",
43
+ }),
44
+
45
+ async handler(args) {
46
+ const output = new OutputService();
47
+ const envService = new EnvironmentService(output);
48
+
49
+ try {
50
+ await envService.create({ configPath: args.config });
51
+ const env = envService.getEnvironment();
52
+ if (!env) {
53
+ output.error("Failed to create environment");
54
+ process.exit(1);
55
+ }
56
+ const mcpComponent = env.getComponent("mcp") as McpComponent | undefined;
57
+
58
+ if (!mcpComponent) {
59
+ output.error("McpComponent not available");
60
+ process.exit(1);
61
+ }
62
+
63
+ let tools = mcpComponent.listTools();
64
+
65
+ // 按服务器筛选
66
+ if (args.server) {
67
+ tools = tools.filter(t =>
68
+ t.metadata?.tags?.includes(args.server!)
69
+ );
70
+ }
71
+
72
+ if (args.json) {
73
+ output.json({
74
+ tools: tools.map(t => ({
75
+ name: t.name,
76
+ description: t.description,
77
+ category: t.metadata?.category,
78
+ tags: t.metadata?.tags,
79
+ })),
80
+ count: tools.length,
81
+ });
82
+ } else if (args.quiet) {
83
+ tools.forEach(t => output.log(t.name));
84
+ } else {
85
+ if (tools.length === 0) {
86
+ output.log(chalk.yellow("No MCP tools available"));
87
+ return;
88
+ }
89
+
90
+ // 按服务器分组
91
+ const byServer = new Map<string, typeof tools>();
92
+ for (const tool of tools) {
93
+ const serverName = tool.metadata?.tags?.find(t => t !== "mcp") || "unknown";
94
+ if (!byServer.has(serverName)) {
95
+ byServer.set(serverName, []);
96
+ }
97
+ byServer.get(serverName)!.push(tool);
98
+ }
99
+
100
+ for (const [serverName, serverTools] of byServer) {
101
+ output.log(chalk.bold.cyan(`\n[${serverName}] ${serverTools.length} tools`));
102
+
103
+ for (const tool of serverTools) {
104
+ const desc = tool.description.length > 80
105
+ ? tool.description.slice(0, 77) + "..."
106
+ : tool.description;
107
+ output.log(` ${chalk.green("+")} ${chalk.white(tool.name)}`);
108
+ output.log(` ${chalk.gray(desc)}`);
109
+ }
110
+ }
111
+
112
+ output.log(chalk.gray(`\nTotal: ${tools.length} tools across ${byServer.size} servers`));
113
+ }
114
+ } catch (error) {
115
+ output.error(`Failed to list MCP tools: ${error}`);
116
+ process.exit(1);
117
+ } finally {
118
+ await envService.dispose();
119
+ }
120
+ },
121
+ };