@codemcp/workflows 5.0.0 → 5.1.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 (77) hide show
  1. package/SKILL.md +23 -0
  2. package/package.json +6 -2
  3. package/.prettierignore +0 -2
  4. package/.turbo/turbo-build.log +0 -4
  5. package/.vibe/conversation-state.sqlite +0 -0
  6. package/src/components/beads/beads-instruction-generator.ts +0 -230
  7. package/src/components/beads/beads-plan-manager.ts +0 -333
  8. package/src/components/beads/beads-task-backend-client.ts +0 -229
  9. package/src/index.ts +0 -93
  10. package/src/notification-service.ts +0 -23
  11. package/src/plugin-system/beads-plugin.ts +0 -649
  12. package/src/plugin-system/commit-plugin.ts +0 -252
  13. package/src/plugin-system/index.ts +0 -20
  14. package/src/plugin-system/plugin-interfaces.ts +0 -153
  15. package/src/plugin-system/plugin-registry.ts +0 -190
  16. package/src/resource-handlers/conversation-state.ts +0 -55
  17. package/src/resource-handlers/development-plan.ts +0 -48
  18. package/src/resource-handlers/index.ts +0 -73
  19. package/src/resource-handlers/system-prompt.ts +0 -55
  20. package/src/resource-handlers/workflow-resource.ts +0 -132
  21. package/src/response-renderer.ts +0 -116
  22. package/src/server-config.ts +0 -760
  23. package/src/server-helpers.ts +0 -245
  24. package/src/server-implementation.ts +0 -277
  25. package/src/server.ts +0 -9
  26. package/src/tool-handlers/base-tool-handler.ts +0 -151
  27. package/src/tool-handlers/conduct-review.ts +0 -190
  28. package/src/tool-handlers/get-tool-info.ts +0 -273
  29. package/src/tool-handlers/index.ts +0 -115
  30. package/src/tool-handlers/list-workflows.ts +0 -78
  31. package/src/tool-handlers/no-idea.ts +0 -47
  32. package/src/tool-handlers/proceed-to-phase.ts +0 -296
  33. package/src/tool-handlers/reset-development.ts +0 -90
  34. package/src/tool-handlers/resume-workflow.ts +0 -378
  35. package/src/tool-handlers/setup-project-docs.ts +0 -232
  36. package/src/tool-handlers/start-development.ts +0 -746
  37. package/src/tool-handlers/whats-next.ts +0 -246
  38. package/src/types.ts +0 -135
  39. package/src/version-info.ts +0 -213
  40. package/test/e2e/beads-plugin-integration.test.ts +0 -1623
  41. package/test/e2e/commit-plugin-integration.test.ts +0 -222
  42. package/test/e2e/core-functionality.test.ts +0 -167
  43. package/test/e2e/git-branch-detection.test.ts +0 -351
  44. package/test/e2e/mcp-contract.test.ts +0 -509
  45. package/test/e2e/plan-management.test.ts +0 -334
  46. package/test/e2e/plugin-system-integration.test.ts +0 -1410
  47. package/test/e2e/state-management.test.ts +0 -387
  48. package/test/e2e/workflow-integration.test.ts +0 -498
  49. package/test/unit/beads-instruction-generator.test.ts +0 -979
  50. package/test/unit/beads-phase-task-id-integration.test.ts +0 -535
  51. package/test/unit/beads-plugin-behavioral.test.ts +0 -545
  52. package/test/unit/beads-plugin.test.ts +0 -117
  53. package/test/unit/commit-plugin.test.ts +0 -196
  54. package/test/unit/conduct-review.test.ts +0 -151
  55. package/test/unit/conversation-not-found-error.test.ts +0 -120
  56. package/test/unit/plugin-error-handling.test.ts +0 -240
  57. package/test/unit/proceed-to-phase-plugin-integration.test.ts +0 -150
  58. package/test/unit/reset-functionality.test.ts +0 -72
  59. package/test/unit/resume-workflow.test.ts +0 -193
  60. package/test/unit/server-config-plugin-registry.test.ts +0 -99
  61. package/test/unit/server-tools.test.ts +0 -310
  62. package/test/unit/setup-project-docs-handler.test.ts +0 -268
  63. package/test/unit/start-development-artifact-detection.test.ts +0 -387
  64. package/test/unit/start-development-gitignore.test.ts +0 -178
  65. package/test/unit/start-development-goal-extraction.test.ts +0 -226
  66. package/test/unit/system-prompt-resource.test.ts +0 -102
  67. package/test/unit/tool-handlers/no-idea.test.ts +0 -40
  68. package/test/utils/e2e-test-setup.ts +0 -451
  69. package/test/utils/run-server-in-dir.sh +0 -27
  70. package/test/utils/temp-files.ts +0 -320
  71. package/test/utils/test-access.ts +0 -79
  72. package/test/utils/test-helpers.ts +0 -288
  73. package/test/utils/test-setup.ts +0 -77
  74. package/tsconfig.build.json +0 -10
  75. package/tsconfig.build.tsbuildinfo +0 -1
  76. package/tsconfig.json +0 -12
  77. package/vitest.config.ts +0 -19
