@codemcp/workflows 3.1.21
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.
- package/.turbo/turbo-build.log +4 -0
- package/.vibe/conversation-state.sqlite +0 -0
- package/LICENSE +674 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/notification-service.d.ts +14 -0
- package/dist/notification-service.d.ts.map +1 -0
- package/dist/notification-service.js +18 -0
- package/dist/notification-service.js.map +1 -0
- package/dist/resource-handlers/conversation-state.d.ts +15 -0
- package/dist/resource-handlers/conversation-state.d.ts.map +1 -0
- package/dist/resource-handlers/conversation-state.js +40 -0
- package/dist/resource-handlers/conversation-state.js.map +1 -0
- package/dist/resource-handlers/development-plan.d.ts +14 -0
- package/dist/resource-handlers/development-plan.d.ts.map +1 -0
- package/dist/resource-handlers/development-plan.js +31 -0
- package/dist/resource-handlers/development-plan.js.map +1 -0
- package/dist/resource-handlers/index.d.ts +24 -0
- package/dist/resource-handlers/index.d.ts.map +1 -0
- package/dist/resource-handlers/index.js +62 -0
- package/dist/resource-handlers/index.js.map +1 -0
- package/dist/resource-handlers/system-prompt.d.ts +15 -0
- package/dist/resource-handlers/system-prompt.d.ts.map +1 -0
- package/dist/resource-handlers/system-prompt.js +40 -0
- package/dist/resource-handlers/system-prompt.js.map +1 -0
- package/dist/resource-handlers/workflow-resource.d.ts +15 -0
- package/dist/resource-handlers/workflow-resource.d.ts.map +1 -0
- package/dist/resource-handlers/workflow-resource.js +85 -0
- package/dist/resource-handlers/workflow-resource.js.map +1 -0
- package/dist/response-renderer.d.ts +30 -0
- package/dist/response-renderer.d.ts.map +1 -0
- package/dist/response-renderer.js +94 -0
- package/dist/response-renderer.js.map +1 -0
- package/dist/server-config.d.ts +34 -0
- package/dist/server-config.d.ts.map +1 -0
- package/dist/server-config.js +486 -0
- package/dist/server-config.js.map +1 -0
- package/dist/server-helpers.d.ts +62 -0
- package/dist/server-helpers.d.ts.map +1 -0
- package/dist/server-helpers.js +156 -0
- package/dist/server-helpers.js.map +1 -0
- package/dist/server-implementation.d.ts +74 -0
- package/dist/server-implementation.d.ts.map +1 -0
- package/dist/server-implementation.js +201 -0
- package/dist/server-implementation.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +5 -0
- package/dist/server.js.map +1 -0
- package/dist/tool-handlers/base-tool-handler.d.ts +50 -0
- package/dist/tool-handlers/base-tool-handler.d.ts.map +1 -0
- package/dist/tool-handlers/base-tool-handler.js +74 -0
- package/dist/tool-handlers/base-tool-handler.js.map +1 -0
- package/dist/tool-handlers/conduct-review.d.ts +49 -0
- package/dist/tool-handlers/conduct-review.d.ts.map +1 -0
- package/dist/tool-handlers/conduct-review.js +105 -0
- package/dist/tool-handlers/conduct-review.js.map +1 -0
- package/dist/tool-handlers/get-tool-info.d.ts +76 -0
- package/dist/tool-handlers/get-tool-info.d.ts.map +1 -0
- package/dist/tool-handlers/get-tool-info.js +168 -0
- package/dist/tool-handlers/get-tool-info.js.map +1 -0
- package/dist/tool-handlers/index.d.ts +42 -0
- package/dist/tool-handlers/index.d.ts.map +1 -0
- package/dist/tool-handlers/index.js +74 -0
- package/dist/tool-handlers/index.js.map +1 -0
- package/dist/tool-handlers/install-workflow.d.ts +48 -0
- package/dist/tool-handlers/install-workflow.d.ts.map +1 -0
- package/dist/tool-handlers/install-workflow.js +131 -0
- package/dist/tool-handlers/install-workflow.js.map +1 -0
- package/dist/tool-handlers/list-workflows.d.ts +47 -0
- package/dist/tool-handlers/list-workflows.d.ts.map +1 -0
- package/dist/tool-handlers/list-workflows.js +58 -0
- package/dist/tool-handlers/list-workflows.js.map +1 -0
- package/dist/tool-handlers/no-idea.d.ts +41 -0
- package/dist/tool-handlers/no-idea.d.ts.map +1 -0
- package/dist/tool-handlers/no-idea.js +29 -0
- package/dist/tool-handlers/no-idea.js.map +1 -0
- package/dist/tool-handlers/proceed-to-phase.d.ts +39 -0
- package/dist/tool-handlers/proceed-to-phase.d.ts.map +1 -0
- package/dist/tool-handlers/proceed-to-phase.js +109 -0
- package/dist/tool-handlers/proceed-to-phase.js.map +1 -0
- package/dist/tool-handlers/reset-development.d.ts +31 -0
- package/dist/tool-handlers/reset-development.d.ts.map +1 -0
- package/dist/tool-handlers/reset-development.js +48 -0
- package/dist/tool-handlers/reset-development.js.map +1 -0
- package/dist/tool-handlers/resume-workflow.d.ts +88 -0
- package/dist/tool-handlers/resume-workflow.d.ts.map +1 -0
- package/dist/tool-handlers/resume-workflow.js +213 -0
- package/dist/tool-handlers/resume-workflow.js.map +1 -0
- package/dist/tool-handlers/setup-project-docs.d.ts +36 -0
- package/dist/tool-handlers/setup-project-docs.d.ts.map +1 -0
- package/dist/tool-handlers/setup-project-docs.js +136 -0
- package/dist/tool-handlers/setup-project-docs.js.map +1 -0
- package/dist/tool-handlers/start-development.d.ts +82 -0
- package/dist/tool-handlers/start-development.d.ts.map +1 -0
- package/dist/tool-handlers/start-development.js +448 -0
- package/dist/tool-handlers/start-development.js.map +1 -0
- package/dist/tool-handlers/whats-next.d.ts +42 -0
- package/dist/tool-handlers/whats-next.d.ts.map +1 -0
- package/dist/tool-handlers/whats-next.js +118 -0
- package/dist/tool-handlers/whats-next.js.map +1 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +29 -0
- package/src/index.ts +93 -0
- package/src/notification-service.ts +23 -0
- package/src/resource-handlers/conversation-state.ts +55 -0
- package/src/resource-handlers/development-plan.ts +48 -0
- package/src/resource-handlers/index.ts +73 -0
- package/src/resource-handlers/system-prompt.ts +55 -0
- package/src/resource-handlers/workflow-resource.ts +126 -0
- package/src/response-renderer.ts +116 -0
- package/src/server-config.ts +744 -0
- package/src/server-helpers.ts +225 -0
- package/src/server-implementation.ts +277 -0
- package/src/server.ts +9 -0
- package/src/tool-handlers/base-tool-handler.ts +141 -0
- package/src/tool-handlers/conduct-review.ts +191 -0
- package/src/tool-handlers/get-tool-info.ts +274 -0
- package/src/tool-handlers/index.ts +117 -0
- package/src/tool-handlers/install-workflow.ts +185 -0
- package/src/tool-handlers/list-workflows.ts +94 -0
- package/src/tool-handlers/no-idea.ts +47 -0
- package/src/tool-handlers/proceed-to-phase.ts +205 -0
- package/src/tool-handlers/reset-development.ts +90 -0
- package/src/tool-handlers/resume-workflow.ts +380 -0
- package/src/tool-handlers/setup-project-docs.ts +226 -0
- package/src/tool-handlers/start-development.ts +685 -0
- package/src/tool-handlers/whats-next.ts +235 -0
- package/src/types.ts +130 -0
- package/test/e2e/core-functionality.test.ts +176 -0
- package/test/e2e/mcp-contract.test.ts +540 -0
- package/test/e2e/plan-management.test.ts +331 -0
- package/test/e2e/state-management.test.ts +392 -0
- package/test/e2e/workflow-integration.test.ts +506 -0
- package/test/unit/commit-behaviour-interface.test.ts +244 -0
- package/test/unit/conduct-review.test.ts +151 -0
- package/test/unit/reset-functionality.test.ts +72 -0
- package/test/unit/resume-workflow.test.ts +192 -0
- package/test/unit/server-tools.test.ts +311 -0
- package/test/unit/setup-project-docs-handler.test.ts +267 -0
- package/test/unit/start-development-artifact-detection.test.ts +387 -0
- package/test/unit/start-development-gitignore.test.ts +178 -0
- package/test/unit/system-prompt-resource.test.ts +101 -0
- package/test/unit/tool-handlers/no-idea.test.ts +40 -0
- package/test/utils/e2e-test-setup.ts +453 -0
- package/test/utils/run-server-in-dir.sh +27 -0
- package/test/utils/temp-files.ts +308 -0
- package/test/utils/test-access.ts +79 -0
- package/test/utils/test-helpers.ts +286 -0
- package/test/utils/test-setup.ts +78 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +12 -0
- package/vitest.config.ts +17 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
TempProject,
|
|
4
|
+
createTempProjectWithDefaultStateMachine,
|
|
5
|
+
} from '../utils/temp-files';
|
|
6
|
+
import {
|
|
7
|
+
DirectServerInterface,
|
|
8
|
+
createSuiteIsolatedE2EScenario,
|
|
9
|
+
assertToolSuccess,
|
|
10
|
+
initializeDevelopment,
|
|
11
|
+
} from '../utils/e2e-test-setup';
|
|
12
|
+
import { promises as fs } from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
|
|
15
|
+
vi.unmock('fs');
|
|
16
|
+
vi.unmock('fs/promises');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* State Management Tests
|
|
20
|
+
*
|
|
21
|
+
* Tests state machine functionality including:
|
|
22
|
+
* - Phase transitions and state machine logic
|
|
23
|
+
* - Custom state machine loading and validation
|
|
24
|
+
* - State persistence and consistency
|
|
25
|
+
* - Conversation state management across sessions
|
|
26
|
+
*/
|
|
27
|
+
describe('State Management', () => {
|
|
28
|
+
let client: DirectServerInterface;
|
|
29
|
+
let tempProject: TempProject;
|
|
30
|
+
let cleanup: () => Promise<void>;
|
|
31
|
+
|
|
32
|
+
beforeEach(async () => {
|
|
33
|
+
const scenario = await createSuiteIsolatedE2EScenario({
|
|
34
|
+
suiteName: 'state-management',
|
|
35
|
+
tempProjectFactory: createTempProjectWithDefaultStateMachine,
|
|
36
|
+
});
|
|
37
|
+
client = scenario.client;
|
|
38
|
+
tempProject = scenario.tempProject;
|
|
39
|
+
cleanup = scenario.cleanup;
|
|
40
|
+
|
|
41
|
+
// Initialize development with default workflow before each test
|
|
42
|
+
await initializeDevelopment(client);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
afterEach(async () => {
|
|
46
|
+
if (cleanup) {
|
|
47
|
+
await cleanup();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('Phase Transitions', () => {
|
|
52
|
+
it('should transition through standard development phases', async () => {
|
|
53
|
+
// Start with requirements
|
|
54
|
+
const start = await client.callTool('whats_next', {
|
|
55
|
+
user_input: 'implement feature',
|
|
56
|
+
});
|
|
57
|
+
expect(assertToolSuccess(start).phase).toBe('requirements');
|
|
58
|
+
|
|
59
|
+
// Transition to design
|
|
60
|
+
const design = await client.callTool('proceed_to_phase', {
|
|
61
|
+
target_phase: 'design',
|
|
62
|
+
reason: 'requirements complete',
|
|
63
|
+
review_state: 'not-required',
|
|
64
|
+
});
|
|
65
|
+
expect(assertToolSuccess(design).phase).toBe('design');
|
|
66
|
+
|
|
67
|
+
// Transition to implementation
|
|
68
|
+
const impl = await client.callTool('proceed_to_phase', {
|
|
69
|
+
target_phase: 'implementation',
|
|
70
|
+
reason: 'design complete',
|
|
71
|
+
review_state: 'not-required',
|
|
72
|
+
});
|
|
73
|
+
expect(assertToolSuccess(impl).phase).toBe('implementation');
|
|
74
|
+
|
|
75
|
+
// Verify state consistency
|
|
76
|
+
const stateResource = await client.readResource('state://current');
|
|
77
|
+
const stateData = JSON.parse(stateResource.contents[0].text);
|
|
78
|
+
expect(stateData.currentPhase).toBe('implementation');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should support non-linear phase transitions', async () => {
|
|
82
|
+
// Start conversation
|
|
83
|
+
await client.callTool('whats_next', { user_input: 'start' });
|
|
84
|
+
|
|
85
|
+
// Jump to testing phase
|
|
86
|
+
const testing = await client.callTool('proceed_to_phase', {
|
|
87
|
+
target_phase: 'testing',
|
|
88
|
+
reason: 'skip to testing',
|
|
89
|
+
review_state: 'not-required',
|
|
90
|
+
});
|
|
91
|
+
expect(assertToolSuccess(testing).phase).toBe('testing');
|
|
92
|
+
|
|
93
|
+
// Go back to design
|
|
94
|
+
const design = await client.callTool('proceed_to_phase', {
|
|
95
|
+
target_phase: 'design',
|
|
96
|
+
reason: 'need to revise design',
|
|
97
|
+
review_state: 'not-required',
|
|
98
|
+
});
|
|
99
|
+
expect(assertToolSuccess(design).phase).toBe('design');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should track phase transition history', async () => {
|
|
103
|
+
await client.callTool('whats_next', { user_input: 'start' });
|
|
104
|
+
await client.callTool('proceed_to_phase', {
|
|
105
|
+
target_phase: 'design',
|
|
106
|
+
reason: 'test',
|
|
107
|
+
review_state: 'not-required',
|
|
108
|
+
});
|
|
109
|
+
await client.callTool('proceed_to_phase', {
|
|
110
|
+
target_phase: 'implementation',
|
|
111
|
+
reason: 'test',
|
|
112
|
+
review_state: 'not-required',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const stateResource = await client.readResource('state://current');
|
|
116
|
+
const stateData = JSON.parse(stateResource.contents[0].text);
|
|
117
|
+
|
|
118
|
+
expect(stateData.currentPhase).toBe('implementation');
|
|
119
|
+
// Verify conversation maintains consistency
|
|
120
|
+
expect(stateData.conversationId).toBeTruthy();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('Custom State Machines', () => {
|
|
125
|
+
beforeEach(async () => {
|
|
126
|
+
// Reset any existing development state
|
|
127
|
+
await cleanup();
|
|
128
|
+
|
|
129
|
+
// Create a fresh test environment without initializing development
|
|
130
|
+
const scenario = await createSuiteIsolatedE2EScenario({
|
|
131
|
+
suiteName: 'state-management-custom',
|
|
132
|
+
tempProjectFactory: createTempProjectWithDefaultStateMachine,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
client = scenario.client;
|
|
136
|
+
tempProject = scenario.tempProject;
|
|
137
|
+
cleanup = scenario.cleanup;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should load custom state machine from .vibe directory', async () => {
|
|
141
|
+
const vibeDir = path.join(tempProject.projectPath, '.vibe');
|
|
142
|
+
await fs.mkdir(vibeDir, { recursive: true });
|
|
143
|
+
|
|
144
|
+
const customStateMachine = `
|
|
145
|
+
name: "custom"
|
|
146
|
+
description: "Custom development workflow for testing"
|
|
147
|
+
initial_state: "planning"
|
|
148
|
+
states:
|
|
149
|
+
planning:
|
|
150
|
+
description: "Planning phase"
|
|
151
|
+
default_instructions: "Start planning the feature. Define what needs to be built and create a plan."
|
|
152
|
+
transitions:
|
|
153
|
+
- trigger: "planning_complete"
|
|
154
|
+
to: "building"
|
|
155
|
+
instructions: "Planning complete, start building"
|
|
156
|
+
transition_reason: "Planning phase finished, moving to building"
|
|
157
|
+
building:
|
|
158
|
+
description: "Building phase"
|
|
159
|
+
default_instructions: "Build the feature according to the plan. Focus on implementation and testing."
|
|
160
|
+
transitions:
|
|
161
|
+
- trigger: "build_finished"
|
|
162
|
+
to: "complete"
|
|
163
|
+
instructions: "Building complete, feature is ready"
|
|
164
|
+
transition_reason: "Building phase finished, feature complete"
|
|
165
|
+
complete:
|
|
166
|
+
description: "Completed"
|
|
167
|
+
default_instructions: "Feature is complete and ready for delivery."
|
|
168
|
+
transitions: []
|
|
169
|
+
`;
|
|
170
|
+
|
|
171
|
+
await fs.writeFile(
|
|
172
|
+
path.join(vibeDir, 'workflow.yaml'),
|
|
173
|
+
customStateMachine
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Initialize development with start_development and specify custom workflow
|
|
177
|
+
const result = await client.callTool('start_development', {
|
|
178
|
+
workflow: 'custom',
|
|
179
|
+
commit_behaviour: 'none',
|
|
180
|
+
});
|
|
181
|
+
const response = assertToolSuccess(result);
|
|
182
|
+
|
|
183
|
+
expect(response.phase).toBe('planning');
|
|
184
|
+
expect(response.instructions).toContain('whats_next()');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should support .yml extension for state machine files', async () => {
|
|
188
|
+
const vibeDir = path.join(tempProject.projectPath, '.vibe');
|
|
189
|
+
await fs.mkdir(vibeDir, { recursive: true });
|
|
190
|
+
|
|
191
|
+
const customStateMachine = `
|
|
192
|
+
name: "custom"
|
|
193
|
+
description: "Test .yml extension"
|
|
194
|
+
initial_state: "start"
|
|
195
|
+
states:
|
|
196
|
+
start:
|
|
197
|
+
description: "Start state"
|
|
198
|
+
default_instructions: "YML state machine loaded"
|
|
199
|
+
transitions: []
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
await fs.writeFile(
|
|
203
|
+
path.join(vibeDir, 'workflow.yml'),
|
|
204
|
+
customStateMachine
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Initialize development with custom workflow
|
|
208
|
+
await client.callTool('start_development', {
|
|
209
|
+
workflow: 'custom',
|
|
210
|
+
commit_behaviour: 'none',
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Then call whats_next
|
|
214
|
+
const result = await client.callTool('whats_next', {
|
|
215
|
+
user_input: 'test yml',
|
|
216
|
+
});
|
|
217
|
+
const response = assertToolSuccess(result);
|
|
218
|
+
|
|
219
|
+
expect(response.phase).toBe('start');
|
|
220
|
+
expect(response.instructions).toContain('YML state machine loaded');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should fall back to default state machine on invalid custom configuration', async () => {
|
|
224
|
+
// Mock logger only for this test to suppress expected error output
|
|
225
|
+
const mockCreateLogger = vi.fn().mockReturnValue({
|
|
226
|
+
debug: vi.fn(),
|
|
227
|
+
info: vi.fn(),
|
|
228
|
+
warn: vi.fn(),
|
|
229
|
+
error: vi.fn(),
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Mock the module
|
|
233
|
+
vi.doMock('@codemcp/workflows-core', async () => {
|
|
234
|
+
const actual = await vi.importActual('@codemcp/workflows-core');
|
|
235
|
+
return {
|
|
236
|
+
...actual,
|
|
237
|
+
createLogger: mockCreateLogger,
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const vibeDir = path.join(tempProject.projectPath, '.vibe');
|
|
242
|
+
await fs.mkdir(vibeDir, { recursive: true });
|
|
243
|
+
|
|
244
|
+
// Create invalid YAML
|
|
245
|
+
await fs.writeFile(
|
|
246
|
+
path.join(vibeDir, 'workflow.yaml'),
|
|
247
|
+
'invalid: yaml: ['
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
// Initialize development with waterfall workflow since custom will fail
|
|
251
|
+
await client.callTool('start_development', {
|
|
252
|
+
workflow: 'waterfall',
|
|
253
|
+
commit_behaviour: 'none',
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const result = await client.callTool('whats_next', {
|
|
257
|
+
user_input: 'test fallback',
|
|
258
|
+
});
|
|
259
|
+
const response = assertToolSuccess(result);
|
|
260
|
+
|
|
261
|
+
// Should fall back to default state machine
|
|
262
|
+
expect(response.phase).toBeTruthy();
|
|
263
|
+
expect(response.instructions).toBeTruthy();
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('should use default state machine when no custom configuration exists', async () => {
|
|
267
|
+
// Initialize development with waterfall workflow
|
|
268
|
+
await client.callTool('start_development', {
|
|
269
|
+
workflow: 'waterfall',
|
|
270
|
+
commit_behaviour: 'none',
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const result = await client.callTool('whats_next', {
|
|
274
|
+
user_input: 'test default',
|
|
275
|
+
});
|
|
276
|
+
const response = assertToolSuccess(result);
|
|
277
|
+
|
|
278
|
+
// Should use default phases
|
|
279
|
+
expect(['idle', 'requirements']).toContain(response.phase);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
describe('State Persistence', () => {
|
|
284
|
+
it('should persist state across tool calls', async () => {
|
|
285
|
+
const first = await client.callTool('whats_next', {
|
|
286
|
+
user_input: 'start project',
|
|
287
|
+
});
|
|
288
|
+
const firstResponse = assertToolSuccess(first);
|
|
289
|
+
|
|
290
|
+
await client.callTool('proceed_to_phase', {
|
|
291
|
+
target_phase: 'design',
|
|
292
|
+
reason: 'move to design',
|
|
293
|
+
review_state: 'not-required',
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const third = await client.callTool('whats_next', {
|
|
297
|
+
user_input: 'continue',
|
|
298
|
+
});
|
|
299
|
+
const thirdResponse = assertToolSuccess(third);
|
|
300
|
+
|
|
301
|
+
expect(firstResponse.conversation_id).toBe(thirdResponse.conversation_id);
|
|
302
|
+
expect(thirdResponse.phase).toBe('design');
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('should maintain conversation state consistency', async () => {
|
|
306
|
+
const result = await client.callTool('whats_next', {
|
|
307
|
+
user_input: 'test consistency',
|
|
308
|
+
});
|
|
309
|
+
const response = assertToolSuccess(result);
|
|
310
|
+
|
|
311
|
+
const stateResource = await client.readResource('state://current');
|
|
312
|
+
const stateData = JSON.parse(stateResource.contents[0].text);
|
|
313
|
+
|
|
314
|
+
expect(stateData.conversationId).toBe(response.conversation_id);
|
|
315
|
+
expect(stateData.currentPhase).toBe(response.phase);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('should handle concurrent state updates', async () => {
|
|
319
|
+
// Initialize conversation
|
|
320
|
+
await client.callTool('whats_next', { user_input: 'start' });
|
|
321
|
+
|
|
322
|
+
// Make multiple rapid state changes
|
|
323
|
+
const promises = [
|
|
324
|
+
client.callTool('proceed_to_phase', {
|
|
325
|
+
target_phase: 'design',
|
|
326
|
+
reason: 'test1',
|
|
327
|
+
review_state: 'not-required',
|
|
328
|
+
}),
|
|
329
|
+
client.callTool('proceed_to_phase', {
|
|
330
|
+
target_phase: 'implementation',
|
|
331
|
+
reason: 'test2',
|
|
332
|
+
review_state: 'not-required',
|
|
333
|
+
}),
|
|
334
|
+
client.callTool('proceed_to_phase', {
|
|
335
|
+
target_phase: 'qa',
|
|
336
|
+
reason: 'test3',
|
|
337
|
+
review_state: 'not-required',
|
|
338
|
+
}),
|
|
339
|
+
];
|
|
340
|
+
|
|
341
|
+
const results = await Promise.all(promises);
|
|
342
|
+
|
|
343
|
+
// All should succeed (though final state may vary)
|
|
344
|
+
for (const result of results) {
|
|
345
|
+
expect(result).toBeTruthy();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Final state should be consistent
|
|
349
|
+
const stateResource = await client.readResource('state://current');
|
|
350
|
+
const stateData = JSON.parse(stateResource.contents[0].text);
|
|
351
|
+
expect(stateData.currentPhase).toBeTruthy();
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
describe('Conversation Context Management', () => {
|
|
356
|
+
it('should handle conversation context in whats_next calls', async () => {
|
|
357
|
+
// Call whats_next with rich context
|
|
358
|
+
const result = await client.callTool('whats_next', {
|
|
359
|
+
user_input: 'I want to implement authentication',
|
|
360
|
+
context: 'Starting new feature development',
|
|
361
|
+
conversation_summary: 'Starting new auth feature',
|
|
362
|
+
recent_messages: [
|
|
363
|
+
{ role: 'user', content: 'I need authentication' },
|
|
364
|
+
{ role: 'assistant', content: 'I can help with that' },
|
|
365
|
+
],
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const response = assertToolSuccess(result);
|
|
369
|
+
expect(response.phase).toBeTruthy();
|
|
370
|
+
expect(response.instructions).toBeTruthy();
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('should maintain context across phase transitions', async () => {
|
|
374
|
+
// Start with context
|
|
375
|
+
await client.callTool('whats_next', {
|
|
376
|
+
user_input: 'start feature',
|
|
377
|
+
context: 'new feature development',
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// Transition with context
|
|
381
|
+
const transition = await client.callTool('proceed_to_phase', {
|
|
382
|
+
target_phase: 'design',
|
|
383
|
+
reason: 'requirements gathered',
|
|
384
|
+
review_state: 'not-required',
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
const response = assertToolSuccess(transition);
|
|
388
|
+
expect(response.phase).toBe('design');
|
|
389
|
+
expect(response.instructions).toBeTruthy();
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
});
|