@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,122 @@
1
+ /**
2
+ * @fileoverview Interactive Shutdown Tests
3
+ *
4
+ * TDD: 测试 InteractiveCommand 的 shutdown 功能和 EventSource 清理
5
+ */
6
+
7
+ import { describe, test, expect, vi, beforeEach, afterEach } from "bun:test";
8
+
9
+ describe("Interactive Shutdown Tests", () => {
10
+ describe("REPL should support graceful shutdown", () => {
11
+ test("REPL should have shutdown capability in options", async () => {
12
+ // Arrange - 测试接口定义是否包含 shutdown
13
+ const options = {
14
+ sessionId: "test",
15
+ sessionTitle: "Test",
16
+ onExecute: vi.fn(),
17
+ onStatus: vi.fn(),
18
+ onSwitchSession: vi.fn(),
19
+ onCompact: vi.fn(),
20
+ onShutdown: vi.fn(), // 应该有 onShutdown 回调
21
+ };
22
+
23
+ expect(typeof options.onShutdown).toBe("function");
24
+ });
25
+
26
+ test("exit commands should trigger shutdown callback", async () => {
27
+ // 这个测试验证 exit 命令会调用 onShutdown
28
+ // 由于 REPL 是内部类,我们通过集成测试来验证
29
+ // 这里我们验证 shutdown 逻辑的存在性
30
+ const mockShutdown = vi.fn();
31
+
32
+ // 模拟 shutdown 逻辑
33
+ const shutdown = async () => {
34
+ await mockShutdown();
35
+ };
36
+
37
+ await shutdown();
38
+
39
+ expect(mockShutdown).toHaveBeenCalled();
40
+ });
41
+ });
42
+
43
+ describe("EventSource cleanup during shutdown", () => {
44
+ test("should stop running EventSource sources when shutting down", async () => {
45
+ // 验证 shutdown 时应该停止所有运行中的事件源
46
+ const mockStopSource = vi.fn().mockResolvedValue(undefined);
47
+
48
+ // 模拟 EventSourceComponent
49
+ const mockEventSourceComponent = {
50
+ list: vi.fn().mockReturnValue([
51
+ { id: "es1", name: "Event Source 1" },
52
+ { id: "es2", name: "Event Source 2" },
53
+ ]),
54
+ getStatus: vi.fn().mockImplementation((id: string) => {
55
+ return id === "es1" ? "running" : "stopped";
56
+ }),
57
+ stopSource: mockStopSource,
58
+ };
59
+
60
+ // 模拟 shutdown 逻辑
61
+ const shutdown = async () => {
62
+ const sources = mockEventSourceComponent.list();
63
+ for (const source of sources) {
64
+ const status = mockEventSourceComponent.getStatus(source.id);
65
+ if (status === "running") {
66
+ await mockEventSourceComponent.stopSource(source.id);
67
+ }
68
+ }
69
+ };
70
+
71
+ await shutdown();
72
+
73
+ // 验证只停止了运行中的源
74
+ expect(mockStopSource).toHaveBeenCalledTimes(1);
75
+ expect(mockStopSource).toHaveBeenCalledWith("es1");
76
+ expect(mockStopSource).not.toHaveBeenCalledWith("es2");
77
+ });
78
+
79
+ test("should handle multiple running EventSource sources", async () => {
80
+ const mockStopSource = vi.fn().mockResolvedValue(undefined);
81
+
82
+ const mockEventSourceComponent = {
83
+ list: vi.fn().mockReturnValue([
84
+ { id: "es1", name: "Source 1" },
85
+ { id: "es2", name: "Source 2" },
86
+ { id: "es3", name: "Source 3" },
87
+ ]),
88
+ getStatus: vi.fn().mockImplementation((id: string) => {
89
+ return id === "es1" || id === "es3" ? "running" : "stopped";
90
+ }),
91
+ stopSource: mockStopSource,
92
+ };
93
+
94
+ const shutdown = async () => {
95
+ const sources = mockEventSourceComponent.list();
96
+ for (const source of sources) {
97
+ const status = mockEventSourceComponent.getStatus(source.id);
98
+ if (status === "running") {
99
+ await mockEventSourceComponent.stopSource(source.id);
100
+ }
101
+ }
102
+ };
103
+
104
+ await shutdown();
105
+
106
+ expect(mockStopSource).toHaveBeenCalledTimes(2);
107
+ });
108
+ });
109
+
110
+ describe("SIGINT handling", () => {
111
+ test("should register SIGINT handler for graceful shutdown", async () => {
112
+ // 验证 SIGINT 处理器应该被注册
113
+ const mockOn = vi.spyOn(process, "on").mockImplementation(() => process);
114
+
115
+ // 模拟注册
116
+ const sigintHandler = vi.fn();
117
+ process.on("SIGINT", sigintHandler);
118
+
119
+ expect(mockOn).toHaveBeenCalledWith("SIGINT", expect.any(Function));
120
+ });
121
+ });
122
+ });
@@ -0,0 +1,221 @@
1
+ /**
2
+ * @fileoverview InteractiveCommand Test
3
+ *
4
+ * TDD: 测试 InteractiveCommand 的核心功能
5
+ *
6
+ * 注意:由于 InteractiveCommand 涉及 readline 交互式输入,
7
+ * 我们主要测试其选项解析和命令注册逻辑
8
+ */
9
+
10
+ import { describe, test, expect, vi, beforeEach, afterEach } from "bun:test";
11
+ import { InteractiveCommand, type InteractiveOptions } from "./interactive";
12
+
13
+ describe("InteractiveCommand", () => {
14
+ describe("command definition", () => {
15
+ test("should have correct command name", () => {
16
+ expect(InteractiveCommand.command).toBe("interactive");
17
+ });
18
+
19
+ test("should have aliases defined", () => {
20
+ expect(InteractiveCommand.aliases).toEqual(["i", "repl"]);
21
+ });
22
+
23
+ test("should have describe text", () => {
24
+ expect(typeof InteractiveCommand.describe).toBe("string");
25
+ expect(InteractiveCommand.describe.length).toBeGreaterThan(0);
26
+ });
27
+
28
+ test("should have builder function", () => {
29
+ expect(typeof InteractiveCommand.builder).toBe("function");
30
+ });
31
+
32
+ test("should have handler function", () => {
33
+ expect(typeof InteractiveCommand.handler).toBe("function");
34
+ });
35
+ });
36
+
37
+ describe("builder", () => {
38
+ test("should add options via builder", () => {
39
+ // Given
40
+ const mockYargs = {
41
+ option: vi.fn().mockReturnThis(),
42
+ positional: vi.fn().mockReturnThis(),
43
+ };
44
+
45
+ // When
46
+ InteractiveCommand.builder(mockYargs as any);
47
+
48
+ // Then - verify options were added
49
+ expect(mockYargs.option).toHaveBeenCalled();
50
+ });
51
+
52
+ test("should add session option", () => {
53
+ // Given
54
+ const mockYargs = {
55
+ option: vi.fn().mockReturnThis(),
56
+ positional: vi.fn().mockReturnThis(),
57
+ };
58
+
59
+ // When
60
+ InteractiveCommand.builder(mockYargs as any);
61
+
62
+ // Then - check if session option was added
63
+ const optionCalls = mockYargs.option.mock.calls;
64
+ const sessionOption = optionCalls.find(
65
+ (call: any[]) => call[0] === "session"
66
+ );
67
+ expect(sessionOption).toBeDefined();
68
+ expect(sessionOption[1].alias).toBe("s");
69
+ });
70
+
71
+ test("should add continue option", () => {
72
+ // Given
73
+ const mockYargs = {
74
+ option: vi.fn().mockReturnThis(),
75
+ positional: vi.fn().mockReturnThis(),
76
+ };
77
+
78
+ // When
79
+ InteractiveCommand.builder(mockYargs as any);
80
+
81
+ // Then - check if continue option was added
82
+ const optionCalls = mockYargs.option.mock.calls;
83
+ const continueOption = optionCalls.find(
84
+ (call: any[]) => call[0] === "continue"
85
+ );
86
+ expect(continueOption).toBeDefined();
87
+ expect(continueOption[1].alias).toBe("c");
88
+ });
89
+
90
+ test("should add config option", () => {
91
+ // Given
92
+ const mockYargs = {
93
+ option: vi.fn().mockReturnThis(),
94
+ positional: vi.fn().mockReturnThis(),
95
+ };
96
+
97
+ // When
98
+ InteractiveCommand.builder(mockYargs as any);
99
+
100
+ // Then - check if config option was added
101
+ const optionCalls = mockYargs.option.mock.calls;
102
+ const configOption = optionCalls.find(
103
+ (call: any[]) => call[0] === "config"
104
+ );
105
+ expect(configOption).toBeDefined();
106
+ expect(configOption[1].alias).toBe("C");
107
+ });
108
+
109
+ test("should add reasoning option", () => {
110
+ // Given
111
+ const mockYargs = {
112
+ option: vi.fn().mockReturnThis(),
113
+ positional: vi.fn().mockReturnThis(),
114
+ };
115
+
116
+ // When
117
+ InteractiveCommand.builder(mockYargs as any);
118
+
119
+ // Then - check if reasoning option was added
120
+ const optionCalls = mockYargs.option.mock.calls;
121
+ const reasoningOption = optionCalls.find(
122
+ (call: any[]) => call[0] === "reasoning"
123
+ );
124
+ expect(reasoningOption).toBeDefined();
125
+ expect(reasoningOption[1].alias).toBe("r");
126
+ });
127
+
128
+ test("should add tool-calls option", () => {
129
+ // Given
130
+ const mockYargs = {
131
+ option: vi.fn().mockReturnThis(),
132
+ positional: vi.fn().mockReturnThis(),
133
+ };
134
+
135
+ // When
136
+ InteractiveCommand.builder(mockYargs as any);
137
+
138
+ // Then - check if tool-calls option was added
139
+ const optionCalls = mockYargs.option.mock.calls;
140
+ const toolCallsOption = optionCalls.find(
141
+ (call: any[]) => call[0] === "tool-calls"
142
+ );
143
+ expect(toolCallsOption).toBeDefined();
144
+ });
145
+
146
+ test("should add tool-results option", () => {
147
+ // Given
148
+ const mockYargs = {
149
+ option: vi.fn().mockReturnThis(),
150
+ positional: vi.fn().mockReturnThis(),
151
+ };
152
+
153
+ // When
154
+ InteractiveCommand.builder(mockYargs as any);
155
+
156
+ // Then - check if tool-results option was added
157
+ const optionCalls = mockYargs.option.mock.calls;
158
+ const toolResultsOption = optionCalls.find(
159
+ (call: any[]) => call[0] === "tool-results"
160
+ );
161
+ expect(toolResultsOption).toBeDefined();
162
+ });
163
+ });
164
+
165
+ describe("InteractiveOptions interface", () => {
166
+ test("should allow optional session", () => {
167
+ const options: InteractiveOptions = {
168
+ session: undefined,
169
+ continue: false,
170
+ config: undefined,
171
+ reasoning: false,
172
+ toolCalls: false,
173
+ toolResults: false,
174
+ };
175
+ expect(options.session).toBeUndefined();
176
+ });
177
+
178
+ test("should allow explicit session", () => {
179
+ const options: InteractiveOptions = {
180
+ session: "sess_123",
181
+ };
182
+ expect(options.session).toBe("sess_123");
183
+ });
184
+
185
+ test("should allow continue flag", () => {
186
+ const options: InteractiveOptions = {
187
+ continue: true,
188
+ };
189
+ expect(options.continue).toBe(true);
190
+ });
191
+
192
+ test("should allow reasoning flag", () => {
193
+ const options: InteractiveOptions = {
194
+ reasoning: true,
195
+ };
196
+ expect(options.reasoning).toBe(true);
197
+ });
198
+
199
+ test("should allow tool-calls flag", () => {
200
+ const options: InteractiveOptions = {
201
+ toolCalls: true,
202
+ };
203
+ expect(options.toolCalls).toBe(true);
204
+ });
205
+
206
+ test("should allow tool-results flag", () => {
207
+ const options: InteractiveOptions = {
208
+ toolResults: true,
209
+ };
210
+ expect(options.toolResults).toBe(true);
211
+ });
212
+ });
213
+ });
214
+
215
+ describe("Interactive Command Integration", () => {
216
+ test("should have handler that handles options", async () => {
217
+ // Note: This test verifies the handler exists and is callable
218
+ // Actual handler testing would require mocking the entire environment
219
+ expect(typeof InteractiveCommand.handler).toBe("function");
220
+ });
221
+ });