@timetotest/cli 0.2.4 → 0.3.1

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 (114) 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 +8 -3
  5. package/dist/src/commands/chat/ChatApp.js +249 -67
  6. package/dist/src/commands/chat/ChatApp.js.map +1 -1
  7. package/dist/src/commands/chat/OnboardingApp.js +49 -0
  8. package/dist/src/commands/chat/OnboardingApp.js.map +1 -0
  9. package/dist/src/commands/chat/components/Banner.js +1 -1
  10. package/dist/src/commands/chat/components/Banner.js.map +1 -1
  11. package/dist/src/commands/chat/components/ChatInput.js +61 -22
  12. package/dist/src/commands/chat/components/ChatInput.js.map +1 -1
  13. package/dist/src/commands/chat/components/ChatMessage.js +102 -0
  14. package/dist/src/commands/chat/components/ChatMessage.js.map +1 -0
  15. package/dist/src/commands/chat/components/MessageBubble.js +1 -1
  16. package/dist/src/commands/chat/components/MessageBubble.js.map +1 -1
  17. package/dist/src/commands/chat/components/PermissionPrompt.js +92 -0
  18. package/dist/src/commands/chat/components/PermissionPrompt.js.map +1 -0
  19. package/dist/src/commands/chat/components/StatusIndicator.js +21 -5
  20. package/dist/src/commands/chat/components/StatusIndicator.js.map +1 -1
  21. package/dist/src/commands/chat/components/ToolCallDisplay.js +141 -0
  22. package/dist/src/commands/chat/components/ToolCallDisplay.js.map +1 -0
  23. package/dist/src/commands/chat-ink.js +328 -93
  24. package/dist/src/commands/chat-ink.js.map +1 -1
  25. package/dist/src/commands/login.js +5 -5
  26. package/dist/src/commands/login.js.map +1 -1
  27. package/dist/src/commands/test.js +14 -291
  28. package/dist/src/commands/test.js.map +1 -1
  29. package/dist/src/lib/__tests__/code-mode-integration.test.js +381 -0
  30. package/dist/src/lib/__tests__/code-mode-integration.test.js.map +1 -0
  31. package/dist/src/lib/__tests__/config-manager.test.js +81 -0
  32. package/dist/src/lib/__tests__/config-manager.test.js.map +1 -0
  33. package/dist/src/lib/__tests__/mode-persistence-integration.test.js +75 -0
  34. package/dist/src/lib/__tests__/mode-persistence-integration.test.js.map +1 -0
  35. package/dist/src/lib/__tests__/permission-flow-integration.test.js +145 -0
  36. package/dist/src/lib/__tests__/permission-flow-integration.test.js.map +1 -0
  37. package/dist/src/lib/__tests__/permissions.test.js +132 -0
  38. package/dist/src/lib/__tests__/permissions.test.js.map +1 -0
  39. package/dist/src/lib/agent-orchestrator.js +259 -5
  40. package/dist/src/lib/agent-orchestrator.js.map +1 -1
  41. package/dist/src/lib/config.js +40 -0
  42. package/dist/src/lib/config.js.map +1 -1
  43. package/dist/src/lib/context-compactor.js +310 -0
  44. package/dist/src/lib/context-compactor.js.map +1 -0
  45. package/dist/src/lib/http.js +8 -0
  46. package/dist/src/lib/http.js.map +1 -1
  47. package/dist/src/lib/local-tools/code/__tests__/grep-search.test.js +146 -0
  48. package/dist/src/lib/local-tools/code/__tests__/grep-search.test.js.map +1 -0
  49. package/dist/src/lib/local-tools/code/__tests__/list-directory.test.js +192 -0
  50. package/dist/src/lib/local-tools/code/__tests__/list-directory.test.js.map +1 -0
  51. package/dist/src/lib/local-tools/code/__tests__/read-file.test.js +169 -0
  52. package/dist/src/lib/local-tools/code/__tests__/read-file.test.js.map +1 -0
  53. package/dist/src/lib/local-tools/code/__tests__/run-command.test.js +101 -0
  54. package/dist/src/lib/local-tools/code/__tests__/run-command.test.js.map +1 -0
  55. package/dist/src/lib/local-tools/code/__tests__/search-files.test.js +191 -0
  56. package/dist/src/lib/local-tools/code/__tests__/search-files.test.js.map +1 -0
  57. package/dist/src/lib/local-tools/code/grep-search.js +404 -0
  58. package/dist/src/lib/local-tools/code/grep-search.js.map +1 -0
  59. package/dist/src/lib/local-tools/code/index.js +11 -0
  60. package/dist/src/lib/local-tools/code/index.js.map +1 -0
  61. package/dist/src/lib/local-tools/code/list-directory.js +276 -0
  62. package/dist/src/lib/local-tools/code/list-directory.js.map +1 -0
  63. package/dist/src/lib/local-tools/code/read-file.js +301 -0
  64. package/dist/src/lib/local-tools/code/read-file.js.map +1 -0
  65. package/dist/src/lib/local-tools/code/run-command.js +235 -0
  66. package/dist/src/lib/local-tools/code/run-command.js.map +1 -0
  67. package/dist/src/lib/local-tools/code/search-files.js +297 -0
  68. package/dist/src/lib/local-tools/code/search-files.js.map +1 -0
  69. package/dist/src/lib/local-tools/code/types.js +6 -0
  70. package/dist/src/lib/local-tools/code/types.js.map +1 -0
  71. package/dist/src/lib/permissions.js +94 -0
  72. package/dist/src/lib/permissions.js.map +1 -0
  73. package/dist/src/lib/prompts/builder.js +13 -10
  74. package/dist/src/lib/prompts/builder.js.map +1 -1
  75. package/dist/src/lib/prompts/templates.js +78 -0
  76. package/dist/src/lib/prompts/templates.js.map +1 -1
  77. package/dist/src/lib/session-manager.js.map +1 -1
  78. package/dist/src/lib/testing-mode.js +2 -2
  79. package/dist/src/lib/testing-mode.js.map +1 -1
  80. package/dist/src/lib/tool-executor.js +131 -2
  81. package/dist/src/lib/tool-executor.js.map +1 -1
  82. package/dist/src/lib/tool-registry.js +171 -3
  83. package/dist/src/lib/tool-registry.js.map +1 -1
  84. package/dist/src/lib/tool-result-pruner.js +4 -4
  85. package/dist/src/lib/tool-result-pruner.js.map +1 -1
  86. package/dist/src/lib/tui/ink/components/AppFrame.js +17 -0
  87. package/dist/src/lib/tui/ink/components/AppFrame.js.map +1 -0
  88. package/dist/src/lib/tui/ink/components/CommandPalette.js +24 -0
  89. package/dist/src/lib/tui/ink/components/CommandPalette.js.map +1 -0
  90. package/dist/src/lib/tui/ink/components/Pill.js +19 -0
  91. package/dist/src/lib/tui/ink/components/Pill.js.map +1 -0
  92. package/dist/src/lib/tui/ink/components/TimetoTestLogo.js +30 -0
  93. package/dist/src/lib/tui/ink/components/TimetoTestLogo.js.map +1 -0
  94. package/dist/src/lib/tui/ink/theme.js +13 -6
  95. package/dist/src/lib/tui/ink/theme.js.map +1 -1
  96. package/dist/src/lib/tui/interactive-chat.js +35 -35
  97. package/dist/src/lib/tui/interactive-chat.js.map +1 -1
  98. package/dist/src/lib/tui/print.js +18 -18
  99. package/dist/src/lib/tui/print.js.map +1 -1
  100. package/dist/src/lib/tui/prompt.js +3 -3
  101. package/dist/src/lib/tui/prompt.js.map +1 -1
  102. package/dist/src/lib/tui/status.js +1 -1
  103. package/dist/src/lib/tui/status.js.map +1 -1
  104. package/dist/src/lib/update.js +10 -10
  105. package/dist/src/lib/update.js.map +1 -1
  106. package/package.json +8 -3
  107. package/dist/src/commands/start-test.js +0 -180
  108. package/dist/src/commands/start-test.js.map +0 -1
  109. package/dist/src/commands/stream/StreamApp.js +0 -127
  110. package/dist/src/commands/stream/StreamApp.js.map +0 -1
  111. package/dist/src/commands/stream.js +0 -52
  112. package/dist/src/commands/stream.js.map +0 -1
  113. package/dist/src/commands/test/TestRunApp.js +0 -183
  114. package/dist/src/commands/test/TestRunApp.js.map +0 -1
