@timetotest/cli 0.2.3 → 0.3.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 (200) hide show
  1. package/README.md +49 -40
  2. package/dist/bin/ttt.js +0 -2
  3. package/dist/bin/ttt.js.map +1 -1
  4. package/dist/package.json +13 -6
  5. package/dist/src/commands/chat/ChatApp.js +270 -100
  6. package/dist/src/commands/chat/ChatApp.js.map +1 -1
  7. package/dist/src/commands/chat/components/Banner.js +1 -1
  8. package/dist/src/commands/chat/components/ChatInput.js +97 -36
  9. package/dist/src/commands/chat/components/ChatInput.js.map +1 -1
  10. package/dist/src/commands/chat/components/ChatMessage.js +102 -0
  11. package/dist/src/commands/chat/components/ChatMessage.js.map +1 -0
  12. package/dist/src/commands/chat/components/MessageBubble.js +2 -1
  13. package/dist/src/commands/chat/components/MessageBubble.js.map +1 -1
  14. package/dist/src/commands/chat/components/PermissionPrompt.js +92 -0
  15. package/dist/src/commands/chat/components/PermissionPrompt.js.map +1 -0
  16. package/dist/src/commands/chat/components/StatusIndicator.js +21 -5
  17. package/dist/src/commands/chat/components/StatusIndicator.js.map +1 -1
  18. package/dist/src/commands/chat/components/ToolCallDisplay.js +141 -0
  19. package/dist/src/commands/chat/components/ToolCallDisplay.js.map +1 -0
  20. package/dist/src/commands/chat-ink.js +389 -61
  21. package/dist/src/commands/chat-ink.js.map +1 -1
  22. package/dist/src/commands/login.js +5 -5
  23. package/dist/src/commands/login.js.map +1 -1
  24. package/dist/src/commands/test.js +14 -194
  25. package/dist/src/commands/test.js.map +1 -1
  26. package/dist/src/lib/__tests__/code-mode-integration.test.js +381 -0
  27. package/dist/src/lib/__tests__/code-mode-integration.test.js.map +1 -0
  28. package/dist/src/lib/__tests__/config-manager.test.js +81 -0
  29. package/dist/src/lib/__tests__/config-manager.test.js.map +1 -0
  30. package/dist/src/lib/__tests__/mode-persistence-integration.test.js +75 -0
  31. package/dist/src/lib/__tests__/mode-persistence-integration.test.js.map +1 -0
  32. package/dist/src/lib/__tests__/permission-flow-integration.test.js +145 -0
  33. package/dist/src/lib/__tests__/permission-flow-integration.test.js.map +1 -0
  34. package/dist/src/lib/__tests__/permissions.test.js +132 -0
  35. package/dist/src/lib/__tests__/permissions.test.js.map +1 -0
  36. package/dist/src/lib/agent-orchestrator.js +263 -4
  37. package/dist/src/lib/agent-orchestrator.js.map +1 -1
  38. package/dist/src/lib/config.js +40 -0
  39. package/dist/src/lib/config.js.map +1 -1
  40. package/dist/src/lib/context-compactor.js +310 -0
  41. package/dist/src/lib/context-compactor.js.map +1 -0
  42. package/dist/src/lib/http.js +8 -0
  43. package/dist/src/lib/http.js.map +1 -1
  44. package/dist/src/lib/local-tools/code/__tests__/grep-search.test.js +146 -0
  45. package/dist/src/lib/local-tools/code/__tests__/grep-search.test.js.map +1 -0
  46. package/dist/src/lib/local-tools/code/__tests__/list-directory.test.js +192 -0
  47. package/dist/src/lib/local-tools/code/__tests__/list-directory.test.js.map +1 -0
  48. package/dist/src/lib/local-tools/code/__tests__/read-file.test.js +169 -0
  49. package/dist/src/lib/local-tools/code/__tests__/read-file.test.js.map +1 -0
  50. package/dist/src/lib/local-tools/code/__tests__/run-command.test.js +101 -0
  51. package/dist/src/lib/local-tools/code/__tests__/run-command.test.js.map +1 -0
  52. package/dist/src/lib/local-tools/code/__tests__/search-files.test.js +191 -0
  53. package/dist/src/lib/local-tools/code/__tests__/search-files.test.js.map +1 -0
  54. package/dist/src/lib/local-tools/code/grep-search.js +404 -0
  55. package/dist/src/lib/local-tools/code/grep-search.js.map +1 -0
  56. package/dist/src/lib/local-tools/code/index.js +11 -0
  57. package/dist/src/lib/local-tools/code/index.js.map +1 -0
  58. package/dist/src/lib/local-tools/code/list-directory.js +276 -0
  59. package/dist/src/lib/local-tools/code/list-directory.js.map +1 -0
  60. package/dist/src/lib/local-tools/code/read-file.js +301 -0
  61. package/dist/src/lib/local-tools/code/read-file.js.map +1 -0
  62. package/dist/src/lib/local-tools/code/run-command.js +235 -0
  63. package/dist/src/lib/local-tools/code/run-command.js.map +1 -0
  64. package/dist/src/lib/local-tools/code/search-files.js +297 -0
  65. package/dist/src/lib/local-tools/code/search-files.js.map +1 -0
  66. package/dist/src/lib/local-tools/code/types.js +6 -0
  67. package/dist/src/lib/local-tools/code/types.js.map +1 -0
  68. package/dist/src/lib/local-tools/ui/playwright-mcp.js +1 -1
  69. package/dist/src/lib/permissions.js +94 -0
  70. package/dist/src/lib/permissions.js.map +1 -0
  71. package/dist/src/lib/prompts/builder.js +13 -10
  72. package/dist/src/lib/prompts/builder.js.map +1 -1
  73. package/dist/src/lib/prompts/templates.js +78 -0
  74. package/dist/src/lib/prompts/templates.js.map +1 -1
  75. package/dist/src/lib/session-manager.js.map +1 -1
  76. package/dist/src/lib/testing-mode.js +2 -2
  77. package/dist/src/lib/testing-mode.js.map +1 -1
  78. package/dist/src/lib/tool-executor.js +131 -2
  79. package/dist/src/lib/tool-executor.js.map +1 -1
  80. package/dist/src/lib/tool-registry.js +171 -3
  81. package/dist/src/lib/tool-registry.js.map +1 -1
  82. package/dist/src/lib/tool-result-pruner.js +4 -4
  83. package/dist/src/lib/tool-result-pruner.js.map +1 -1
  84. package/dist/src/lib/tui/ink/components/AppFrame.js +17 -0
  85. package/dist/src/lib/tui/ink/components/AppFrame.js.map +1 -0
  86. package/dist/src/lib/tui/ink/components/CommandPalette.js +24 -0
  87. package/dist/src/lib/tui/ink/components/CommandPalette.js.map +1 -0
  88. package/dist/src/lib/tui/ink/components/Pill.js +19 -0
  89. package/dist/src/lib/tui/ink/components/Pill.js.map +1 -0
  90. package/dist/src/lib/tui/ink/components/TimetoTestLogo.js +30 -0
  91. package/dist/src/lib/tui/ink/components/TimetoTestLogo.js.map +1 -0
  92. package/dist/src/lib/tui/ink/theme.js +28 -0
  93. package/dist/src/lib/tui/ink/theme.js.map +1 -0
  94. package/dist/src/lib/tui/interactive-chat.js +35 -35
  95. package/dist/src/lib/tui/interactive-chat.js.map +1 -1
  96. package/dist/src/lib/tui/print.js +18 -18
  97. package/dist/src/lib/tui/print.js.map +1 -1
  98. package/dist/src/lib/tui/prompt.js +3 -3
  99. package/dist/src/lib/tui/prompt.js.map +1 -1
  100. package/dist/src/lib/tui/status.js +1 -1
  101. package/dist/src/lib/tui/status.js.map +1 -1
  102. package/dist/src/lib/update.js +10 -10
  103. package/dist/src/lib/update.js.map +1 -1
  104. package/package.json +13 -6
  105. package/dist/src/commands/ask/AskApp.js +0 -121
  106. package/dist/src/commands/ask/AskApp.js.map +0 -1
  107. package/dist/src/commands/ask/components/AssistantResponse.js +0 -31
  108. package/dist/src/commands/ask/components/AssistantResponse.js.map +0 -1
  109. package/dist/src/commands/ask/components/Banner.js +0 -15
  110. package/dist/src/commands/ask/components/Banner.js.map +0 -1
  111. package/dist/src/commands/ask/components/ChatInput.js +0 -93
  112. package/dist/src/commands/ask/components/ChatInput.js.map +0 -1
  113. package/dist/src/commands/ask/components/Divider.js +0 -17
  114. package/dist/src/commands/ask/components/Divider.js.map +0 -1
  115. package/dist/src/commands/ask/components/IntroTips.js +0 -19
  116. package/dist/src/commands/ask/components/IntroTips.js.map +0 -1
  117. package/dist/src/commands/ask/components/MessageBubble.js +0 -47
  118. package/dist/src/commands/ask/components/MessageBubble.js.map +0 -1
  119. package/dist/src/commands/ask/components/SessionInfo.js +0 -20
  120. package/dist/src/commands/ask/components/SessionInfo.js.map +0 -1
  121. package/dist/src/commands/ask/components/StatusIndicator.js +0 -67
  122. package/dist/src/commands/ask/components/StatusIndicator.js.map +0 -1
  123. package/dist/src/commands/ask-ink.js +0 -380
  124. package/dist/src/commands/ask-ink.js.map +0 -1
  125. package/dist/src/commands/ask.js +0 -991
  126. package/dist/src/commands/ask.js.map +0 -1
  127. package/dist/src/commands/chat/components/Divider.js +0 -7
  128. package/dist/src/commands/chat/components/Divider.js.map +0 -1
  129. package/dist/src/commands/chat/components/SessionInfo.js +0 -11
  130. package/dist/src/commands/chat/components/SessionInfo.js.map +0 -1
  131. package/dist/src/commands/chat.js +0 -82
  132. package/dist/src/commands/chat.js.map +0 -1
  133. package/dist/src/commands/start-test.js +0 -119
  134. package/dist/src/commands/start-test.js.map +0 -1
  135. package/dist/src/commands/stream.js +0 -17
  136. package/dist/src/commands/stream.js.map +0 -1
  137. package/dist/src/lib/legacy-chat-runner.js +0 -37
  138. package/dist/src/lib/legacy-chat-runner.js.map +0 -1
  139. package/dist/src/lib/local-tools/ui/click-element.js +0 -105
  140. package/dist/src/lib/local-tools/ui/click-element.js.map +0 -1
  141. package/dist/src/lib/local-tools/ui/dom-rag.js +0 -201
  142. package/dist/src/lib/local-tools/ui/dom-rag.js.map +0 -1
  143. package/dist/src/lib/local-tools/ui/find-element.js +0 -31
  144. package/dist/src/lib/local-tools/ui/find-element.js.map +0 -1
  145. package/dist/src/lib/local-tools/ui/hover-element.js +0 -94
  146. package/dist/src/lib/local-tools/ui/hover-element.js.map +0 -1
  147. package/dist/src/lib/local-tools/ui/manage-tab.js +0 -65
  148. package/dist/src/lib/local-tools/ui/manage-tab.js.map +0 -1
  149. package/dist/src/lib/local-tools/ui/navigate.js +0 -35
  150. package/dist/src/lib/local-tools/ui/navigate.js.map +0 -1
  151. package/dist/src/lib/local-tools/ui/page-discovery.js +0 -32
  152. package/dist/src/lib/local-tools/ui/page-discovery.js.map +0 -1
  153. package/dist/src/lib/local-tools/ui/screenshot.js +0 -19
  154. package/dist/src/lib/local-tools/ui/screenshot.js.map +0 -1
  155. package/dist/src/lib/local-tools/ui/search-interactive-elements.js +0 -18
  156. package/dist/src/lib/local-tools/ui/search-interactive-elements.js.map +0 -1
  157. package/dist/src/lib/local-tools/ui/selector-resolver.js +0 -153
  158. package/dist/src/lib/local-tools/ui/selector-resolver.js.map +0 -1
  159. package/dist/src/lib/local-tools/ui/type-text.js +0 -40
  160. package/dist/src/lib/local-tools/ui/type-text.js.map +0 -1
  161. package/dist/src/lib/tui/components/AskIntro.js +0 -6
  162. package/dist/src/lib/tui/components/AskIntro.js.map +0 -1
  163. package/dist/src/lib/tui/components/Banner.js +0 -15
  164. package/dist/src/lib/tui/components/Banner.js.map +0 -1
  165. package/dist/src/lib/tui/components/Divider.js +0 -17
  166. package/dist/src/lib/tui/components/Divider.js.map +0 -1
  167. package/dist/src/lib/tui/components/EventLine.js +0 -110
  168. package/dist/src/lib/tui/components/EventLine.js.map +0 -1
  169. package/dist/src/lib/tui/components/Header.js +0 -15
  170. package/dist/src/lib/tui/components/Header.js.map +0 -1
  171. package/dist/src/lib/tui/components/InputBox.js +0 -9
  172. package/dist/src/lib/tui/components/InputBox.js.map +0 -1
  173. package/dist/src/lib/tui/components/Mapping.js +0 -8
  174. package/dist/src/lib/tui/components/Mapping.js.map +0 -1
  175. package/dist/src/lib/tui/components/ProjectList.js +0 -6
  176. package/dist/src/lib/tui/components/ProjectList.js.map +0 -1
  177. package/dist/src/lib/tui/components/Spinner.js +0 -20
  178. package/dist/src/lib/tui/components/Spinner.js.map +0 -1
  179. package/dist/src/lib/tui/components/StatusBanner.js +0 -12
  180. package/dist/src/lib/tui/components/StatusBanner.js.map +0 -1
  181. package/dist/src/lib/tui/components/StatusBar.js +0 -11
  182. package/dist/src/lib/tui/components/StatusBar.js.map +0 -1
  183. package/dist/src/lib/tui/components/UserBubble.js +0 -6
  184. package/dist/src/lib/tui/components/UserBubble.js.map +0 -1
  185. package/dist/src/lib/tui/components/index.js +0 -16
  186. package/dist/src/lib/tui/components/index.js.map +0 -1
  187. package/dist/src/lib/tui/ink-print.js +0 -41
  188. package/dist/src/lib/tui/ink-print.js.map +0 -1
  189. package/dist/src/test-agent-flow.js +0 -148
  190. package/dist/src/test-agent-flow.js.map +0 -1
  191. package/dist/src/test-browser-session.js +0 -152
  192. package/dist/src/test-browser-session.js.map +0 -1
  193. package/dist/src/test-browser-snapshot.js +0 -187
  194. package/dist/src/test-browser-snapshot.js.map +0 -1
  195. package/dist/src/test-snapshot-detailed.js +0 -219
  196. package/dist/src/test-snapshot-detailed.js.map +0 -1
  197. package/dist/src/test-snapshot-simple.js +0 -85
  198. package/dist/src/test-snapshot-simple.js.map +0 -1
  199. package/dist/src/test-snapshot-tabs.js +0 -110
  200. package/dist/src/test-snapshot-tabs.js.map +0 -1
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Unit tests for list_directory tool.
3
+ * Tests directory listing, glob patterns, recursive listing, and hidden files.
4
+ */
5
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
6
+ import * as fs from "fs/promises";
7
+ import * as path from "path";
8
+ import * as os from "os";
9
+ import { listDirectory } from "../list-directory.js";
10
+ describe("listDirectory", () => {
11
+ let tempDir;
12
+ let context;
13
+ beforeEach(async () => {
14
+ tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "list-dir-test-"));
15
+ context = { workingDirectory: tempDir };
16
+ });
17
+ afterEach(async () => {
18
+ await fs.rm(tempDir, { recursive: true, force: true });
19
+ });
20
+ describe("basic directory listing", () => {
21
+ it("should list directory contents", async () => {
22
+ await fs.writeFile(path.join(tempDir, "file1.txt"), "content1");
23
+ await fs.writeFile(path.join(tempDir, "file2.txt"), "content2");
24
+ await fs.mkdir(path.join(tempDir, "subdir"));
25
+ const result = await listDirectory({ path: "." }, context);
26
+ expect(result.success).toBe(true);
27
+ expect(result.total_count).toBe(3);
28
+ expect(result.entries.map((e) => e.name)).toContain("file1.txt");
29
+ expect(result.entries.map((e) => e.name)).toContain("file2.txt");
30
+ expect(result.entries.map((e) => e.name)).toContain("subdir");
31
+ });
32
+ it("should return error for non-existent directory", async () => {
33
+ const result = await listDirectory({ path: "nonexistent" }, context);
34
+ expect(result.success).toBe(false);
35
+ expect(result.error).toBe("Directory not found");
36
+ });
37
+ it("should return error for file path", async () => {
38
+ await fs.writeFile(path.join(tempDir, "file.txt"), "content");
39
+ const result = await listDirectory({ path: "file.txt" }, context);
40
+ expect(result.success).toBe(false);
41
+ expect(result.error).toBe("Path is not a directory");
42
+ });
43
+ it("should use current directory by default", async () => {
44
+ await fs.writeFile(path.join(tempDir, "test.txt"), "content");
45
+ const result = await listDirectory({}, context);
46
+ expect(result.success).toBe(true);
47
+ expect(result.path).toBe(".");
48
+ expect(result.entries.map((e) => e.name)).toContain("test.txt");
49
+ });
50
+ });
51
+ describe("glob pattern filtering", () => {
52
+ it("should filter by glob pattern", async () => {
53
+ await fs.writeFile(path.join(tempDir, "file1.txt"), "content");
54
+ await fs.writeFile(path.join(tempDir, "file2.txt"), "content");
55
+ await fs.writeFile(path.join(tempDir, "file3.js"), "content");
56
+ const result = await listDirectory({ pattern: "*.txt" }, context);
57
+ expect(result.success).toBe(true);
58
+ expect(result.total_count).toBe(2);
59
+ expect(result.entries.map((e) => e.name)).toContain("file1.txt");
60
+ expect(result.entries.map((e) => e.name)).toContain("file2.txt");
61
+ expect(result.entries.map((e) => e.name)).not.toContain("file3.js");
62
+ });
63
+ it("should support wildcard patterns", async () => {
64
+ await fs.writeFile(path.join(tempDir, "test1.ts"), "content");
65
+ await fs.writeFile(path.join(tempDir, "test2.ts"), "content");
66
+ await fs.writeFile(path.join(tempDir, "other.ts"), "content");
67
+ const result = await listDirectory({ pattern: "test*" }, context);
68
+ expect(result.success).toBe(true);
69
+ expect(result.total_count).toBe(2);
70
+ });
71
+ it("should support single character wildcard", async () => {
72
+ await fs.writeFile(path.join(tempDir, "file1.txt"), "content");
73
+ await fs.writeFile(path.join(tempDir, "file2.txt"), "content");
74
+ await fs.writeFile(path.join(tempDir, "file10.txt"), "content");
75
+ const result = await listDirectory({ pattern: "file?.txt" }, context);
76
+ expect(result.success).toBe(true);
77
+ expect(result.total_count).toBe(2);
78
+ expect(result.entries.map((e) => e.name)).not.toContain("file10.txt");
79
+ });
80
+ });
81
+ describe("recursive listing", () => {
82
+ it("should list recursively when enabled", async () => {
83
+ await fs.mkdir(path.join(tempDir, "subdir"));
84
+ await fs.writeFile(path.join(tempDir, "root.txt"), "content");
85
+ await fs.writeFile(path.join(tempDir, "subdir", "nested.txt"), "content");
86
+ const result = await listDirectory({ recursive: true }, context);
87
+ expect(result.success).toBe(true);
88
+ expect(result.entries.map((e) => e.name)).toContain("root.txt");
89
+ // Nested file should have relative path
90
+ const nestedEntry = result.entries.find((e) => e.name.includes("nested.txt"));
91
+ expect(nestedEntry).toBeDefined();
92
+ });
93
+ it("should respect max_depth", async () => {
94
+ await fs.mkdir(path.join(tempDir, "level1"));
95
+ await fs.mkdir(path.join(tempDir, "level1", "level2"));
96
+ await fs.mkdir(path.join(tempDir, "level1", "level2", "level3"));
97
+ await fs.writeFile(path.join(tempDir, "level1", "level2", "level3", "deep.txt"), "content");
98
+ const result = await listDirectory({ recursive: true, max_depth: 1 }, context);
99
+ expect(result.success).toBe(true);
100
+ // Should not include files deeper than max_depth
101
+ const deepFile = result.entries.find((e) => e.name.includes("deep.txt"));
102
+ expect(deepFile).toBeUndefined();
103
+ });
104
+ it("should not recurse by default", async () => {
105
+ await fs.mkdir(path.join(tempDir, "subdir"));
106
+ await fs.writeFile(path.join(tempDir, "subdir", "nested.txt"), "content");
107
+ const result = await listDirectory({}, context);
108
+ expect(result.success).toBe(true);
109
+ const nestedFile = result.entries.find((e) => e.name.includes("nested.txt"));
110
+ expect(nestedFile).toBeUndefined();
111
+ });
112
+ });
113
+ describe("hidden files", () => {
114
+ it("should exclude hidden files by default", async () => {
115
+ await fs.writeFile(path.join(tempDir, "visible.txt"), "content");
116
+ await fs.writeFile(path.join(tempDir, ".hidden"), "content");
117
+ const result = await listDirectory({}, context);
118
+ expect(result.success).toBe(true);
119
+ expect(result.entries.map((e) => e.name)).toContain("visible.txt");
120
+ expect(result.entries.map((e) => e.name)).not.toContain(".hidden");
121
+ });
122
+ it("should include hidden files when include_hidden is true", async () => {
123
+ await fs.writeFile(path.join(tempDir, "visible.txt"), "content");
124
+ await fs.writeFile(path.join(tempDir, ".hidden"), "content");
125
+ const result = await listDirectory({ include_hidden: true }, context);
126
+ expect(result.success).toBe(true);
127
+ expect(result.entries.map((e) => e.name)).toContain("visible.txt");
128
+ expect(result.entries.map((e) => e.name)).toContain(".hidden");
129
+ });
130
+ });
131
+ describe("path validation (security)", () => {
132
+ it("should prevent directory traversal", async () => {
133
+ const result = await listDirectory({ path: "../../../" }, context);
134
+ expect(result.success).toBe(false);
135
+ expect(result.error).toBe("Path validation failed: access denied");
136
+ });
137
+ it("should allow subdirectory access", async () => {
138
+ await fs.mkdir(path.join(tempDir, "subdir"));
139
+ await fs.writeFile(path.join(tempDir, "subdir", "file.txt"), "content");
140
+ const result = await listDirectory({ path: "subdir" }, context);
141
+ expect(result.success).toBe(true);
142
+ expect(result.entries.map((e) => e.name)).toContain("file.txt");
143
+ });
144
+ });
145
+ describe("entry metadata", () => {
146
+ it("should include file type", async () => {
147
+ await fs.writeFile(path.join(tempDir, "file.txt"), "content");
148
+ await fs.mkdir(path.join(tempDir, "dir"));
149
+ const result = await listDirectory({}, context);
150
+ expect(result.success).toBe(true);
151
+ const fileEntry = result.entries.find((e) => e.name === "file.txt");
152
+ const dirEntry = result.entries.find((e) => e.name === "dir");
153
+ expect(fileEntry?.type).toBe("file");
154
+ expect(dirEntry?.type).toBe("directory");
155
+ });
156
+ it("should include file size for files", async () => {
157
+ await fs.writeFile(path.join(tempDir, "file.txt"), "hello");
158
+ const result = await listDirectory({}, context);
159
+ expect(result.success).toBe(true);
160
+ const fileEntry = result.entries.find((e) => e.name === "file.txt");
161
+ expect(fileEntry?.size).toBe(5);
162
+ });
163
+ it("should include modification time", async () => {
164
+ await fs.writeFile(path.join(tempDir, "file.txt"), "content");
165
+ const result = await listDirectory({}, context);
166
+ expect(result.success).toBe(true);
167
+ const fileEntry = result.entries.find((e) => e.name === "file.txt");
168
+ expect(fileEntry?.modified).toBeDefined();
169
+ expect(new Date(fileEntry.modified).getTime()).toBeGreaterThan(0);
170
+ });
171
+ });
172
+ describe("sorting", () => {
173
+ it("should sort directories before files", async () => {
174
+ await fs.writeFile(path.join(tempDir, "aaa.txt"), "content");
175
+ await fs.mkdir(path.join(tempDir, "zzz"));
176
+ const result = await listDirectory({}, context);
177
+ expect(result.success).toBe(true);
178
+ expect(result.entries[0].name).toBe("zzz");
179
+ expect(result.entries[0].type).toBe("directory");
180
+ });
181
+ it("should sort alphabetically within type", async () => {
182
+ await fs.writeFile(path.join(tempDir, "c.txt"), "content");
183
+ await fs.writeFile(path.join(tempDir, "a.txt"), "content");
184
+ await fs.writeFile(path.join(tempDir, "b.txt"), "content");
185
+ const result = await listDirectory({}, context);
186
+ expect(result.success).toBe(true);
187
+ const names = result.entries.map((e) => e.name);
188
+ expect(names).toEqual(["a.txt", "b.txt", "c.txt"]);
189
+ });
190
+ });
191
+ });
192
+ //# sourceMappingURL=list-directory.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-directory.test.js","sourceRoot":"","sources":["../../../../../../src/lib/local-tools/code/__tests__/list-directory.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Unit tests for read_file tool.
3
+ * Tests file reading, line ranges, path validation, and language detection.
4
+ */
5
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
6
+ import * as fs from "fs/promises";
7
+ import * as path from "path";
8
+ import * as os from "os";
9
+ import { readFile } from "../read-file.js";
10
+ describe("readFile", () => {
11
+ let tempDir;
12
+ let context;
13
+ beforeEach(async () => {
14
+ // Create a temporary directory for tests
15
+ tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "read-file-test-"));
16
+ context = { workingDirectory: tempDir };
17
+ });
18
+ afterEach(async () => {
19
+ // Clean up temporary directory
20
+ await fs.rm(tempDir, { recursive: true, force: true });
21
+ });
22
+ describe("basic file reading", () => {
23
+ it("should read a file successfully", async () => {
24
+ const testContent = "line 1\nline 2\nline 3";
25
+ await fs.writeFile(path.join(tempDir, "test.txt"), testContent);
26
+ const result = await readFile({ path: "test.txt" }, context);
27
+ expect(result.success).toBe(true);
28
+ expect(result.path).toBe("test.txt");
29
+ expect(result.total_lines).toBe(3);
30
+ expect(result.start_line).toBe(1);
31
+ expect(result.end_line).toBe(3);
32
+ expect(result.content).toContain("line 1");
33
+ expect(result.content).toContain("line 2");
34
+ expect(result.content).toContain("line 3");
35
+ });
36
+ it("should return error for non-existent file", async () => {
37
+ const result = await readFile({ path: "nonexistent.txt" }, context);
38
+ expect(result.success).toBe(false);
39
+ expect(result.error).toBe("File not found");
40
+ });
41
+ it("should return error for directory path", async () => {
42
+ await fs.mkdir(path.join(tempDir, "subdir"));
43
+ const result = await readFile({ path: "subdir" }, context);
44
+ expect(result.success).toBe(false);
45
+ expect(result.error).toBe("Path is a directory, not a file");
46
+ });
47
+ });
48
+ describe("line range support", () => {
49
+ it("should read specific line range", async () => {
50
+ const testContent = "line 1\nline 2\nline 3\nline 4\nline 5";
51
+ await fs.writeFile(path.join(tempDir, "test.txt"), testContent);
52
+ const result = await readFile({ path: "test.txt", start_line: 2, end_line: 4 }, context);
53
+ expect(result.success).toBe(true);
54
+ expect(result.start_line).toBe(2);
55
+ expect(result.end_line).toBe(4);
56
+ expect(result.content).toContain("line 2");
57
+ expect(result.content).toContain("line 3");
58
+ expect(result.content).toContain("line 4");
59
+ expect(result.content).not.toContain("line 1");
60
+ expect(result.content).not.toContain("line 5");
61
+ });
62
+ it("should clamp start_line to 1 if less than 1", async () => {
63
+ const testContent = "line 1\nline 2\nline 3";
64
+ await fs.writeFile(path.join(tempDir, "test.txt"), testContent);
65
+ const result = await readFile({ path: "test.txt", start_line: -5 }, context);
66
+ expect(result.success).toBe(true);
67
+ expect(result.start_line).toBe(1);
68
+ });
69
+ it("should clamp end_line to total_lines if exceeds file length", async () => {
70
+ const testContent = "line 1\nline 2\nline 3";
71
+ await fs.writeFile(path.join(tempDir, "test.txt"), testContent);
72
+ const result = await readFile({ path: "test.txt", end_line: 100 }, context);
73
+ expect(result.success).toBe(true);
74
+ expect(result.end_line).toBe(3);
75
+ });
76
+ it("should handle start_line greater than total_lines", async () => {
77
+ const testContent = "line 1\nline 2\nline 3";
78
+ await fs.writeFile(path.join(tempDir, "test.txt"), testContent);
79
+ const result = await readFile({ path: "test.txt", start_line: 100 }, context);
80
+ expect(result.success).toBe(true);
81
+ expect(result.start_line).toBe(3);
82
+ });
83
+ });
84
+ describe("line number formatting", () => {
85
+ it("should include line numbers by default", async () => {
86
+ const testContent = "line 1\nline 2";
87
+ await fs.writeFile(path.join(tempDir, "test.txt"), testContent);
88
+ const result = await readFile({ path: "test.txt" }, context);
89
+ expect(result.success).toBe(true);
90
+ expect(result.content).toMatch(/1 \| line 1/);
91
+ expect(result.content).toMatch(/2 \| line 2/);
92
+ });
93
+ it("should exclude line numbers when show_line_numbers is false", async () => {
94
+ const testContent = "line 1\nline 2";
95
+ await fs.writeFile(path.join(tempDir, "test.txt"), testContent);
96
+ const result = await readFile({ path: "test.txt", show_line_numbers: false }, context);
97
+ expect(result.success).toBe(true);
98
+ expect(result.content).toBe("line 1\nline 2");
99
+ expect(result.content).not.toContain("|");
100
+ });
101
+ });
102
+ describe("path validation (security)", () => {
103
+ it("should prevent directory traversal with ../", async () => {
104
+ const result = await readFile({ path: "../../../etc/passwd" }, context);
105
+ expect(result.success).toBe(false);
106
+ expect(result.error).toBe("Path validation failed: access denied");
107
+ });
108
+ it("should allow reading files in subdirectories", async () => {
109
+ await fs.mkdir(path.join(tempDir, "subdir"));
110
+ await fs.writeFile(path.join(tempDir, "subdir", "test.txt"), "content");
111
+ const result = await readFile({ path: "subdir/test.txt" }, context);
112
+ expect(result.success).toBe(true);
113
+ expect(result.content).toContain("content");
114
+ });
115
+ it("should handle absolute paths within working directory", async () => {
116
+ await fs.writeFile(path.join(tempDir, "test.txt"), "content");
117
+ const absolutePath = path.join(tempDir, "test.txt");
118
+ const result = await readFile({ path: absolutePath }, context);
119
+ expect(result.success).toBe(true);
120
+ });
121
+ });
122
+ describe("language detection", () => {
123
+ it("should detect TypeScript files", async () => {
124
+ await fs.writeFile(path.join(tempDir, "test.ts"), "const x = 1;");
125
+ const result = await readFile({ path: "test.ts" }, context);
126
+ expect(result.success).toBe(true);
127
+ expect(result.language).toBe("typescript");
128
+ });
129
+ it("should detect JavaScript files", async () => {
130
+ await fs.writeFile(path.join(tempDir, "test.js"), "const x = 1;");
131
+ const result = await readFile({ path: "test.js" }, context);
132
+ expect(result.success).toBe(true);
133
+ expect(result.language).toBe("javascript");
134
+ });
135
+ it("should detect Python files", async () => {
136
+ await fs.writeFile(path.join(tempDir, "test.py"), "x = 1");
137
+ const result = await readFile({ path: "test.py" }, context);
138
+ expect(result.success).toBe(true);
139
+ expect(result.language).toBe("python");
140
+ });
141
+ it("should detect JSON files", async () => {
142
+ await fs.writeFile(path.join(tempDir, "test.json"), "{}");
143
+ const result = await readFile({ path: "test.json" }, context);
144
+ expect(result.success).toBe(true);
145
+ expect(result.language).toBe("json");
146
+ });
147
+ it("should detect Markdown files", async () => {
148
+ await fs.writeFile(path.join(tempDir, "test.md"), "# Title");
149
+ const result = await readFile({ path: "test.md" }, context);
150
+ expect(result.success).toBe(true);
151
+ expect(result.language).toBe("markdown");
152
+ });
153
+ it("should return undefined for unknown extensions", async () => {
154
+ await fs.writeFile(path.join(tempDir, "test.xyz"), "content");
155
+ const result = await readFile({ path: "test.xyz" }, context);
156
+ expect(result.success).toBe(true);
157
+ expect(result.language).toBeUndefined();
158
+ });
159
+ });
160
+ describe("empty file handling", () => {
161
+ it("should handle empty files", async () => {
162
+ await fs.writeFile(path.join(tempDir, "empty.txt"), "");
163
+ const result = await readFile({ path: "empty.txt" }, context);
164
+ expect(result.success).toBe(true);
165
+ expect(result.total_lines).toBe(1); // Empty file has one empty line
166
+ });
167
+ });
168
+ });
169
+ //# sourceMappingURL=read-file.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-file.test.js","sourceRoot":"","sources":["../../../../../../src/lib/local-tools/code/__tests__/read-file.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAC,MAAM,QAAQ,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAC,QAAQ,EAAC,MAAM,iBAAiB,CAAC;AAGzC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,IAAI,OAAe,CAAC;IACpB,IAAI,OAAoB,CAAC;IAEzB,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,yCAAyC;QACzC,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;QACtE,OAAO,GAAG,EAAC,gBAAgB,EAAE,OAAO,EAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,+BAA+B;QAC/B,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAC,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,WAAW,GAAG,wBAAwB,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;YAEhE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,UAAU,EAAC,EAAE,OAAO,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,iBAAiB,EAAC,EAAE,OAAO,CAAC,CAAC;YAElE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;YAE7C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAC,EAAE,OAAO,CAAC,CAAC;YAEzD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,WAAW,GAAG,wCAAwC,CAAC;YAC7D,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;YAEhE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC3B,EAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAC,EAC9C,OAAO,CACR,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,WAAW,GAAG,wBAAwB,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;YAEhE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC3B,EAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,EAAC,EAClC,OAAO,CACR,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YAC3E,MAAM,WAAW,GAAG,wBAAwB,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;YAEhE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAC,EAAE,OAAO,CAAC,CAAC;YAE1E,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,WAAW,GAAG,wBAAwB,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;YAEhE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC3B,EAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,EAAC,EACnC,OAAO,CACR,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACtC,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,WAAW,GAAG,gBAAgB,CAAC;YACrC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;YAEhE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,UAAU,EAAC,EAAE,OAAO,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YAC3E,MAAM,WAAW,GAAG,gBAAgB,CAAC;YACrC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;YAEhE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC3B,EAAC,IAAI,EAAE,UAAU,EAAE,iBAAiB,EAAE,KAAK,EAAC,EAC5C,OAAO,CACR,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAC1C,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,qBAAqB,EAAC,EAAE,OAAO,CAAC,CAAC;YAEtE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC;YAExE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,iBAAiB,EAAC,EAAE,OAAO,CAAC,CAAC;YAElE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC;YAC9D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAEpD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,YAAY,EAAC,EAAE,OAAO,CAAC,CAAC;YAE7D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,cAAc,CAAC,CAAC;YAElE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,SAAS,EAAC,EAAE,OAAO,CAAC,CAAC;YAE1D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,cAAc,CAAC,CAAC;YAElE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,SAAS,EAAC,EAAE,OAAO,CAAC,CAAC;YAE1D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;YAE3D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,SAAS,EAAC,EAAE,OAAO,CAAC,CAAC;YAE1D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;YACxC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;YAE1D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,WAAW,EAAC,EAAE,OAAO,CAAC,CAAC;YAE5D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;YAE7D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,SAAS,EAAC,EAAE,OAAO,CAAC,CAAC;YAE1D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC;YAE9D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,UAAU,EAAC,EAAE,OAAO,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,aAAa,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;YAExD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAC,IAAI,EAAE,WAAW,EAAC,EAAE,OAAO,CAAC,CAAC;YAE5D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,gCAAgC;QACtE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Unit tests for run_command tool.
3
+ * Tests command execution, timeout, and working directory validation.
4
+ */
5
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
6
+ import * as fs from "fs/promises";
7
+ import * as path from "path";
8
+ import * as os from "os";
9
+ import { runCommand } from "../run-command.js";
10
+ describe("runCommand", () => {
11
+ let tempDir;
12
+ let context;
13
+ beforeEach(async () => {
14
+ tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "run-command-test-"));
15
+ context = { workingDirectory: tempDir };
16
+ });
17
+ afterEach(async () => {
18
+ await fs.rm(tempDir, { recursive: true, force: true });
19
+ });
20
+ describe("command execution", () => {
21
+ it("should execute command successfully", async () => {
22
+ const result = await runCommand({ command: "node", args: ["--version"] }, context);
23
+ expect(result.success).toBe(true);
24
+ expect(result.exit_code).toBe(0);
25
+ expect(result.stdout).toMatch(/v\d+\.\d+\.\d+/);
26
+ });
27
+ it("should capture stdout", async () => {
28
+ const result = await runCommand({ command: "node", args: ["-e", 'console.log("hello")'] }, context);
29
+ expect(result.success).toBe(true);
30
+ expect(result.stdout.trim()).toBe("hello");
31
+ });
32
+ it("should capture stderr", async () => {
33
+ const result = await runCommand({ command: "node", args: ["-e", 'console.error("error msg")'] }, context);
34
+ expect(result.success).toBe(true);
35
+ expect(result.stderr.trim()).toBe("error msg");
36
+ });
37
+ it("should return non-zero exit code for failed commands", async () => {
38
+ const result = await runCommand({ command: "node", args: ["-e", "process.exit(1)"] }, context);
39
+ expect(result.success).toBe(false);
40
+ expect(result.exit_code).toBe(1);
41
+ });
42
+ });
43
+ describe("timeout", () => {
44
+ it("should timeout long-running commands", async () => {
45
+ const result = await runCommand({
46
+ command: "node",
47
+ args: ["-e", "setTimeout(() => {}, 10000)"],
48
+ timeout: 500,
49
+ }, context);
50
+ expect(result.success).toBe(false);
51
+ expect(result.timed_out).toBe(true);
52
+ expect(result.error).toContain("timed out");
53
+ }, 10000);
54
+ it("should complete before timeout for fast commands", async () => {
55
+ const result = await runCommand({ command: "node", args: ["-e", 'console.log("fast")'], timeout: 5000 }, context);
56
+ expect(result.success).toBe(true);
57
+ expect(result.timed_out).toBe(false);
58
+ });
59
+ it("should record duration", async () => {
60
+ const result = await runCommand({ command: "node", args: ["--version"] }, context);
61
+ expect(result.duration_ms).toBeGreaterThan(0);
62
+ expect(result.duration_ms).toBeLessThan(5000);
63
+ });
64
+ });
65
+ describe("working directory validation", () => {
66
+ it("should run command in specified working directory", async () => {
67
+ await fs.mkdir(path.join(tempDir, "subdir"));
68
+ const result = await runCommand({
69
+ command: "node",
70
+ args: ["-e", "console.log(process.cwd())"],
71
+ cwd: "subdir",
72
+ }, context);
73
+ expect(result.success).toBe(true);
74
+ expect(result.stdout).toContain("subdir");
75
+ });
76
+ it("should prevent directory traversal in cwd", async () => {
77
+ const result = await runCommand({ command: "node", args: ["--version"], cwd: "../../../" }, context);
78
+ expect(result.success).toBe(false);
79
+ expect(result.error).toContain("access denied");
80
+ });
81
+ it("should use working directory by default", async () => {
82
+ const result = await runCommand({ command: "node", args: ["-e", "console.log(process.cwd())"] }, context);
83
+ expect(result.success).toBe(true);
84
+ // Use realpath to handle macOS symlinks (/var -> /private/var)
85
+ const realTempDir = await fs.realpath(tempDir);
86
+ expect(result.stdout.trim()).toBe(realTempDir);
87
+ });
88
+ });
89
+ describe("environment variables", () => {
90
+ it("should pass additional environment variables", async () => {
91
+ const result = await runCommand({
92
+ command: "node",
93
+ args: ["-e", "console.log(process.env.TEST_VAR)"],
94
+ env: { TEST_VAR: "test_value" },
95
+ }, context);
96
+ expect(result.success).toBe(true);
97
+ expect(result.stdout.trim()).toBe("test_value");
98
+ });
99
+ });
100
+ });
101
+ //# sourceMappingURL=run-command.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-command.test.js","sourceRoot":"","sources":["../../../../../../src/lib/local-tools/code/__tests__/run-command.test.ts"],"names":[],"mappings":"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"}