@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,133 @@
1
+ /**
2
+ * @fileoverview EventSource Add Command
3
+ *
4
+ * 添加新的事件源
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 { generateId } from "@ai-setting/roy-agent-core";
12
+ import type { EventSourceType, EventSourceComponentInterface } from "@ai-setting/roy-agent-core";
13
+
14
+ // 生成事件源 ID
15
+ function uuid(): string {
16
+ return generateId();
17
+ }
18
+
19
+ export interface EventSourceAddOptions {
20
+ name: string;
21
+ type: EventSourceType;
22
+ eventTypes?: string;
23
+ command?: string;
24
+ url?: string;
25
+ interval?: number;
26
+ cron?: string;
27
+ config?: string;
28
+ }
29
+
30
+ export const EventSourceAddCommand: CommandModule<object, object> = {
31
+ command: "add <name> <type>",
32
+ describe: "添加新的事件源",
33
+
34
+ builder: (yargs) =>
35
+ yargs
36
+ .positional("name", {
37
+ describe: "事件源名称",
38
+ type: "string",
39
+ demandOption: true,
40
+ })
41
+ .positional("type", {
42
+ describe: "事件源类型",
43
+ type: "string",
44
+ demandOption: true,
45
+ choices: ["lark-cli", "websocket", "timer", "http-webhook", "file-watcher"],
46
+ })
47
+ .option("event-types", {
48
+ alias: "e",
49
+ describe: "事件类型过滤(逗号分隔,支持通配符如 im.message.*)",
50
+ type: "string",
51
+ })
52
+ .option("command", {
53
+ alias: "c",
54
+ describe: "执行的命令(lark-cli 类型)",
55
+ type: "string",
56
+ })
57
+ .option("url", {
58
+ alias: "u",
59
+ describe: "WebSocket URL",
60
+ type: "string",
61
+ })
62
+ .option("interval", {
63
+ alias: "i",
64
+ describe: "定时器间隔(毫秒)",
65
+ type: "number",
66
+ })
67
+ .option("cron", {
68
+ describe: "Cron 表达式",
69
+ type: "string",
70
+ }),
71
+
72
+ async handler(args) {
73
+ const a = args as any;
74
+ const output = new OutputService();
75
+ const envService = new EnvironmentService(output);
76
+
77
+ try {
78
+ await envService.create({ configPath: a.config });
79
+ const env = envService.getEnvironment();
80
+ if (!env) {
81
+ output.error("Failed to create environment");
82
+ process.exit(1);
83
+ }
84
+ const esComponent = env.getComponent("event-source") as unknown as EventSourceComponentInterface | undefined;
85
+
86
+ if (!esComponent) {
87
+ output.error("EventSourceComponent not available");
88
+ process.exit(1);
89
+ }
90
+
91
+ // 解析事件类型
92
+ const eventTypes = a.eventTypes?.split(",").map((s: string) => s.trim());
93
+
94
+ // 构建配置
95
+ const config = {
96
+ id: uuid(),
97
+ name: a.name,
98
+ type: a.type as EventSourceType,
99
+ enabled: true,
100
+ eventTypes,
101
+ command: a.command,
102
+ url: a.url,
103
+ interval: a.interval,
104
+ cron: a.cron,
105
+ };
106
+
107
+ // 注册
108
+ esComponent.register(config);
109
+
110
+ // 持久化(暂时禁用,等待实现持久化)
111
+ // await esComponent.saveConfig();
112
+
113
+ output.success(chalk.green(`事件源 '${a.name}' 添加成功!`));
114
+ output.log("");
115
+ output.log(` ID: ${chalk.gray(config.id)}`);
116
+ output.log(` Type: ${chalk.cyan(a.type)}`);
117
+ if (eventTypes?.length) {
118
+ output.log(` Event Types: ${chalk.gray(eventTypes.join(", "))}`);
119
+ }
120
+ if (a.command) {
121
+ output.log(` Command: ${chalk.gray(a.command)}`);
122
+ }
123
+ if (a.interval) {
124
+ output.log(` Interval: ${chalk.gray(`${a.interval}ms`)}`);
125
+ }
126
+ output.log("");
127
+ output.log(chalk.gray(`使用 'roy eventsource start ${config.id.substring(0, 8)}' 启动它。`));
128
+
129
+ } finally {
130
+ await envService.dispose();
131
+ }
132
+ },
133
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @fileoverview EventSource Command
3
+ *
4
+ * 事件源管理命令入口
5
+ */
6
+
7
+ import { CommandModule } from "yargs";
8
+ import { EventSourceListCommand } from "./list";
9
+ import { EventSourceAddCommand } from "./add";
10
+ import { EventSourceRemoveCommand } from "./remove";
11
+ import { EventSourceStartCommand } from "./start";
12
+ import { EventSourceStopCommand } from "./stop";
13
+ import { EventSourceStatusCommand } from "./status";
14
+
15
+ /**
16
+ * EventSource Command
17
+ *
18
+ * 事件源管理命令
19
+ */
20
+ export const EventSourceCommand: CommandModule = {
21
+ command: "eventsource",
22
+ aliases: ["es", "event-source"],
23
+ describe: "事件源管理 - 添加、启动、停止各种事件源(lark-cli、timer、websocket)",
24
+
25
+ builder: (yargs) =>
26
+ yargs
27
+ .command(EventSourceListCommand)
28
+ .command(EventSourceAddCommand)
29
+ .command(EventSourceRemoveCommand)
30
+ .command(EventSourceStartCommand)
31
+ .command(EventSourceStopCommand)
32
+ .command(EventSourceStatusCommand)
33
+ .demandCommand()
34
+ .help(),
35
+
36
+ handler: () => {
37
+ // 空实现,yargs 会显示帮助信息
38
+ },
39
+ };
40
+
41
+ export {
42
+ EventSourceListCommand,
43
+ EventSourceAddCommand,
44
+ EventSourceRemoveCommand,
45
+ EventSourceStartCommand,
46
+ EventSourceStopCommand,
47
+ EventSourceStatusCommand,
48
+ };
@@ -0,0 +1,194 @@
1
+ /**
2
+ * @fileoverview EventSource List Command
3
+ *
4
+ * 列出所有已配置的事件源
5
+ */
6
+
7
+ import { CommandModule } from "yargs";
8
+ import { EnvironmentService } from "../../services/environment.service";
9
+ import { OutputService } from "../../services/output.service";
10
+ import chalk, { ChalkInstance } from "chalk";
11
+ import type { EventSourceComponentInterface, EventSourceConfig } from "@ai-setting/roy-agent-core";
12
+
13
+ export interface EventSourceListOptions {
14
+ json?: boolean;
15
+ quiet?: boolean;
16
+ config?: string;
17
+ }
18
+
19
+ interface SourceRow {
20
+ id: string;
21
+ name: string;
22
+ type: string;
23
+ status: string;
24
+ enabled: string;
25
+ }
26
+
27
+ /**
28
+ * 计算字符串的视觉宽度(中文字符占2格)
29
+ */
30
+ function visualWidth(str: string): number {
31
+ let width = 0;
32
+ for (const char of str) {
33
+ if (char.charCodeAt(0) > 255) {
34
+ width += 2;
35
+ } else {
36
+ width += 1;
37
+ }
38
+ }
39
+ return width;
40
+ }
41
+
42
+ /**
43
+ * 按视觉宽度截断字符串
44
+ */
45
+ function truncateVisual(str: string, maxWidth: number): string {
46
+ let result = "";
47
+ let width = 0;
48
+ for (const char of str) {
49
+ const charWidth = char.charCodeAt(0) > 255 ? 2 : 1;
50
+ if (width + charWidth > maxWidth) break;
51
+ result += char;
52
+ width += charWidth;
53
+ }
54
+ return result;
55
+ }
56
+
57
+ /**
58
+ * 格式化事件源表格
59
+ */
60
+ function formatSourcesTable(sources: SourceRow[]): string {
61
+ if (sources.length === 0) {
62
+ return chalk.yellow("没有配置的事件源,使用 'roy eventsource add' 添加");
63
+ }
64
+
65
+ const ID_WIDTH = 10;
66
+ const NAME_WIDTH = 20;
67
+ const TYPE_WIDTH = 12;
68
+ const STATUS_WIDTH = 10;
69
+ const ENABLED_WIDTH = 8;
70
+ const GAP = " ";
71
+
72
+ const headerLine = [
73
+ chalk.bold("ID".padEnd(ID_WIDTH)),
74
+ chalk.bold("NAME".padEnd(NAME_WIDTH)),
75
+ chalk.bold("TYPE".padEnd(TYPE_WIDTH)),
76
+ chalk.bold("STATUS".padEnd(STATUS_WIDTH)),
77
+ chalk.bold("ENABLED".padEnd(ENABLED_WIDTH)),
78
+ ].join(GAP);
79
+
80
+ const sepLine = "─".repeat(ID_WIDTH + NAME_WIDTH + TYPE_WIDTH + STATUS_WIDTH + ENABLED_WIDTH + GAP.length * 4);
81
+
82
+ const formatRow = (src: SourceRow): string => {
83
+ const id = truncateVisual(src.id, ID_WIDTH).padEnd(ID_WIDTH);
84
+ const name = truncateVisual(src.name, NAME_WIDTH).padEnd(NAME_WIDTH);
85
+ const type = truncateVisual(src.type, TYPE_WIDTH).padEnd(TYPE_WIDTH);
86
+ const status = truncateVisual(src.status, STATUS_WIDTH).padEnd(STATUS_WIDTH);
87
+ const enabled = src.enabled.padEnd(ENABLED_WIDTH);
88
+ return `${id}${GAP}${name}${GAP}${type}${GAP}${status}${GAP}${enabled}`;
89
+ };
90
+
91
+ const rows = sources.map(formatRow);
92
+ return [headerLine, sepLine, ...rows].join("\n");
93
+ }
94
+
95
+ export const EventSourceListCommand: CommandModule<object, EventSourceListOptions> = {
96
+ command: "list",
97
+ aliases: ["ls"],
98
+ describe: "列出所有事件源",
99
+
100
+ builder: (yargs) =>
101
+ yargs
102
+ .option("json", {
103
+ alias: "j",
104
+ describe: "JSON 格式输出",
105
+ type: "boolean",
106
+ default: false,
107
+ })
108
+ .option("quiet", {
109
+ alias: "q",
110
+ describe: "静默模式",
111
+ type: "boolean",
112
+ default: false,
113
+ }),
114
+
115
+ async handler(args) {
116
+ const output = new OutputService();
117
+ output.configure({ quiet: args.quiet });
118
+ const envService = new EnvironmentService(output);
119
+
120
+ try {
121
+ await envService.create({ configPath: args.config });
122
+ const env = envService.getEnvironment();
123
+ if (!env) {
124
+ output.error("Failed to create environment");
125
+ process.exit(1);
126
+ }
127
+
128
+ // Debug: 列出所有组件
129
+ const components = env.listComponents().map(c => c.name);
130
+ output.log("Available components: " + components.join(", "));
131
+
132
+ const esComponent = env.getComponent("event-source") as unknown as EventSourceComponentInterface | undefined;
133
+
134
+ if (!esComponent) {
135
+ output.error("EventSourceComponent not available");
136
+ process.exit(1);
137
+ }
138
+
139
+ const sources = esComponent.list();
140
+
141
+ if (!sources || sources.length === 0) {
142
+ if (args.json) {
143
+ output.json({ sources: [], count: 0 });
144
+ } else {
145
+ output.log(chalk.yellow("没有配置的事件源,使用 'roy eventsource add' 添加"));
146
+ }
147
+ return;
148
+ }
149
+
150
+ if (args.json) {
151
+ const sourcesWithStatus = sources.map((s) => ({
152
+ ...s,
153
+ status: esComponent.getStatus(s.id) || "unknown",
154
+ }));
155
+ output.json({ sources: sourcesWithStatus, count: sources.length });
156
+ return;
157
+ }
158
+
159
+ // 表格输出
160
+ const rows: SourceRow[] = sources.map((s) => {
161
+ const status = esComponent.getStatus(s.id) || "unknown";
162
+ const statusColorMap: Record<string, ChalkInstance> = {
163
+ running: chalk.green,
164
+ stopped: chalk.gray,
165
+ error: chalk.red,
166
+ starting: chalk.yellow,
167
+ created: chalk.gray,
168
+ stopping: chalk.yellow,
169
+ unknown: chalk.gray,
170
+ };
171
+ const statusColor = statusColorMap[status] || chalk.gray;
172
+
173
+ return {
174
+ id: s.id.substring(0, 8),
175
+ name: s.name,
176
+ type: s.type,
177
+ status: statusColor(status),
178
+ enabled: s.enabled ? chalk.green("✓") : chalk.gray("✗"),
179
+ };
180
+ });
181
+
182
+ output.log(formatSourcesTable(rows));
183
+ output.info("");
184
+ output.log(
185
+ chalk.green(`✅ 共 ${sources.length} 个事件源`)
186
+ );
187
+ } catch (error) {
188
+ output.error(`Failed to list event sources: ${error}`);
189
+ process.exit(1);
190
+ } finally {
191
+ await envService.dispose();
192
+ }
193
+ },
194
+ };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @fileoverview EventSource Remove Command
3
+ *
4
+ * 移除事件源
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 { EventSourceComponentInterface } from "@ai-setting/roy-agent-core";
12
+
13
+ export interface EventSourceRemoveOptions {
14
+ id: string;
15
+ config?: string;
16
+ force?: boolean;
17
+ }
18
+
19
+ export const EventSourceRemoveCommand: CommandModule<object, EventSourceRemoveOptions> = {
20
+ command: "remove <id>",
21
+ aliases: ["rm"],
22
+ describe: "移除指定的事件源",
23
+
24
+ builder: (yargs) =>
25
+ yargs
26
+ .positional("id", {
27
+ describe: "事件源 ID(支持前缀匹配)",
28
+ type: "string",
29
+ demandOption: true,
30
+ })
31
+ .option("force", {
32
+ alias: "f",
33
+ describe: "强制移除(即使正在运行)",
34
+ type: "boolean",
35
+ default: false,
36
+ }),
37
+
38
+ async handler(args) {
39
+ const output = new OutputService();
40
+ const envService = new EnvironmentService(output);
41
+
42
+ try {
43
+ await envService.create({ configPath: args.config });
44
+ const env = envService.getEnvironment();
45
+ if (!env) {
46
+ output.error("Failed to create environment");
47
+ process.exit(1);
48
+ }
49
+ const esComponent = env.getComponent("event-source") as unknown as EventSourceComponentInterface | undefined;
50
+
51
+ if (!esComponent) {
52
+ output.error("EventSourceComponent not available");
53
+ process.exit(1);
54
+ }
55
+
56
+ // 查找事件源(支持前缀匹配)
57
+ const sources = esComponent.list();
58
+ const matchedSource = sources.find(
59
+ (s) => s.id === args.id || s.id.startsWith(args.id)
60
+ );
61
+
62
+ if (!matchedSource) {
63
+ output.error(`事件源不存在: ${args.id}`);
64
+ process.exit(1);
65
+ }
66
+
67
+ // 检查是否正在运行
68
+ const status = esComponent.getStatus(matchedSource.id);
69
+ if (status === "running" && !args.force) {
70
+ output.error(`事件源正在运行中,请先停止: ${matchedSource.name} (${status})`);
71
+ output.log(chalk.gray(`使用 --force 强制移除或 'roy eventsource stop ${matchedSource.id.substring(0, 8)}' 先停止`));
72
+ process.exit(1);
73
+ }
74
+
75
+ // 如果正在运行,先停止
76
+ if (status === "running") {
77
+ await esComponent.stopSource(matchedSource.id);
78
+ output.info(`已停止事件源: ${matchedSource.name}`);
79
+ }
80
+
81
+ // 移除
82
+ const result = esComponent.unregister(matchedSource.id);
83
+
84
+ if (result) {
85
+ output.success(chalk.green(`事件源已移除: ${matchedSource.name}`));
86
+ } else {
87
+ output.error("移除失败");
88
+ process.exit(1);
89
+ }
90
+
91
+ } finally {
92
+ await envService.dispose();
93
+ }
94
+ },
95
+ };
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @fileoverview EventSource Start Command
3
+ *
4
+ * 启动事件源
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 { EventSourceComponentInterface } from "@ai-setting/roy-agent-core";
12
+
13
+ export interface EventSourceStartOptions {
14
+ id: string;
15
+ config?: string;
16
+ background?: boolean;
17
+ }
18
+
19
+ export const EventSourceStartCommand: CommandModule<object, EventSourceStartOptions> = {
20
+ command: "start <id>",
21
+ describe: "启动指定的事件源",
22
+
23
+ builder: (yargs) =>
24
+ yargs
25
+ .positional("id", {
26
+ describe: "事件源 ID(支持前缀匹配)",
27
+ type: "string",
28
+ demandOption: true,
29
+ })
30
+ .option("background", {
31
+ alias: "b",
32
+ describe: "后台运行",
33
+ type: "boolean",
34
+ default: false,
35
+ }),
36
+
37
+ async handler(args) {
38
+ const output = new OutputService();
39
+ const envService = new EnvironmentService(output);
40
+
41
+ try {
42
+ await envService.create({ configPath: args.config });
43
+ const env = envService.getEnvironment();
44
+ if (!env) {
45
+ output.error("Failed to create environment");
46
+ process.exit(1);
47
+ }
48
+ const esComponent = env.getComponent("event-source") as unknown as EventSourceComponentInterface | undefined;
49
+
50
+ if (!esComponent) {
51
+ output.error("EventSourceComponent not available");
52
+ process.exit(1);
53
+ }
54
+
55
+ // 查找事件源(支持前缀匹配)
56
+ const sources = esComponent.list();
57
+ const matchedSource = sources.find(
58
+ (s) => s.id === args.id || s.id.startsWith(args.id)
59
+ );
60
+
61
+ if (!matchedSource) {
62
+ output.error(`事件源不存在: ${args.id}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ // 检查状态
67
+ const status = esComponent.getStatus(matchedSource.id);
68
+ if (status === "running") {
69
+ output.log(chalk.yellow(`事件源已在运行: ${matchedSource.name}`));
70
+ return;
71
+ }
72
+
73
+ // 启动
74
+ output.info(`正在启动事件源 '${matchedSource.name}'...`);
75
+
76
+ try {
77
+ await esComponent.startSource(matchedSource.id);
78
+ output.success(chalk.green(`事件源已启动: ${matchedSource.name}`));
79
+
80
+ if (!args.background) {
81
+ output.log(chalk.gray("按 Ctrl+C 停止..."));
82
+
83
+ // 等待信号
84
+ await new Promise<void>((resolve) => {
85
+ const cleanup = () => {
86
+ process.removeListener("SIGINT", cleanup);
87
+ process.removeListener("SIGTERM", cleanup);
88
+ resolve();
89
+ };
90
+ process.on("SIGINT", cleanup);
91
+ process.on("SIGTERM", cleanup);
92
+ });
93
+ }
94
+ } catch (error) {
95
+ output.error(`启动失败: ${error}`);
96
+ process.exit(1);
97
+ }
98
+
99
+ } finally {
100
+ await envService.dispose();
101
+ }
102
+ },
103
+ };