@@ -0,0 +1,381 @@
1
+ /**
2
+ * Integration tests for Code Testing Mode.
3
+ * Tests mode switching, tool availability per mode, and end-to-end code analysis flow.
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 { parseTestingMode, resolveTestingMode, isTestingMode, TESTING_MODES, } from "../testing-mode.js";
10
+ import { getToolSchemasByDomain } from "../tool-registry.js";
11
+ import { ToolExecutor } from "../tool-executor.js";
12
+ describe("Code Mode Integration Tests", () => {
13
+ /**
14
+ * Task 14.1: Test mode switching to/from code mode
15
+ */
16
+ describe("Mode Switching", () => {
17
+ describe("parseTestingMode", () => {
18
+ it("should parse 'code' as a valid testing mode", () => {
19
+ const result = parseTestingMode("code");
20
+ expect(result).toBe("code");
21
+ });
22
+ it("should parse 'CODE' (uppercase) as 'code'", () => {
23
+ const result = parseTestingMode("CODE");
24
+ expect(result).toBe("code");
25
+ });
26
+ it("should parse 'Code' (mixed case) as 'code'", () => {
27
+ const result = parseTestingMode("Code");
28
+ expect(result).toBe("code");
29
+ });
30
+ it("should still parse 'ui' and 'api' modes correctly", () => {
31
+ expect(parseTestingMode("ui")).toBe("ui");
32
+ expect(parseTestingMode("api")).toBe("api");
33
+ });
34
+ it("should return null for invalid modes", () => {
35
+ expect(parseTestingMode("invalid")).toBeNull();
36
+ expect(parseTestingMode("")).toBeNull();
37
+ expect(parseTestingMode(123)).toBeNull();
38
+ expect(parseTestingMode(null)).toBeNull();
39
+ });
40
+ });
41
+ describe("resolveTestingMode", () => {
42
+ it("should resolve 'code' mode correctly", () => {
43
+ const result = resolveTestingMode("code");
44
+ expect(result).toBe("code");
45
+ });
46
+ it("should use default mode when value is empty", () => {
47
+ expect(resolveTestingMode(undefined)).toBe("ui");
48
+ expect(resolveTestingMode(null)).toBe("ui");
49
+ expect(resolveTestingMode("")).toBe("ui");
50
+ });
51
+ it("should use custom default mode when specified", () => {
52
+ const result = resolveTestingMode(undefined, { defaultMode: "code" });
53
+ expect(result).toBe("code");
54
+ });
55
+ it("should throw error in strict mode for invalid values", () => {
56
+ expect(() => resolveTestingMode("invalid", { strict: true })).toThrow(/invalid testing mode/);
57
+ });
58
+ it("should throw error in strict mode for empty values", () => {
59
+ expect(() => resolveTestingMode("", { strict: true })).toThrow(/invalid testing mode/);
60
+ });
61
+ it("should include context label in error message", () => {
62
+ expect(() => resolveTestingMode("invalid", {
63
+ strict: true,
64
+ contextLabel: "CLI flag",
65
+ })).toThrow(/CLI flag/);
66
+ });
67
+ });
68
+ describe("isTestingMode", () => {
69
+ it("should return true for 'code'", () => {
70
+ expect(isTestingMode("code")).toBe(true);
71
+ });
72
+ it("should return true for 'ui' and 'api'", () => {
73
+ expect(isTestingMode("ui")).toBe(true);
74
+ expect(isTestingMode("api")).toBe(true);
75
+ });
76
+ it("should return false for invalid modes", () => {
77
+ expect(isTestingMode("invalid")).toBe(false);
78
+ expect(isTestingMode("")).toBe(false);
79
+ expect(isTestingMode(null)).toBe(false);
80
+ expect(isTestingMode(undefined)).toBe(false);
81
+ });
82
+ });
83
+ describe("TESTING_MODES constant", () => {
84
+ it("should include 'code' in the list of testing modes", () => {
85
+ expect(TESTING_MODES).toContain("code");
86
+ });
87
+ it("should include all three modes: ui, api, code", () => {
88
+ expect(TESTING_MODES).toEqual(["ui", "api", "code"]);
89
+ });
90
+ });
91
+ });
92
+ /**
93
+ * Task 14.2: Test tool availability per mode (code tools only in code mode)
94
+ */
95
+ describe("Tool Availability Per Mode", () => {
96
+ const CODE_TOOLS = [
97
+ "read_file",
98
+ "list_directory",
99
+ "search_files",
100
+ "grep_search",
101
+ "run_command",
102
+ ];
103
+ const GENERAL_TOOLS = ["finish", "set_testing_mode"];
104
+ describe("getToolSchemasByDomain for code mode", () => {
105
+ it("should return all code tools when domain is 'code'", () => {
106
+ const tools = getToolSchemasByDomain("code");
107
+ const toolNames = Object.keys(tools);
108
+ for (const codeTool of CODE_TOOLS) {
109
+ expect(toolNames).toContain(codeTool);
110
+ }
111
+ });
112
+ it("should include general tools in code mode", () => {
113
+ const tools = getToolSchemasByDomain("code");
114
+ const toolNames = Object.keys(tools);
115
+ for (const generalTool of GENERAL_TOOLS) {
116
+ expect(toolNames).toContain(generalTool);
117
+ }
118
+ });
119
+ it("should have correct schema structure for code tools", () => {
120
+ const tools = getToolSchemasByDomain("code");
121
+ for (const toolName of CODE_TOOLS) {
122
+ const schema = tools[toolName];
123
+ expect(schema).toBeDefined();
124
+ expect(schema.name).toBe(toolName);
125
+ expect(schema.description).toBeTruthy();
126
+ expect(schema.parameters).toBeDefined();
127
+ expect(schema.parameters.type).toBe("object");
128
+ }
129
+ });
130
+ });
131
+ describe("code tools not available in other modes", () => {
132
+ it("should NOT include code tools in 'ui' mode", () => {
133
+ const tools = getToolSchemasByDomain("ui");
134
+ const toolNames = Object.keys(tools);
135
+ for (const codeTool of CODE_TOOLS) {
136
+ expect(toolNames).not.toContain(codeTool);
137
+ }
138
+ });
139
+ it("should NOT include code tools in 'api' mode", () => {
140
+ const tools = getToolSchemasByDomain("api");
141
+ const toolNames = Object.keys(tools);
142
+ for (const codeTool of CODE_TOOLS) {
143
+ expect(toolNames).not.toContain(codeTool);
144
+ }
145
+ });
146
+ it("should include general tools in all modes", () => {
147
+ const uiTools = getToolSchemasByDomain("ui");
148
+ const apiTools = getToolSchemasByDomain("api");
149
+ const codeTools = getToolSchemasByDomain("code");
150
+ for (const generalTool of GENERAL_TOOLS) {
151
+ expect(Object.keys(uiTools)).toContain(generalTool);
152
+ expect(Object.keys(apiTools)).toContain(generalTool);
153
+ expect(Object.keys(codeTools)).toContain(generalTool);
154
+ }
155
+ });
156
+ });
157
+ describe("UI tools not available in code mode", () => {
158
+ const UI_TOOLS = [
159
+ "browser_navigate",
160
+ "browser_click",
161
+ "browser_type",
162
+ "browser_hover",
163
+ ];
164
+ it("should NOT include UI tools in 'code' mode", () => {
165
+ const tools = getToolSchemasByDomain("code");
166
+ const toolNames = Object.keys(tools);
167
+ for (const uiTool of UI_TOOLS) {
168
+ expect(toolNames).not.toContain(uiTool);
169
+ }
170
+ });
171
+ });
172
+ describe("API tools not available in code mode", () => {
173
+ const API_TOOLS = [
174
+ "api_request",
175
+ "build_api_request",
176
+ "generate_curl",
177
+ "validate_api_response",
178
+ ];
179
+ it("should NOT include API tools in 'code' mode", () => {
180
+ const tools = getToolSchemasByDomain("code");
181
+ const toolNames = Object.keys(tools);
182
+ for (const apiTool of API_TOOLS) {
183
+ expect(toolNames).not.toContain(apiTool);
184
+ }
185
+ });
186
+ });
187
+ });
188
+ /**
189
+ * Task 14.3: Test end-to-end code analysis flow
190
+ */
191
+ describe("End-to-End Code Analysis Flow", () => {
192
+ let tempDir;
193
+ let executor;
194
+ beforeEach(async () => {
195
+ // Create a temporary directory for tests
196
+ tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "code-mode-integration-"));
197
+ // Create executor in code mode
198
+ const context = {
199
+ testingMode: "code",
200
+ codeContext: {
201
+ workingDirectory: tempDir,
202
+ },
203
+ };
204
+ executor = new ToolExecutor(context);
205
+ });
206
+ afterEach(async () => {
207
+ // Clean up temporary directory
208
+ await fs.rm(tempDir, { recursive: true, force: true });
209
+ });
210
+ describe("ToolExecutor executes code tools in code mode", () => {
211
+ it("should execute read_file successfully in code mode", async () => {
212
+ // Create a test file
213
+ const testContent = "const x = 1;\nconst y = 2;";
214
+ await fs.writeFile(path.join(tempDir, "test.ts"), testContent);
215
+ const result = await executor.execute({
216
+ name: "read_file",
217
+ arguments: { path: "test.ts" },
218
+ });
219
+ expect(result.success).toBe(true);
220
+ expect(result.content).toContain("const x = 1");
221
+ expect(result.language).toBe("typescript");
222
+ });
223
+ it("should execute list_directory successfully in code mode", async () => {
224
+ // Create test files
225
+ await fs.writeFile(path.join(tempDir, "file1.ts"), "");
226
+ await fs.writeFile(path.join(tempDir, "file2.ts"), "");
227
+ await fs.mkdir(path.join(tempDir, "subdir"));
228
+ const result = await executor.execute({
229
+ name: "list_directory",
230
+ arguments: { path: "." },
231
+ });
232
+ expect(result.success).toBe(true);
233
+ expect(result.entries).toBeDefined();
234
+ expect(result.entries.length).toBeGreaterThanOrEqual(3);
235
+ });
236
+ it("should execute search_files successfully in code mode", async () => {
237
+ // Create test files
238
+ await fs.writeFile(path.join(tempDir, "file1.ts"), "");
239
+ await fs.writeFile(path.join(tempDir, "file2.ts"), "");
240
+ await fs.writeFile(path.join(tempDir, "file3.js"), "");
241
+ const result = await executor.execute({
242
+ name: "search_files",
243
+ arguments: { pattern: "*.ts" },
244
+ });
245
+ expect(result.success).toBe(true);
246
+ expect(result.files).toBeDefined();
247
+ expect(result.files.length).toBe(2);
248
+ });
249
+ it("should execute grep_search successfully in code mode", async () => {
250
+ // Create test file with searchable content
251
+ await fs.writeFile(path.join(tempDir, "test.ts"), "function hello() {\n return 'world';\n}");
252
+ const result = await executor.execute({
253
+ name: "grep_search",
254
+ arguments: { query: "hello" },
255
+ });
256
+ expect(result.success).toBe(true);
257
+ expect(result.matches).toBeDefined();
258
+ expect(result.matches.length).toBeGreaterThan(0);
259
+ });
260
+ });
261
+ describe("ToolExecutor rejects code tools when not in code mode", () => {
262
+ it("should reject read_file when in UI mode", async () => {
263
+ const uiContext = {
264
+ testingMode: "ui",
265
+ };
266
+ const uiExecutor = new ToolExecutor(uiContext);
267
+ const result = await uiExecutor.execute({
268
+ name: "read_file",
269
+ arguments: { path: "test.ts" },
270
+ });
271
+ expect(result.error).toBeDefined();
272
+ expect(result.error).toContain("code mode");
273
+ expect(result.current_mode).toBe("ui");
274
+ });
275
+ it("should reject list_directory when in API mode", async () => {
276
+ const apiContext = {
277
+ testingMode: "api",
278
+ };
279
+ const apiExecutor = new ToolExecutor(apiContext);
280
+ const result = await apiExecutor.execute({
281
+ name: "list_directory",
282
+ arguments: { path: "." },
283
+ });
284
+ expect(result.error).toBeDefined();
285
+ expect(result.error).toContain("code mode");
286
+ expect(result.current_mode).toBe("api");
287
+ });
288
+ it("should reject grep_search when in UI mode", async () => {
289
+ const uiContext = {
290
+ testingMode: "ui",
291
+ };
292
+ const uiExecutor = new ToolExecutor(uiContext);
293
+ const result = await uiExecutor.execute({
294
+ name: "grep_search",
295
+ arguments: { query: "test" },
296
+ });
297
+ expect(result.error).toBeDefined();
298
+ expect(result.error).toContain("code mode");
299
+ });
300
+ it("should reject run_command when in API mode", async () => {
301
+ const apiContext = {
302
+ testingMode: "api",
303
+ };
304
+ const apiExecutor = new ToolExecutor(apiContext);
305
+ const result = await apiExecutor.execute({
306
+ name: "run_command",
307
+ arguments: { command: "echo", args: ["hello"] },
308
+ });
309
+ expect(result.error).toBeDefined();
310
+ expect(result.error).toContain("code mode");
311
+ });
312
+ });
313
+ describe("Mode switching via set_testing_mode", () => {
314
+ it("should switch from UI mode to code mode", async () => {
315
+ const context = {
316
+ testingMode: "ui",
317
+ };
318
+ const switchExecutor = new ToolExecutor(context);
319
+ // First, verify code tools don't work in UI mode
320
+ let result = await switchExecutor.execute({
321
+ name: "read_file",
322
+ arguments: { path: "test.ts" },
323
+ });
324
+ expect(result.error).toContain("code mode");
325
+ // Switch to code mode
326
+ result = await switchExecutor.execute({
327
+ name: "set_testing_mode",
328
+ arguments: { mode: "code" },
329
+ });
330
+ expect(result.success).toBe(true);
331
+ expect(result.mode).toBe("code");
332
+ });
333
+ it("should switch from code mode to API mode", async () => {
334
+ const context = {
335
+ testingMode: "code",
336
+ codeContext: { workingDirectory: tempDir },
337
+ };
338
+ const switchExecutor = new ToolExecutor(context);
339
+ // Switch to API mode
340
+ const result = await switchExecutor.execute({
341
+ name: "set_testing_mode",
342
+ arguments: { mode: "api" },
343
+ });
344
+ expect(result.success).toBe(true);
345
+ expect(result.mode).toBe("api");
346
+ });
347
+ it("should reject invalid mode in set_testing_mode", async () => {
348
+ const context = {
349
+ testingMode: "code",
350
+ };
351
+ const switchExecutor = new ToolExecutor(context);
352
+ const result = await switchExecutor.execute({
353
+ name: "set_testing_mode",
354
+ arguments: { mode: "invalid" },
355
+ });
356
+ expect(result.success).toBe(false);
357
+ expect(result.error).toContain("Invalid testing mode");
358
+ });
359
+ });
360
+ describe("General tools work in code mode", () => {
361
+ it("should execute finish tool in code mode", async () => {
362
+ const result = await executor.execute({
363
+ name: "finish",
364
+ arguments: { summary: "Test completed" },
365
+ });
366
+ expect(result.success).toBe(true);
367
+ expect(result.finished).toBe(true);
368
+ expect(result.summary).toBe("Test completed");
369
+ });
370
+ it("should execute set_testing_mode in code mode", async () => {
371
+ const result = await executor.execute({
372
+ name: "set_testing_mode",
373
+ arguments: { mode: "ui" },
374
+ });
375
+ expect(result.success).toBe(true);
376
+ expect(result.mode).toBe("ui");
377
+ });
378
+ });
379
+ });
380
+ });
381
+ //# sourceMappingURL=code-mode-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-mode-integration.test.js","sourceRoot":"","sources":["../../../../src/lib/__tests__/code-mode-integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { ConfigManager } from "../config.js";
3
+ import fs from "fs-extra";
4
+ import path from "path";
5
+ import os from "os";
6
+ describe("ConfigManager", () => {
7
+ let testDir;
8
+ let configManager;
9
+ beforeEach(async () => {
10
+ // Create a temp directory for test preferences
11
+ testDir = path.join(os.tmpdir(), `ttt-test-${Date.now()}`);
12
+ await fs.ensureDir(testDir);
13
+ const prefsPath = path.join(testDir, "preferences.json");
14
+ configManager = new ConfigManager(prefsPath);
15
+ });
16
+ afterEach(async () => {
17
+ // Clean up temp directory
18
+ await fs.remove(testDir);
19
+ });
20
+ describe("loadPreferences", () => {
21
+ it("returns empty object when file does not exist", async () => {
22
+ const prefs = await configManager.loadPreferences();
23
+ expect(prefs).toEqual({});
24
+ });
25
+ it("loads preferences from file", async () => {
26
+ const prefsPath = path.join(testDir, "preferences.json");
27
+ await fs.writeJson(prefsPath, { lastMode: "code" });
28
+ const prefs = await configManager.loadPreferences();
29
+ expect(prefs).toEqual({ lastMode: "code" });
30
+ });
31
+ it("returns empty object on invalid JSON", async () => {
32
+ const prefsPath = path.join(testDir, "preferences.json");
33
+ await fs.writeFile(prefsPath, "invalid json");
34
+ const prefs = await configManager.loadPreferences();
35
+ expect(prefs).toEqual({});
36
+ });
37
+ });
38
+ describe("savePreferences", () => {
39
+ it("saves preferences to file", async () => {
40
+ await configManager.savePreferences({ lastMode: "api" });
41
+ const prefsPath = path.join(testDir, "preferences.json");
42
+ const content = await fs.readJson(prefsPath);
43
+ expect(content).toEqual({ lastMode: "api" });
44
+ });
45
+ it("creates directory if it does not exist", async () => {
46
+ const nestedDir = path.join(testDir, "nested", "dir");
47
+ const prefsPath = path.join(nestedDir, "preferences.json");
48
+ const nestedManager = new ConfigManager(prefsPath);
49
+ await nestedManager.savePreferences({ lastMode: "ui" });
50
+ const content = await fs.readJson(prefsPath);
51
+ expect(content).toEqual({ lastMode: "ui" });
52
+ });
53
+ });
54
+ describe("getLastMode", () => {
55
+ it("returns null when no mode saved", async () => {
56
+ const mode = await configManager.getLastMode();
57
+ expect(mode).toBeNull();
58
+ });
59
+ it("returns saved mode", async () => {
60
+ const prefsPath = path.join(testDir, "preferences.json");
61
+ await fs.writeJson(prefsPath, { lastMode: "code" });
62
+ const mode = await configManager.getLastMode();
63
+ expect(mode).toBe("code");
64
+ });
65
+ });
66
+ describe("setLastMode", () => {
67
+ it("saves mode to preferences", async () => {
68
+ await configManager.setLastMode("api");
69
+ const mode = await configManager.getLastMode();
70
+ expect(mode).toBe("api");
71
+ });
72
+ it("preserves other preferences when setting mode", async () => {
73
+ const prefsPath = path.join(testDir, "preferences.json");
74
+ await fs.writeJson(prefsPath, { lastMode: "ui", otherPref: "value" });
75
+ await configManager.setLastMode("code");
76
+ const content = await fs.readJson(prefsPath);
77
+ expect(content.lastMode).toBe("code");
78
+ });
79
+ });
80
+ });
81
+ //# sourceMappingURL=config-manager.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-manager.test.js","sourceRoot":"","sources":["../../../../src/lib/__tests__/config-manager.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAC,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAC,aAAa,EAAC,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAI,OAAe,CAAC;IACpB,IAAI,aAA4B,CAAC;IAEjC,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,+CAA+C;QAC/C,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,YAAY,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC3D,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;QACzD,aAAa,GAAG,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,0BAA0B;QAC1B,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,eAAe,EAAE,CAAC;YACpD,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACzD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC,CAAC;YAElD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,eAAe,EAAE,CAAC;YACpD,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACzD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YAE9C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,eAAe,EAAE,CAAC;YACpD,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,aAAa,CAAC,eAAe,CAAC,EAAC,QAAQ,EAAE,KAAK,EAAC,CAAC,CAAC;YAEvD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACzD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAC,QAAQ,EAAE,KAAK,EAAC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACtD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;YAEnD,MAAM,aAAa,CAAC,eAAe,CAAC,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAC;YAEtD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;YAClC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACzD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC,CAAC;YAElD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAEvC,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACzD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAC,CAAC,CAAC;YAEpE,MAAM,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAExC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { ConfigManager } from "../config.js";
3
+ import fs from "fs-extra";
4
+ import path from "path";
5
+ import os from "os";
6
+ describe("Mode Persistence Integration", () => {
7
+ let testDir;
8
+ let configManager;
9
+ beforeEach(async () => {
10
+ testDir = path.join(os.tmpdir(), `ttt-mode-test-${Date.now()}`);
11
+ await fs.ensureDir(testDir);
12
+ const prefsPath = path.join(testDir, "preferences.json");
13
+ configManager = new ConfigManager(prefsPath);
14
+ });
15
+ afterEach(async () => {
16
+ await fs.remove(testDir);
17
+ });
18
+ describe("mode persistence flow", () => {
19
+ it("persists mode across sessions", async () => {
20
+ // Simulate first session - user switches to code mode
21
+ await configManager.setLastMode("code");
22
+ // Simulate second session - create new manager instance
23
+ const prefsPath = path.join(testDir, "preferences.json");
24
+ const newManager = new ConfigManager(prefsPath);
25
+ const savedMode = await newManager.getLastMode();
26
+ expect(savedMode).toBe("code");
27
+ });
28
+ it("handles mode changes in sequence", async () => {
29
+ const modes = ["ui", "api", "code", "ui"];
30
+ for (const mode of modes) {
31
+ await configManager.setLastMode(mode);
32
+ const saved = await configManager.getLastMode();
33
+ expect(saved).toBe(mode);
34
+ }
35
+ });
36
+ it("returns null for fresh installation", async () => {
37
+ const freshDir = path.join(os.tmpdir(), `ttt-fresh-${Date.now()}`);
38
+ const freshPrefsPath = path.join(freshDir, "preferences.json");
39
+ const freshManager = new ConfigManager(freshPrefsPath);
40
+ const mode = await freshManager.getLastMode();
41
+ expect(mode).toBeNull();
42
+ // Cleanup
43
+ await fs.remove(freshDir);
44
+ });
45
+ it("handles sequential saves correctly", async () => {
46
+ // Simulate sequential mode changes
47
+ await configManager.setLastMode("ui");
48
+ await configManager.setLastMode("api");
49
+ await configManager.setLastMode("code");
50
+ // Last write should be persisted
51
+ const saved = await configManager.getLastMode();
52
+ expect(saved).toBe("code");
53
+ });
54
+ });
55
+ describe("preferences file format", () => {
56
+ it("stores preferences as readable JSON", async () => {
57
+ await configManager.setLastMode("api");
58
+ const prefsPath = path.join(testDir, "preferences.json");
59
+ const content = await fs.readFile(prefsPath, "utf-8");
60
+ const parsed = JSON.parse(content);
61
+ expect(parsed).toEqual({ lastMode: "api" });
62
+ // Check it's formatted (has newlines)
63
+ expect(content).toContain("\n");
64
+ });
65
+ it("sets secure file permissions", async () => {
66
+ await configManager.setLastMode("ui");
67
+ const prefsPath = path.join(testDir, "preferences.json");
68
+ const stats = await fs.stat(prefsPath);
69
+ const mode = stats.mode & 0o777;
70
+ // Should be 0o600 (owner read/write only)
71
+ expect(mode).toBe(0o600);
72
+ });
73
+ });
74
+ });
75
+ //# sourceMappingURL=mode-persistence-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode-persistence-integration.test.js","sourceRoot":"","sources":["../../../../src/lib/__tests__/mode-persistence-integration.test.ts"],"names":[],"mappings":"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"}