@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,388 @@
1
+ /**
2
+ * @fileoverview End-to-End Test for Memory Extract Mode
3
+ *
4
+ * 完整测试 record --extract 命令的集成流程
5
+ *
6
+ * 注意:runExtractMode 是内部函数,直接测试其逻辑而非导入
7
+ */
8
+
9
+ import { describe, expect, test, vi, beforeEach, afterEach } from "vitest";
10
+
11
+ // Mock chalk
12
+ vi.mock("chalk", () => ({
13
+ default: {
14
+ blue: (str: string) => str,
15
+ gray: (str: string) => str,
16
+ green: (str: string) => str,
17
+ red: (str: string) => str,
18
+ },
19
+ }));
20
+
21
+ // Mock dependencies
22
+ const mockSessionComponent = {
23
+ searchSessions: vi.fn().mockResolvedValue([
24
+ { sessionId: "test-1", title: "Test Session", preview: "Hello world" }
25
+ ]),
26
+ getSession: vi.fn().mockResolvedValue({
27
+ sessionId: "test-1",
28
+ messages: [
29
+ { role: "user", content: "Hello" },
30
+ { role: "assistant", content: "Hi there!" },
31
+ ],
32
+ }),
33
+ getContext: vi.fn().mockResolvedValue({
34
+ messages: [
35
+ { id: "1", role: "user", content: "What's the weather?" },
36
+ { id: "2", role: "assistant", content: "It's sunny today." },
37
+ ],
38
+ }),
39
+ };
40
+
41
+ const mockMemoryComponent = {
42
+ recallMemory: vi.fn().mockResolvedValue("# 项目记忆\n\n暂无内容"),
43
+ recordMemory: vi.fn().mockResolvedValue({ path: "/test/memory.md", action: "overwrite" }),
44
+ };
45
+
46
+ const mockAgentInstance = {
47
+ name: "memory-extract-project",
48
+ config: {
49
+ type: "sub",
50
+ systemPrompt: "",
51
+ allowedTools: ["search_sessions", "get_session", "write_memory"],
52
+ deniedTools: [],
53
+ },
54
+ status: "idle",
55
+ plugins: new Map(),
56
+ };
57
+
58
+ const mockAgentComponent = {
59
+ registerAgent: vi.fn().mockReturnValue(mockAgentInstance),
60
+ unregisterAgent: vi.fn(),
61
+ setDefaultTools: vi.fn(),
62
+ run: vi.fn().mockResolvedValue({
63
+ finalText: "Memory extracted successfully",
64
+ iterations: 1,
65
+ toolCalls: [],
66
+ }),
67
+ getAgent: vi.fn().mockReturnValue(mockAgentInstance),
68
+ getAvailableTools: vi.fn().mockReturnValue([
69
+ { name: "search_sessions", execute: vi.fn() },
70
+ { name: "get_session", execute: vi.fn() },
71
+ { name: "write_memory", execute: vi.fn() },
72
+ ]),
73
+ };
74
+
75
+ // Replicate runExtractMode logic for testing
76
+ async function testableRunExtractMode(
77
+ output: any,
78
+ memoryComponent: any,
79
+ agentComponent: any,
80
+ sessionComponent: any,
81
+ options: {
82
+ scope: "project" | "global";
83
+ sessionId?: string;
84
+ require?: string;
85
+ }
86
+ ): Promise<void> {
87
+ const { scope, sessionId, require: userRequirement } = options;
88
+
89
+ // Get current memory
90
+ const currentMemory = await memoryComponent.recallMemory(scope) || "(无现有记忆)";
91
+
92
+ // Import getBuiltInPrompt and createMemoryAgentTools
93
+ const { getBuiltInPrompt, createMemoryAgentTools } = await import("@ai-setting/roy-agent-core");
94
+
95
+ // Build prompt
96
+ const promptTemplate = scope === "project"
97
+ ? getBuiltInPrompt("project-memory")
98
+ : getBuiltInPrompt("global-memory");
99
+
100
+ if (!promptTemplate) {
101
+ throw new Error(`Prompt not found for scope: ${scope}`);
102
+ }
103
+
104
+ const systemPrompt = promptTemplate
105
+ .replace("{USER_REQUIREMENT}", userRequirement || "请从会话历史中提炼关键知识。")
106
+ .replace("{SCOPE}", scope)
107
+ .replace("{CURRENT_MEMORY}", currentMemory);
108
+
109
+ // Create tools
110
+ const memoryTools = createMemoryAgentTools({
111
+ sessionComponent,
112
+ memoryComponent,
113
+ });
114
+
115
+ // Register agent
116
+ const agentName = `memory-extract-${scope}`;
117
+ agentComponent.registerAgent(agentName, {
118
+ type: "sub",
119
+ systemPrompt,
120
+ allowedTools: ["search_sessions", "get_session", "write_memory"],
121
+ deniedTools: [],
122
+ });
123
+ agentComponent.setDefaultTools([
124
+ memoryTools.searchSessions,
125
+ memoryTools.getSession,
126
+ memoryTools.writeMemory,
127
+ ]);
128
+
129
+ // Run agent
130
+ const query = `请分析会话历史,提炼${scope === "project" ? "项目" : "全局"}记忆并写入记忆文件。`;
131
+ const result = await agentComponent.run(agentName, query, {
132
+ sessionId,
133
+ });
134
+
135
+ // Handle result
136
+ if (result.error) {
137
+ output.error(`提取失败: ${result.error}`);
138
+ } else if (result.finalText) {
139
+ output.log(chalk.green("\n✅ 记忆提取完成"));
140
+ }
141
+
142
+ // Cleanup
143
+ agentComponent.unregisterAgent(agentName);
144
+ }
145
+
146
+ // Mock chalk after importing
147
+ import chalk from "chalk";
148
+
149
+ // Helper to create mock output
150
+ function createMockOutput() {
151
+ return {
152
+ log: vi.fn(),
153
+ info: vi.fn(),
154
+ warn: vi.fn(),
155
+ error: vi.fn(),
156
+ };
157
+ }
158
+
159
+ describe("runExtractMode - E2E Test (replicated logic)", () => {
160
+ beforeEach(() => {
161
+ vi.clearAllMocks();
162
+ });
163
+
164
+ afterEach(() => {
165
+ vi.restoreAllMocks();
166
+ });
167
+
168
+ test("should complete full extract flow with project scope", async () => {
169
+ const mockOutput = createMockOutput();
170
+
171
+ await testableRunExtractMode(
172
+ mockOutput,
173
+ mockMemoryComponent,
174
+ mockAgentComponent,
175
+ mockSessionComponent,
176
+ {
177
+ scope: "project",
178
+ sessionId: "test-session-123",
179
+ require: "重点关注配置信息",
180
+ }
181
+ );
182
+
183
+ // 1. Verify memory recall was called
184
+ expect(mockMemoryComponent.recallMemory).toHaveBeenCalledWith("project");
185
+
186
+ // 2. Verify agent registration
187
+ expect(mockAgentComponent.registerAgent).toHaveBeenCalledWith(
188
+ "memory-extract-project",
189
+ expect.objectContaining({
190
+ type: "sub",
191
+ allowedTools: expect.arrayContaining(["search_sessions", "get_session", "write_memory"]),
192
+ })
193
+ );
194
+
195
+ // 3. Verify default tools were set
196
+ expect(mockAgentComponent.setDefaultTools).toHaveBeenCalled();
197
+
198
+ // 4. Verify agent run was called with correct params
199
+ expect(mockAgentComponent.run).toHaveBeenCalledWith(
200
+ "memory-extract-project",
201
+ expect.stringContaining("分析会话历史"),
202
+ expect.objectContaining({
203
+ sessionId: "test-session-123",
204
+ })
205
+ );
206
+
207
+ // 5. Verify cleanup
208
+ expect(mockAgentComponent.unregisterAgent).toHaveBeenCalledWith("memory-extract-project");
209
+ });
210
+
211
+ test("should complete full extract flow with global scope", async () => {
212
+ const mockOutput = createMockOutput();
213
+
214
+ await testableRunExtractMode(
215
+ mockOutput,
216
+ mockMemoryComponent,
217
+ mockAgentComponent,
218
+ mockSessionComponent,
219
+ {
220
+ scope: "global",
221
+ sessionId: "test-session-456",
222
+ require: "提取通用知识",
223
+ }
224
+ );
225
+
226
+ // Verify agent registration with global scope
227
+ expect(mockAgentComponent.registerAgent).toHaveBeenCalledWith(
228
+ "memory-extract-global",
229
+ expect.objectContaining({
230
+ type: "sub",
231
+ })
232
+ );
233
+
234
+ // Verify agent run with global scope
235
+ expect(mockAgentComponent.run).toHaveBeenCalledWith(
236
+ "memory-extract-global",
237
+ expect.stringContaining("全局"),
238
+ expect.objectContaining({
239
+ sessionId: "test-session-456",
240
+ })
241
+ );
242
+ });
243
+
244
+ test("should use default requirement when not provided", async () => {
245
+ const mockOutput = createMockOutput();
246
+
247
+ await testableRunExtractMode(
248
+ mockOutput,
249
+ mockMemoryComponent,
250
+ mockAgentComponent,
251
+ mockSessionComponent,
252
+ {
253
+ scope: "project",
254
+ sessionId: "test-session",
255
+ }
256
+ );
257
+
258
+ // Verify agent was registered (requirement uses default)
259
+ expect(mockAgentComponent.registerAgent).toHaveBeenCalled();
260
+ expect(mockAgentComponent.run).toHaveBeenCalled();
261
+ });
262
+
263
+ test("should handle agent execution error", async () => {
264
+ const mockOutput = createMockOutput();
265
+
266
+ // Setup error scenario
267
+ mockAgentComponent.run.mockResolvedValueOnce({
268
+ finalText: undefined,
269
+ iterations: 1,
270
+ toolCalls: [],
271
+ error: "LLM invocation failed",
272
+ });
273
+
274
+ await testableRunExtractMode(
275
+ mockOutput,
276
+ mockMemoryComponent,
277
+ mockAgentComponent,
278
+ mockSessionComponent,
279
+ {
280
+ scope: "project",
281
+ sessionId: "test-session",
282
+ }
283
+ );
284
+
285
+ // Verify error was reported
286
+ expect(mockOutput.error).toHaveBeenCalledWith(expect.stringContaining("提取失败"));
287
+
288
+ // Verify cleanup still happened
289
+ expect(mockAgentComponent.unregisterAgent).toHaveBeenCalledWith("memory-extract-project");
290
+ });
291
+
292
+ test("should work without session ID", async () => {
293
+ const mockOutput = createMockOutput();
294
+
295
+ await testableRunExtractMode(
296
+ mockOutput,
297
+ mockMemoryComponent,
298
+ mockAgentComponent,
299
+ mockSessionComponent,
300
+ {
301
+ scope: "project",
302
+ sessionId: undefined,
303
+ }
304
+ );
305
+
306
+ // Verify agent run was called without sessionId
307
+ expect(mockAgentComponent.run).toHaveBeenCalledWith(
308
+ "memory-extract-project",
309
+ expect.any(String),
310
+ expect.not.objectContaining({ sessionId: expect.anything() })
311
+ );
312
+ });
313
+
314
+ test("should verify tool names match between allowedTools and created tools", async () => {
315
+ const { createMemoryAgentTools } = await import("@ai-setting/roy-agent-core");
316
+
317
+ const tools = createMemoryAgentTools({
318
+ sessionComponent: mockSessionComponent,
319
+ memoryComponent: mockMemoryComponent,
320
+ });
321
+
322
+ // These are the allowedTools in the agent config
323
+ const allowedTools = ["search_sessions", "get_session", "write_memory"];
324
+
325
+ // Verify each allowed tool exists with matching name
326
+ expect(tools.searchSessions.name).toBe("search_sessions");
327
+ expect(tools.getSession.name).toBe("get_session");
328
+ expect(tools.writeMemory.name).toBe("write_memory");
329
+
330
+ // Verify all allowed tools are present
331
+ expect(allowedTools).toContain(tools.searchSessions.name);
332
+ expect(allowedTools).toContain(tools.getSession.name);
333
+ expect(allowedTools).toContain(tools.writeMemory.name);
334
+ });
335
+ });
336
+
337
+ describe("CLI parameter integration", () => {
338
+ test("should accept extract option", () => {
339
+ const options = {
340
+ mode: "append" as const,
341
+ extract: true,
342
+ scope: "project" as const,
343
+ "session-id": "sid:abc123",
344
+ require: "提取项目配置",
345
+ };
346
+
347
+ expect(options.extract).toBe(true);
348
+ expect(options.scope).toBe("project");
349
+ expect(options["session-id"]).toBe("sid:abc123");
350
+ expect(options.require).toBe("提取项目配置");
351
+ });
352
+
353
+ test("should accept global scope", () => {
354
+ const options = {
355
+ extract: true,
356
+ scope: "global" as const,
357
+ };
358
+
359
+ expect(options.scope).toBe("global");
360
+ });
361
+
362
+ test("should not require content when extract is true", () => {
363
+ const options = {
364
+ extract: true,
365
+ mode: "append" as const,
366
+ // content is intentionally omitted
367
+ };
368
+
369
+ // This is valid - extract mode doesn't need content
370
+ expect(options.extract).toBe(true);
371
+ expect((options as any).content).toBeUndefined();
372
+ });
373
+
374
+ test("should validate extract mode doesn't require content", () => {
375
+ // Simulate yargs check logic
376
+ const argv = {
377
+ mode: "append",
378
+ extract: true,
379
+ content: undefined,
380
+ };
381
+
382
+ // extract mode should pass validation
383
+ if (argv.extract) {
384
+ // Should pass without content
385
+ expect(true).toBe(true);
386
+ }
387
+ });
388
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @fileoverview Memory Commands Index - Simplified
3
+ *
4
+ * 导出所有 memory 子命令
5
+ *
6
+ * Simplified 设计:只保留 record 和 recall 两个核心命令
7
+ */
8
+
9
+ export { MemoryCommand } from "./memory";
10
+ export { RecordCommand } from "./record";
11
+ export { RecallCommand } from "./recall";
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @fileoverview Memory Command Simplified Tests (TDD)
3
+ *
4
+ * 测试目标:验证简化后的 memory 命令设计
5
+ *
6
+ * Simplified 设计:只保留核心命令 record 和 recall
7
+ */
8
+
9
+ import { describe, expect, test } from "vitest";
10
+ import { MemoryCommand } from "./memory";
11
+
12
+ describe("MemoryCommand - Simplified Design", () => {
13
+ describe("command configuration", () => {
14
+ test("should have correct command name", () => {
15
+ expect(MemoryCommand.command).toBe("memory");
16
+ });
17
+
18
+ test("should have simplified describe text", () => {
19
+ // 描述应该只列出核心命令:record 和 recall
20
+ expect(MemoryCommand.describe).toContain("record");
21
+ expect(MemoryCommand.describe).toContain("recall");
22
+ });
23
+
24
+ test("should NOT mention old commands that were removed", () => {
25
+ // list, read, write, grep 已被移除
26
+ expect(MemoryCommand.describe).not.toContain("list");
27
+ expect(MemoryCommand.describe).not.toContain("read");
28
+ expect(MemoryCommand.describe).not.toContain("write");
29
+ expect(MemoryCommand.describe).not.toContain("grep");
30
+ expect(MemoryCommand.describe).not.toContain("paths");
31
+ });
32
+
33
+ test("should NOT mention draft or organize commands", () => {
34
+ // draft 和 organize 已被移除
35
+ expect(MemoryCommand.describe).not.toContain("draft");
36
+ expect(MemoryCommand.describe).not.toContain("organize");
37
+ });
38
+ });
39
+
40
+ describe("should have essential subcommands", () => {
41
+ test("should register record command", () => {
42
+ expect(MemoryCommand.describe).toContain("record");
43
+ });
44
+
45
+ test("should register recall command", () => {
46
+ expect(MemoryCommand.describe).toContain("recall");
47
+ });
48
+
49
+ test("should NOT register removed commands", () => {
50
+ // 以下命令已被移除
51
+ expect(MemoryCommand.describe).not.toContain("list");
52
+ expect(MemoryCommand.describe).not.toContain("read");
53
+ expect(MemoryCommand.describe).not.toContain("write");
54
+ expect(MemoryCommand.describe).not.toContain("grep");
55
+ expect(MemoryCommand.describe).not.toContain("paths");
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @fileoverview Memory Command - Simplified
3
+ *
4
+ * 命令:roy memory
5
+ *
6
+ * Simplified 设计:只保留 record 和 recall 命令
7
+ */
8
+
9
+ import { CommandModule } from "yargs";
10
+ import { RecordCommand } from "./record";
11
+ import { RecallCommand } from "./recall";
12
+
13
+ export const MemoryCommand: CommandModule = {
14
+ command: "memory",
15
+ describe: "管理记忆文件 (record, recall)",
16
+ builder: (yargs) =>
17
+ yargs
18
+ .command(RecordCommand)
19
+ .command(RecallCommand)
20
+ .demandCommand(1, "请指定子命令。可用子命令: record, recall"),
21
+
22
+ handler: () => {
23
+ // 默认显示帮助
24
+ },
25
+ };