@@ -1,387 +0,0 @@
1
- /**
2
- * Unit tests for StartDevelopmentHandler dynamic artifact detection
3
- *
4
- * Tests the enhanced start_development functionality that dynamically analyzes workflows
5
- * to detect which document variables are referenced and validates only those documents
6
- */
7
-
8
- import { describe, it, expect, beforeEach, vi } from 'vitest';
9
- import { TestAccess } from '../utils/test-access.js';
10
- import { StartDevelopmentHandler } from '../../src/tool-handlers/start-development.js';
11
- import type { YamlStateMachine } from './../../src/state-machine-types';
12
- import { join } from 'node:path';
13
- import {
14
- MockContextFactory,
15
- TEST_WORKFLOWS,
16
- TestAssertions,
17
- } from '../utils/test-helpers.js';
18
-
19
- // Mock ProjectDocsManager
20
- vi.mock('../../src/project-docs-manager.js');
21
-
22
- // Mock other dependencies
23
- vi.mock('../../src/git-manager.js', () => ({
24
- GitManager: {
25
- isGitRepository: vi.fn().mockReturnValue(true),
26
- getCurrentCommitHash: vi.fn().mockReturnValue('abc123'),
27
- },
28
- }));
29
-
30
- describe('StartDevelopmentHandler - Dynamic Artifact Detection', () => {
31
- let handler: StartDevelopmentHandler;
32
- let mockProjectDocsManager: ReturnType<
33
- typeof MockContextFactory.createProjectDocsManagerMock
34
- >;
35
- let testProjectPath: string;
36
- let mockContext: ReturnType<typeof MockContextFactory.createBasicContext>;
37
-
38
- beforeEach(() => {
39
- testProjectPath = '/test/project';
40
-
41
- // Create mock project docs manager
42
- mockProjectDocsManager =
43
- MockContextFactory.createProjectDocsManagerMock(testProjectPath);
44
-
45
- // Create handler and inject mock
46
- handler = new StartDevelopmentHandler();
47
- TestAccess.injectMock(
48
- handler,
49
- 'projectDocsManager',
50
- mockProjectDocsManager
51
- );
52
-
53
- // Create basic mock context
54
- mockContext = MockContextFactory.createBasicContext(testProjectPath);
55
-
56
- // Mock file system operations
57
- vi.mock('fs', () => ({
58
- readFileSync: vi.fn().mockReturnValue('main'),
59
- writeFileSync: vi.fn(),
60
- existsSync: vi.fn().mockReturnValue(false),
61
- }));
62
- });
63
-
64
- describe('dynamic workflow analysis', () => {
65
- it('should proceed normally when workflow contains no document variables', async () => {
66
- mockContext.workflowManager.loadWorkflowForProject.mockReturnValue(
67
- TEST_WORKFLOWS.simple
68
- );
69
-
70
- const result = await handler.executeHandler(
71
- { workflow: 'simple-workflow' },
72
- mockContext
73
- );
74
-
75
- expect(mockProjectDocsManager.getProjectDocsInfo).not.toHaveBeenCalled();
76
- TestAssertions.expectNormalPhase(result, 'requirements');
77
- });
78
-
79
- it('should detect and validate only referenced document variables', async () => {
80
- mockContext.workflowManager.loadWorkflowForProject.mockReturnValue(
81
- TEST_WORKFLOWS.requiredArchDoc
82
- );
83
-
84
- // Update mock context to match the workflow's initial state
85
- mockContext.conversationManager.createConversationContext = vi
86
- .fn()
87
- .mockResolvedValue({
88
- conversationId: 'test-conversation',
89
- currentPhase: 'design',
90
- planFilePath: join(testProjectPath, '.vibe', 'development-plan.md'),
91
- });
92
-
93
- mockProjectDocsManager.getProjectDocsInfo.mockResolvedValue({
94
- architecture: {
95
- exists: false,
96
- path: join(testProjectPath, '.vibe', 'docs', 'architecture.md'),
97
- },
98
- requirements: {
99
- exists: true,
100
- path: join(testProjectPath, '.vibe', 'docs', 'requirements.md'),
101
- },
102
- design: {
103
- exists: true,
104
- path: join(testProjectPath, '.vibe', 'docs', 'design.md'),
105
- },
106
- });
107
-
108
- const result = await handler.executeHandler(
109
- { workflow: 'arch-focused' },
110
- mockContext
111
- );
112
-
113
- TestAssertions.expectArtifactSetupPhase(result);
114
- expect(result.instructions).toContain(
115
- '**Referenced Variables:** `$ARCHITECTURE_DOC`'
116
- );
117
- expect(result.instructions).toContain('architecture.md');
118
- expect(result.instructions).toContain('✅ requirements.md');
119
- expect(result.instructions).toContain('✅ design.md');
120
- });
121
-
122
- it('should detect multiple document variables in workflow', async () => {
123
- mockContext.workflowManager.loadWorkflowForProject.mockReturnValue(
124
- TEST_WORKFLOWS.requiredMultipleDocs
125
- );
126
-
127
- // Update mock context to match the workflow's initial state
128
- mockContext.conversationManager.createConversationContext = vi
129
- .fn()
130
- .mockResolvedValue({
131
- conversationId: 'test-conversation',
132
- currentPhase: 'implementation',
133
- planFilePath: join(testProjectPath, '.vibe', 'development-plan.md'),
134
- });
135
-
136
- mockProjectDocsManager.getProjectDocsInfo.mockResolvedValue({
137
- architecture: {
138
- exists: false,
139
- path: join(testProjectPath, '.vibe', 'docs', 'architecture.md'),
140
- },
141
- requirements: {
142
- exists: false,
143
- path: join(testProjectPath, '.vibe', 'docs', 'requirements.md'),
144
- },
145
- design: {
146
- exists: false,
147
- path: join(testProjectPath, '.vibe', 'docs', 'design.md'),
148
- },
149
- });
150
-
151
- const result = await handler.executeHandler(
152
- { workflow: 'multi-doc' },
153
- mockContext
154
- );
155
-
156
- TestAssertions.expectArtifactSetupPhase(result);
157
- expect(result.instructions).toContain(
158
- '**Referenced Variables:** `$ARCHITECTURE_DOC`, `$REQUIREMENTS_DOC`, `$DESIGN_DOC`'
159
- );
160
- expect(result.instructions).toContain('architecture.md');
161
- expect(result.instructions).toContain('requirements.md');
162
- expect(result.instructions).toContain('design.md');
163
- });
164
-
165
- it('should proceed normally when all referenced documents exist', async () => {
166
- mockContext.workflowManager.loadWorkflowForProject.mockReturnValue(
167
- TEST_WORKFLOWS.requiredMultipleDocs
168
- );
169
-
170
- // Mock conversation context to match initial state
171
- mockContext.conversationManager.createConversationContext.mockResolvedValue(
172
- {
173
- conversationId: 'test-conversation',
174
- currentPhase: 'implementation',
175
- projectPath: testProjectPath,
176
- planFilePath: join(testProjectPath, '.vibe', 'plan.md'),
177
- gitBranch: 'feature-branch',
178
- }
179
- );
180
-
181
- // Mock transition engine to return the correct phase
182
- mockContext.transitionEngine.handleExplicitTransition.mockResolvedValue({
183
- newPhase: 'implementation',
184
- });
185
-
186
- mockProjectDocsManager.getProjectDocsInfo.mockResolvedValue({
187
- architecture: {
188
- exists: true,
189
- path: join(testProjectPath, '.vibe', 'docs', 'architecture.md'),
190
- },
191
- requirements: {
192
- exists: true,
193
- path: join(testProjectPath, '.vibe', 'docs', 'requirements.md'),
194
- },
195
- design: {
196
- exists: true,
197
- path: join(testProjectPath, '.vibe', 'docs', 'design.md'),
198
- },
199
- });
200
-
201
- const result = await handler.executeHandler(
202
- { workflow: 'complete-docs' },
203
- mockContext
204
- );
205
-
206
- expect(mockProjectDocsManager.getProjectDocsInfo).toHaveBeenCalledWith(
207
- testProjectPath
208
- );
209
- TestAssertions.expectNormalPhase(result, 'implementation');
210
- });
211
-
212
- it('should handle partial document availability correctly', async () => {
213
- // Mock workflow that references REQUIREMENTS_DOC and DESIGN_DOC
214
- const partialWorkflow = {
215
- name: 'req-design-focused',
216
- description: 'Workflow focusing on requirements and design docs',
217
- initial_state: 'development',
218
- metadata: {
219
- requiresDocumentation: true,
220
- },
221
- states: {
222
- development: {
223
- default_instructions:
224
- 'Implement features based on $REQUIREMENTS_DOC and follow $DESIGN_DOC patterns.',
225
- },
226
- },
227
- } as Partial<YamlStateMachine>;
228
-
229
- mockContext.workflowManager.loadWorkflowForProject.mockReturnValue(
230
- partialWorkflow
231
- );
232
-
233
- // Update mock context to match the workflow's initial state
234
- mockContext.conversationManager.createConversationContext = vi
235
- .fn()
236
- .mockResolvedValue({
237
- conversationId: 'test-conversation',
238
- currentPhase: 'development',
239
- planFilePath: join(testProjectPath, '.vibe', 'development-plan.md'),
240
- });
241
-
242
- mockProjectDocsManager.getProjectDocsInfo.mockResolvedValue({
243
- architecture: {
244
- exists: true,
245
- path: join(testProjectPath, '.vibe', 'docs', 'architecture.md'),
246
- },
247
- requirements: {
248
- exists: true,
249
- path: join(testProjectPath, '.vibe', 'docs', 'requirements.md'),
250
- },
251
- design: {
252
- exists: false,
253
- path: join(testProjectPath, '.vibe', 'docs', 'design.md'),
254
- },
255
- });
256
-
257
- const result = await handler.executeHandler(
258
- { workflow: 'req-design-focused' },
259
- mockContext
260
- );
261
-
262
- TestAssertions.expectArtifactSetupPhase(result);
263
- expect(result.instructions).toContain(
264
- '**Referenced Variables:** `$REQUIREMENTS_DOC`, `$DESIGN_DOC`'
265
- );
266
- expect(result.instructions).toContain('design.md'); // Only missing doc
267
- expect(result.instructions).toContain('✅ architecture.md'); // Existing doc
268
- expect(result.instructions).toContain('✅ requirements.md'); // Existing doc
269
- });
270
-
271
- it('should handle workflow loading errors gracefully', async () => {
272
- // Mock workflow loading failure - this should happen during artifact check, not during normal workflow loading
273
- let callCount = 0;
274
- mockContext.workflowManager.loadWorkflowForProject.mockImplementation(
275
- () => {
276
- callCount++;
277
- if (callCount === 1) {
278
- // First call during artifact check - throw error
279
- throw new Error('Workflow not found');
280
- } else {
281
- // Second call during normal flow - return valid workflow
282
- return TEST_WORKFLOWS.simple;
283
- }
284
- }
285
- );
286
-
287
- const result = await handler.executeHandler(
288
- { workflow: 'invalid-workflow' },
289
- mockContext
290
- );
291
-
292
- // Should proceed without artifact check when workflow analysis fails
293
- TestAssertions.expectNormalPhase(result, 'requirements');
294
- });
295
-
296
- it('should include detected variables in setup guidance', async () => {
297
- mockContext.workflowManager.loadWorkflowForProject.mockReturnValue(
298
- TEST_WORKFLOWS.requiredArchDoc
299
- );
300
-
301
- // Update mock context to match the workflow's initial state
302
- mockContext.conversationManager.createConversationContext = vi
303
- .fn()
304
- .mockResolvedValue({
305
- conversationId: 'test-conversation',
306
- currentPhase: 'design',
307
- planFilePath: join(testProjectPath, '.vibe', 'development-plan.md'),
308
- });
309
-
310
- mockProjectDocsManager.getProjectDocsInfo.mockResolvedValue({
311
- architecture: {
312
- exists: false,
313
- path: join(testProjectPath, '.vibe', 'docs', 'architecture.md'),
314
- },
315
- requirements: {
316
- exists: true,
317
- path: join(testProjectPath, '.vibe', 'docs', 'requirements.md'),
318
- },
319
- design: {
320
- exists: true,
321
- path: join(testProjectPath, '.vibe', 'docs', 'design.md'),
322
- },
323
- });
324
-
325
- const result = await handler.executeHandler(
326
- { workflow: 'arch-only' },
327
- mockContext
328
- );
329
-
330
- expect(result.instructions).toContain(
331
- '**Referenced Variables:** `$ARCHITECTURE_DOC`'
332
- );
333
- expect(result.instructions).toContain(
334
- 'detected variables: `$ARCHITECTURE_DOC`'
335
- );
336
- });
337
-
338
- it('should proceed normally for optional workflows with missing documents', async () => {
339
- // Use a workflow that has document variables but NO requiresDocumentation flag
340
- mockContext.workflowManager.loadWorkflowForProject.mockReturnValue(
341
- TEST_WORKFLOWS.withArchDoc
342
- );
343
-
344
- // Mock conversation context to match initial state
345
- mockContext.conversationManager.createConversationContext.mockResolvedValue(
346
- {
347
- conversationId: 'test-conversation',
348
- currentPhase: 'design',
349
- projectPath: testProjectPath,
350
- planFilePath: join(testProjectPath, '.vibe', 'plan.md'),
351
- gitBranch: 'feature-branch',
352
- }
353
- );
354
-
355
- // Mock transition engine to return the correct phase
356
- mockContext.transitionEngine.handleExplicitTransition.mockResolvedValue({
357
- newPhase: 'design',
358
- });
359
-
360
- // Mock all documents as missing
361
- mockProjectDocsManager.getProjectDocsInfo.mockResolvedValue({
362
- architecture: {
363
- exists: false,
364
- path: join(testProjectPath, '.vibe', 'docs', 'architecture.md'),
365
- },
366
- requirements: {
367
- exists: false,
368
- path: join(testProjectPath, '.vibe', 'docs', 'requirements.md'),
369
- },
370
- design: {
371
- exists: false,
372
- path: join(testProjectPath, '.vibe', 'docs', 'design.md'),
373
- },
374
- });
375
-
376
- const result = await handler.executeHandler(
377
- { workflow: 'optional-arch-workflow' },
378
- mockContext
379
- );
380
-
381
- // Should proceed to normal phase instead of artifact-setup
382
- // because requiresDocumentation is not set (defaults to false)
383
- TestAssertions.expectNormalPhase(result, 'design');
384
- expect(result.instructions).not.toContain('Referenced Variables');
385
- });
386
- });
387
- });
@@ -1,178 +0,0 @@
1
- /**
2
- * Unit tests for StartDevelopment .gitignore management
3
- *
4
- * Tests the automatic .vibe/.gitignore creation functionality
5
- */
6
-
7
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
8
- import {
9
- existsSync,
10
- readFileSync,
11
- writeFileSync,
12
- mkdirSync,
13
- rmSync,
14
- } from 'node:fs';
15
- import { resolve } from 'node:path';
16
- import { TestAccess } from '../utils/test-access.js';
17
- import { tmpdir } from 'node:os';
18
- import { StartDevelopmentHandler } from '../../src/tool-handlers/start-development.js';
19
-
20
- describe('StartDevelopment .gitignore management', () => {
21
- let tempDir: string;
22
- let handler: StartDevelopmentHandler;
23
- let mockLogger: {
24
- debug: ReturnType<typeof vi.fn>;
25
- info: ReturnType<typeof vi.fn>;
26
- warn: ReturnType<typeof vi.fn>;
27
- error: ReturnType<typeof vi.fn>;
28
- };
29
-
30
- beforeEach(() => {
31
- // Create temporary directory for testing
32
- tempDir = resolve(tmpdir(), `vibe-test-${Date.now()}`);
33
- mkdirSync(tempDir, { recursive: true });
34
-
35
- // Mock logger
36
- mockLogger = {
37
- debug: vi.fn(),
38
- info: vi.fn(),
39
- warn: vi.fn(),
40
- error: vi.fn(),
41
- };
42
-
43
- // Create handler instance with mocked logger
44
- handler = new StartDevelopmentHandler();
45
- (handler as unknown as { logger: unknown }).logger = mockLogger;
46
- });
47
-
48
- afterEach(() => {
49
- // Clean up temporary directory
50
- if (existsSync(tempDir)) {
51
- rmSync(tempDir, { recursive: true, force: true });
52
- }
53
- });
54
-
55
- describe('ensureGitignoreEntry', () => {
56
- it('should skip non-git repositories', () => {
57
- // Call the private method cleanly
58
- TestAccess.callMethod(handler, 'ensureGitignoreEntry', tempDir);
59
-
60
- expect(mockLogger.debug).toHaveBeenCalledWith(
61
- 'Not a git repository, skipping .gitignore management',
62
- { projectPath: tempDir }
63
- );
64
- });
65
-
66
- it('should create .vibe/.gitignore when none exists in git repo', () => {
67
- // Create .git directory to simulate git repo
68
- mkdirSync(resolve(tempDir, '.git'));
69
-
70
- // Call the method
71
- TestAccess.callMethod(handler, 'ensureGitignoreEntry', tempDir);
72
-
73
- // Check that .vibe/.gitignore was created with correct content
74
- const vibeGitignorePath = resolve(tempDir, '.vibe', '.gitignore');
75
- expect(existsSync(vibeGitignorePath)).toBe(true);
76
-
77
- const content = readFileSync(vibeGitignorePath, 'utf-8');
78
- expect(content).toContain('conversations/');
79
- expect(content).toContain('*.sqlite');
80
-
81
- expect(mockLogger.info).toHaveBeenCalledWith(
82
- 'Created .vibe/.gitignore to exclude conversation files',
83
- { projectPath: tempDir, gitignorePath: vibeGitignorePath }
84
- );
85
- });
86
-
87
- it('should create .vibe directory if it does not exist', () => {
88
- // Create .git directory to simulate git repo
89
- mkdirSync(resolve(tempDir, '.git'));
90
-
91
- // Ensure .vibe directory doesn't exist
92
- const vibeDir = resolve(tempDir, '.vibe');
93
- expect(existsSync(vibeDir)).toBe(false);
94
-
95
- // Call the method
96
- TestAccess.callMethod(handler, 'ensureGitignoreEntry', tempDir);
97
-
98
- // Check that .vibe directory was created
99
- expect(existsSync(vibeDir)).toBe(true);
100
-
101
- // Check that .vibe/.gitignore was created
102
- const vibeGitignorePath = resolve(vibeDir, '.gitignore');
103
- expect(existsSync(vibeGitignorePath)).toBe(true);
104
- });
105
-
106
- it('should skip when .vibe/.gitignore already exists with conversation exclusions', () => {
107
- // Create .git directory
108
- mkdirSync(resolve(tempDir, '.git'));
109
-
110
- // Create .vibe directory and .gitignore with existing conversation exclusions
111
- const vibeDir = resolve(tempDir, '.vibe');
112
- mkdirSync(vibeDir, { recursive: true });
113
- const vibeGitignorePath = resolve(vibeDir, '.gitignore');
114
- const existingContent = 'conversations/\n*.sqlite\n';
115
- writeFileSync(vibeGitignorePath, existingContent);
116
-
117
- // Call the method
118
- TestAccess.callMethod(handler, 'ensureGitignoreEntry', tempDir);
119
-
120
- // Check that content wasn't changed
121
- const content = readFileSync(vibeGitignorePath, 'utf-8');
122
- expect(content).toBe(existingContent);
123
-
124
- expect(mockLogger.debug).toHaveBeenCalledWith(
125
- '.vibe/.gitignore already exists with conversation exclusions',
126
- { gitignorePath: vibeGitignorePath }
127
- );
128
- });
129
-
130
- it('should recreate .vibe/.gitignore if existing one is incomplete', () => {
131
- // Create .git directory
132
- mkdirSync(resolve(tempDir, '.git'));
133
-
134
- // Create .vibe directory and incomplete .gitignore
135
- const vibeDir = resolve(tempDir, '.vibe');
136
- mkdirSync(vibeDir, { recursive: true });
137
- const vibeGitignorePath = resolve(vibeDir, '.gitignore');
138
- const incompleteContent = 'some-other-file\n';
139
- writeFileSync(vibeGitignorePath, incompleteContent);
140
-
141
- // Call the method
142
- TestAccess.callMethod(handler, 'ensureGitignoreEntry', tempDir);
143
-
144
- // Check that content was updated to include conversation exclusions
145
- const content = readFileSync(vibeGitignorePath, 'utf-8');
146
- expect(content).toContain('conversations/');
147
- expect(content).toContain('*.sqlite');
148
-
149
- expect(mockLogger.info).toHaveBeenCalledWith(
150
- 'Created .vibe/.gitignore to exclude conversation files',
151
- { projectPath: tempDir, gitignorePath: vibeGitignorePath }
152
- );
153
- });
154
-
155
- it('should not affect parent directory .gitignore', () => {
156
- // Create .git directory
157
- mkdirSync(resolve(tempDir, '.git'));
158
-
159
- // Create parent .gitignore with existing content
160
- const parentGitignorePath = resolve(tempDir, '.gitignore');
161
- const parentContent = 'node_modules/\n*.log\n';
162
- writeFileSync(parentGitignorePath, parentContent);
163
-
164
- // Call the method
165
- TestAccess.callMethod(handler, 'ensureGitignoreEntry', tempDir);
166
-
167
- // Check that parent .gitignore was not modified
168
- const parentContentAfter = readFileSync(parentGitignorePath, 'utf-8');
169
- expect(parentContentAfter).toBe(parentContent);
170
-
171
- // Check that .vibe/.gitignore was created
172
- const vibeGitignorePath = resolve(tempDir, '.vibe', '.gitignore');
173
- expect(existsSync(vibeGitignorePath)).toBe(true);
174
- const vibeContent = readFileSync(vibeGitignorePath, 'utf-8');
175
- expect(vibeContent).toContain('*.sqlite');
176
- });
177
- });
178
- });