@codemcp/workflows 4.10.2 → 4.10.4
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 +1 -1
- package/dist/components/beads/beads-instruction-generator.d.ts +1 -4
- package/dist/components/beads/beads-instruction-generator.d.ts.map +1 -1
- package/dist/components/beads/beads-instruction-generator.js +24 -52
- package/dist/components/beads/beads-instruction-generator.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server-config.d.ts.map +1 -1
- package/dist/server-config.js +4 -8
- package/dist/server-config.js.map +1 -1
- package/dist/tool-handlers/base-tool-handler.d.ts.map +1 -1
- package/dist/tool-handlers/base-tool-handler.js.map +1 -1
- package/dist/tool-handlers/get-tool-info.d.ts +0 -1
- package/dist/tool-handlers/get-tool-info.d.ts.map +1 -1
- package/dist/tool-handlers/get-tool-info.js +0 -1
- package/dist/tool-handlers/get-tool-info.js.map +1 -1
- package/dist/tool-handlers/proceed-to-phase.d.ts +0 -2
- package/dist/tool-handlers/proceed-to-phase.d.ts.map +1 -1
- package/dist/tool-handlers/proceed-to-phase.js +0 -2
- package/dist/tool-handlers/proceed-to-phase.js.map +1 -1
- package/dist/tool-handlers/resume-workflow.d.ts +0 -1
- package/dist/tool-handlers/resume-workflow.d.ts.map +1 -1
- package/dist/tool-handlers/resume-workflow.js +0 -1
- package/dist/tool-handlers/resume-workflow.js.map +1 -1
- package/dist/tool-handlers/start-development.d.ts +0 -3
- package/dist/tool-handlers/start-development.d.ts.map +1 -1
- package/dist/tool-handlers/start-development.js +0 -6
- package/dist/tool-handlers/start-development.js.map +1 -1
- package/dist/tool-handlers/whats-next.d.ts +0 -2
- package/dist/tool-handlers/whats-next.d.ts.map +1 -1
- package/dist/tool-handlers/whats-next.js +0 -2
- package/dist/tool-handlers/whats-next.js.map +1 -1
- package/package.json +5 -5
- package/src/components/beads/beads-instruction-generator.ts +28 -60
- package/src/index.ts +1 -1
- package/src/server-config.ts +6 -9
- package/src/tool-handlers/base-tool-handler.ts +4 -3
- package/src/tool-handlers/get-tool-info.ts +0 -2
- package/src/tool-handlers/proceed-to-phase.ts +0 -4
- package/src/tool-handlers/resume-workflow.ts +0 -2
- package/src/tool-handlers/start-development.ts +0 -8
- package/src/tool-handlers/whats-next.ts +0 -4
- package/test/e2e/beads-plugin-integration.test.ts +4 -19
- package/test/e2e/core-functionality.test.ts +3 -12
- package/test/e2e/mcp-contract.test.ts +0 -31
- package/test/e2e/plugin-system-integration.test.ts +7 -315
- package/test/e2e/state-management.test.ts +1 -5
- package/test/e2e/workflow-integration.test.ts +2 -11
- package/test/unit/beads-instruction-generator.test.ts +235 -103
- package/test/unit/beads-phase-task-id-integration.test.ts +7 -29
- package/test/unit/resume-workflow.test.ts +0 -1
- package/test/unit/server-tools.test.ts +0 -1
- package/test/utils/e2e-test-setup.ts +2 -3
- package/test/utils/test-setup.ts +2 -3
- package/tsconfig.build.json +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -33,7 +33,6 @@ import { McpToolResponse } from '../../src/types';
|
|
|
33
33
|
import type { StartDevelopmentResult } from '../../src/tool-handlers/start-development';
|
|
34
34
|
import type { ProceedToPhaseResult } from '../../src/tool-handlers/proceed-to-phase';
|
|
35
35
|
import type { WhatsNextResult } from '../../src/tool-handlers/whats-next';
|
|
36
|
-
import type { YamlStateMachine } from '@codemcp/workflows-core';
|
|
37
36
|
|
|
38
37
|
vi.unmock('fs');
|
|
39
38
|
vi.unmock('fs/promises');
|
|
@@ -61,18 +60,6 @@ const WORKFLOW_INITIAL_PHASES = {
|
|
|
61
60
|
// These helpers enforce strict contract validation and prevent assertion
|
|
62
61
|
// repetition. Each helper comprehensively validates one response type.
|
|
63
62
|
|
|
64
|
-
/**
|
|
65
|
-
* Validates UUID format (standard v4 UUID) - RELAXED FOR NOW
|
|
66
|
-
* In the actual codebase, conversation IDs may use different formats
|
|
67
|
-
* The important validation is that they're non-empty strings
|
|
68
|
-
* VALIDATE: IDs must be uniquely identifiable
|
|
69
|
-
*/
|
|
70
|
-
function isValidUUID(value: string): boolean {
|
|
71
|
-
// Accept anything that looks like a UUID or a similar unique identifier
|
|
72
|
-
// Format: hex chars and dashes, length 36+, or any non-empty string
|
|
73
|
-
return /^[a-f0-9-]{36,}$|^[a-zA-Z0-9_-]{10,}$/.test(value);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
63
|
/**
|
|
77
64
|
* Validates that a value is a non-empty string
|
|
78
65
|
*/
|
|
@@ -94,46 +81,6 @@ function isSubstantiveContent(value: string): boolean {
|
|
|
94
81
|
);
|
|
95
82
|
}
|
|
96
83
|
|
|
97
|
-
/**
|
|
98
|
-
* Validates workflow object structure
|
|
99
|
-
* VALIDATE: Workflow must have name and state definitions
|
|
100
|
-
*/
|
|
101
|
-
function isValidWorkflowObject(
|
|
102
|
-
workflow: unknown
|
|
103
|
-
): workflow is YamlStateMachine {
|
|
104
|
-
if (typeof workflow !== 'object' || workflow === null) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const obj = workflow as Record<string, unknown>;
|
|
109
|
-
|
|
110
|
-
// VALIDATE: All required properties must exist
|
|
111
|
-
return (
|
|
112
|
-
typeof obj.name === 'string' &&
|
|
113
|
-
obj.name.length > 0 &&
|
|
114
|
-
typeof obj.initial_state === 'string' &&
|
|
115
|
-
obj.initial_state.length > 0 &&
|
|
116
|
-
typeof obj.states === 'object' &&
|
|
117
|
-
obj.states !== null
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Validates phase string against valid workflow phases
|
|
123
|
-
* VALIDATE: Phase must exist in workflow states
|
|
124
|
-
*/
|
|
125
|
-
function isValidPhaseForWorkflow(
|
|
126
|
-
phase: string,
|
|
127
|
-
workflow: YamlStateMachine
|
|
128
|
-
): boolean {
|
|
129
|
-
if (typeof phase !== 'string' || phase.length === 0) {
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const states = workflow.states as Record<string, unknown>;
|
|
134
|
-
return phase in states;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
84
|
/**
|
|
138
85
|
* Comprehensive validation for StartDevelopmentResult
|
|
139
86
|
* VALIDATE: Response must have all required properties with correct types and values
|
|
@@ -151,33 +98,16 @@ function assertValidStartDevelopmentResponse(
|
|
|
151
98
|
}
|
|
152
99
|
const result = response as Record<string, unknown>;
|
|
153
100
|
|
|
154
|
-
// VALIDATE: conversation_id must be a non-empty string in UUID format
|
|
155
|
-
expect(result).toHaveProperty('conversation_id');
|
|
156
|
-
expect(isNonEmptyString(result.conversation_id)).toBe(true);
|
|
157
|
-
expect(isValidUUID(result.conversation_id as string)).toBe(true);
|
|
158
|
-
|
|
159
|
-
// VALIDATE: phase must be a non-empty string
|
|
160
101
|
expect(result).toHaveProperty('phase');
|
|
161
102
|
expect(isNonEmptyString(result.phase)).toBe(true);
|
|
162
103
|
|
|
163
|
-
// VALIDATE: plan_file_path must be a non-empty string pointing to existing file
|
|
164
104
|
expect(result).toHaveProperty('plan_file_path');
|
|
165
105
|
expect(isNonEmptyString(result.plan_file_path)).toBe(true);
|
|
166
106
|
|
|
167
|
-
// VALIDATE: instructions must be substantive content
|
|
168
107
|
expect(result).toHaveProperty('instructions');
|
|
169
108
|
expect(isNonEmptyString(result.instructions)).toBe(true);
|
|
170
109
|
expect(isSubstantiveContent(result.instructions as string)).toBe(true);
|
|
171
110
|
|
|
172
|
-
// VALIDATE: workflow must be valid YamlStateMachine object
|
|
173
|
-
expect(result).toHaveProperty('workflow');
|
|
174
|
-
expect(isValidWorkflowObject(result.workflow)).toBe(true);
|
|
175
|
-
|
|
176
|
-
// VALIDATE: phase must be valid for the workflow
|
|
177
|
-
const workflow = result.workflow as YamlStateMachine;
|
|
178
|
-
expect(isValidPhaseForWorkflow(result.phase as string, workflow)).toBe(true);
|
|
179
|
-
|
|
180
|
-
// VALIDATE: workflowDocumentationUrl is optional but must be string if present
|
|
181
111
|
if (result.workflowDocumentationUrl !== undefined) {
|
|
182
112
|
expect(typeof result.workflowDocumentationUrl).toBe('string');
|
|
183
113
|
}
|
|
@@ -202,32 +132,19 @@ function assertValidProceedToPhaseResponse(
|
|
|
202
132
|
}
|
|
203
133
|
const result = response as Record<string, unknown>;
|
|
204
134
|
|
|
205
|
-
// VALIDATE: phase must be a non-empty string
|
|
206
135
|
expect(result).toHaveProperty('phase');
|
|
207
136
|
expect(isNonEmptyString(result.phase)).toBe(true);
|
|
208
137
|
|
|
209
|
-
// VALIDATE: instructions must be substantive content
|
|
210
138
|
expect(result).toHaveProperty('instructions');
|
|
211
139
|
expect(isNonEmptyString(result.instructions)).toBe(true);
|
|
212
140
|
expect(isSubstantiveContent(result.instructions as string)).toBe(true);
|
|
213
141
|
|
|
214
|
-
// VALIDATE: plan_file_path must be a non-empty string
|
|
215
142
|
expect(result).toHaveProperty('plan_file_path');
|
|
216
143
|
expect(isNonEmptyString(result.plan_file_path)).toBe(true);
|
|
217
144
|
|
|
218
|
-
// VALIDATE: transition_reason must be a non-empty string
|
|
219
145
|
expect(result).toHaveProperty('transition_reason');
|
|
220
146
|
expect(isNonEmptyString(result.transition_reason)).toBe(true);
|
|
221
147
|
|
|
222
|
-
// VALIDATE: is_modeled_transition must be boolean (NOT string, NOT null)
|
|
223
|
-
expect(result).toHaveProperty('is_modeled_transition');
|
|
224
|
-
expect(typeof result.is_modeled_transition).toBe('boolean');
|
|
225
|
-
|
|
226
|
-
// VALIDATE: conversation_id must be a valid UUID
|
|
227
|
-
expect(result).toHaveProperty('conversation_id');
|
|
228
|
-
expect(isNonEmptyString(result.conversation_id)).toBe(true);
|
|
229
|
-
expect(isValidUUID(result.conversation_id as string)).toBe(true);
|
|
230
|
-
|
|
231
148
|
return result as unknown as ProceedToPhaseResult;
|
|
232
149
|
}
|
|
233
150
|
|
|
@@ -246,28 +163,16 @@ function assertValidWhatsNextResponse(response: unknown): WhatsNextResult {
|
|
|
246
163
|
}
|
|
247
164
|
const result = response as Record<string, unknown>;
|
|
248
165
|
|
|
249
|
-
// VALIDATE: phase must be a non-empty string
|
|
250
166
|
expect(result).toHaveProperty('phase');
|
|
251
167
|
expect(isNonEmptyString(result.phase)).toBe(true);
|
|
252
168
|
|
|
253
|
-
// VALIDATE: instructions must be substantive content
|
|
254
169
|
expect(result).toHaveProperty('instructions');
|
|
255
170
|
expect(isNonEmptyString(result.instructions)).toBe(true);
|
|
256
171
|
expect(isSubstantiveContent(result.instructions as string)).toBe(true);
|
|
257
172
|
|
|
258
|
-
// VALIDATE: plan_file_path must be a non-empty string
|
|
259
173
|
expect(result).toHaveProperty('plan_file_path');
|
|
260
174
|
expect(isNonEmptyString(result.plan_file_path)).toBe(true);
|
|
261
175
|
|
|
262
|
-
// VALIDATE: is_modeled_transition must be boolean (NOT string, NOT null)
|
|
263
|
-
expect(result).toHaveProperty('is_modeled_transition');
|
|
264
|
-
expect(typeof result.is_modeled_transition).toBe('boolean');
|
|
265
|
-
|
|
266
|
-
// VALIDATE: conversation_id must be a valid UUID
|
|
267
|
-
expect(result).toHaveProperty('conversation_id');
|
|
268
|
-
expect(isNonEmptyString(result.conversation_id)).toBe(true);
|
|
269
|
-
expect(isValidUUID(result.conversation_id as string)).toBe(true);
|
|
270
|
-
|
|
271
176
|
return result as unknown as WhatsNextResult;
|
|
272
177
|
}
|
|
273
178
|
|
|
@@ -337,12 +242,9 @@ describe('Plugin System Integration Tests', () => {
|
|
|
337
242
|
const response = assertToolSuccess(result);
|
|
338
243
|
const validated = assertValidStartDevelopmentResponse(response);
|
|
339
244
|
|
|
340
|
-
// VALIDATE: Response is properly typed
|
|
341
|
-
expect(validated.conversation_id).toBeDefined();
|
|
342
245
|
expect(validated.phase).toBeDefined();
|
|
343
246
|
expect(validated.plan_file_path).toBeDefined();
|
|
344
247
|
expect(validated.instructions).toBeDefined();
|
|
345
|
-
expect(validated.workflow).toBeDefined();
|
|
346
248
|
});
|
|
347
249
|
|
|
348
250
|
it('should return valid ProceedToPhaseResult with all required properties', async () => {
|
|
@@ -357,10 +259,7 @@ describe('Plugin System Integration Tests', () => {
|
|
|
357
259
|
const response = assertToolSuccess(result);
|
|
358
260
|
const validated = assertValidProceedToPhaseResponse(response);
|
|
359
261
|
|
|
360
|
-
// VALIDATE: Response has all required properties
|
|
361
262
|
expect(validated.phase).toBe('design');
|
|
362
|
-
// is_modeled_transition can be true or false - just validate it's boolean
|
|
363
|
-
expect(typeof validated.is_modeled_transition).toBe('boolean');
|
|
364
263
|
});
|
|
365
264
|
|
|
366
265
|
it('should return valid WhatsNextResult with all required properties', async () => {
|
|
@@ -374,9 +273,7 @@ describe('Plugin System Integration Tests', () => {
|
|
|
374
273
|
const response = assertToolSuccess(result);
|
|
375
274
|
const validated = assertValidWhatsNextResponse(response);
|
|
376
275
|
|
|
377
|
-
// VALIDATE: Response has all required properties
|
|
378
276
|
expect(validated.phase).toBe('requirements');
|
|
379
|
-
expect(validated.is_modeled_transition).toBeDefined();
|
|
380
277
|
});
|
|
381
278
|
|
|
382
279
|
it('should validate conversation IDs are UUID format', async () => {
|
|
@@ -385,10 +282,7 @@ describe('Plugin System Integration Tests', () => {
|
|
|
385
282
|
commit_behaviour: 'none',
|
|
386
283
|
});
|
|
387
284
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// VALIDATE: conversation_id must be UUID format to ensure uniqueness
|
|
391
|
-
expect(isValidUUID(response.conversation_id)).toBe(true);
|
|
285
|
+
assertToolSuccess(result);
|
|
392
286
|
});
|
|
393
287
|
|
|
394
288
|
it('should validate instructions contain substantive content', async () => {
|
|
@@ -399,7 +293,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
399
293
|
|
|
400
294
|
const response = assertToolSuccess(result);
|
|
401
295
|
|
|
402
|
-
// VALIDATE: instructions must be meaningful and guide user
|
|
403
296
|
expect(response.instructions.length).toBeGreaterThan(100);
|
|
404
297
|
expect(response.instructions).toMatch(
|
|
405
298
|
/\b(phase|development|task|workflow|plan)\b/i
|
|
@@ -414,40 +307,10 @@ describe('Plugin System Integration Tests', () => {
|
|
|
414
307
|
|
|
415
308
|
const response = assertToolSuccess(result);
|
|
416
309
|
|
|
417
|
-
// VALIDATE: plan file must exist and be readable
|
|
418
310
|
await assertFileExists(response.plan_file_path);
|
|
419
311
|
const content = await fs.readFile(response.plan_file_path, 'utf-8');
|
|
420
312
|
expect(content.length).toBeGreaterThan(0);
|
|
421
313
|
});
|
|
422
|
-
|
|
423
|
-
it('should validate workflow objects have required structure', async () => {
|
|
424
|
-
const result = await client.callTool('start_development', {
|
|
425
|
-
workflow: 'waterfall',
|
|
426
|
-
commit_behaviour: 'none',
|
|
427
|
-
});
|
|
428
|
-
|
|
429
|
-
const response = assertToolSuccess(result);
|
|
430
|
-
|
|
431
|
-
// VALIDATE: workflow must be actual object with expected properties
|
|
432
|
-
expect(response.workflow).toStrictEqual(expect.any(Object));
|
|
433
|
-
expect(response.workflow).toHaveProperty('name');
|
|
434
|
-
expect(response.workflow).toHaveProperty('initial_state');
|
|
435
|
-
expect(response.workflow).toHaveProperty('states');
|
|
436
|
-
expect(response.workflow.name).toBe('waterfall');
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
it('should validate phase is valid for workflow', async () => {
|
|
440
|
-
const result = await client.callTool('start_development', {
|
|
441
|
-
workflow: 'waterfall',
|
|
442
|
-
commit_behaviour: 'none',
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
const response = assertToolSuccess(result);
|
|
446
|
-
|
|
447
|
-
// VALIDATE: phase must exist in workflow states
|
|
448
|
-
const states = response.workflow.states as Record<string, unknown>;
|
|
449
|
-
expect(states).toHaveProperty(response.phase);
|
|
450
|
-
});
|
|
451
314
|
});
|
|
452
315
|
|
|
453
316
|
describe('Semantic Validation', () => {
|
|
@@ -481,7 +344,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
481
344
|
|
|
482
345
|
const response = assertToolSuccess(result);
|
|
483
346
|
|
|
484
|
-
// VALIDATE: Plan file must exist and contain workflow sections
|
|
485
347
|
const planContent = await fs.readFile(response.plan_file_path, 'utf-8');
|
|
486
348
|
expect(planContent).toContain('## Explore');
|
|
487
349
|
expect(planContent).toContain('## Plan');
|
|
@@ -510,7 +372,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
510
372
|
|
|
511
373
|
const response = assertToolSuccess(result);
|
|
512
374
|
|
|
513
|
-
// VALIDATE: phase must match the target and be in valid list
|
|
514
375
|
expect(response.phase).toBe(targetPhase);
|
|
515
376
|
expect(validPhases).toContain(response.phase);
|
|
516
377
|
}
|
|
@@ -537,10 +398,8 @@ describe('Plugin System Integration Tests', () => {
|
|
|
537
398
|
});
|
|
538
399
|
const response2 = assertToolSuccess(result2);
|
|
539
400
|
|
|
540
|
-
// VALIDATE: Plan file path must remain consistent
|
|
541
401
|
expect(response2.plan_file_path).toBe(planPath1);
|
|
542
402
|
|
|
543
|
-
// VALIDATE: File must exist and have content
|
|
544
403
|
const planContent = await fs.readFile(planPath1, 'utf-8');
|
|
545
404
|
expect(planContent.length).toBeGreaterThan(0);
|
|
546
405
|
});
|
|
@@ -563,7 +422,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
563
422
|
});
|
|
564
423
|
const response = assertToolSuccess(result);
|
|
565
424
|
|
|
566
|
-
// VALIDATE: instructions must be substantive
|
|
567
425
|
expect(isSubstantiveContent(response.instructions)).toBe(true);
|
|
568
426
|
|
|
569
427
|
// Transition to next phase
|
|
@@ -609,13 +467,9 @@ describe('Plugin System Integration Tests', () => {
|
|
|
609
467
|
|
|
610
468
|
const response = assertToolSuccess(result);
|
|
611
469
|
|
|
612
|
-
// VALIDATE: No plugin internals should leak
|
|
613
470
|
assertNoPluginLeak(response);
|
|
614
471
|
|
|
615
|
-
// VALIDATE: Should have core fields only
|
|
616
|
-
expect(response).toHaveProperty('conversation_id');
|
|
617
472
|
expect(response).toHaveProperty('phase');
|
|
618
|
-
expect(response).toHaveProperty('workflow');
|
|
619
473
|
expect(response).toHaveProperty('instructions');
|
|
620
474
|
});
|
|
621
475
|
|
|
@@ -630,13 +484,10 @@ describe('Plugin System Integration Tests', () => {
|
|
|
630
484
|
|
|
631
485
|
const response = assertToolSuccess(result);
|
|
632
486
|
|
|
633
|
-
// VALIDATE: No plugin internals should leak
|
|
634
487
|
assertNoPluginLeak(response);
|
|
635
488
|
|
|
636
|
-
// VALIDATE: Should have core fields only
|
|
637
489
|
expect(response).toHaveProperty('phase');
|
|
638
490
|
expect(response).toHaveProperty('instructions');
|
|
639
|
-
expect(response).toHaveProperty('is_modeled_transition');
|
|
640
491
|
});
|
|
641
492
|
|
|
642
493
|
it('should not expose plugin internals in WhatsNextResult', async () => {
|
|
@@ -648,13 +499,10 @@ describe('Plugin System Integration Tests', () => {
|
|
|
648
499
|
|
|
649
500
|
const response = assertToolSuccess(result);
|
|
650
501
|
|
|
651
|
-
// VALIDATE: No plugin internals should leak
|
|
652
502
|
assertNoPluginLeak(response);
|
|
653
503
|
|
|
654
|
-
// VALIDATE: Should have core fields only
|
|
655
504
|
expect(response).toHaveProperty('phase');
|
|
656
505
|
expect(response).toHaveProperty('instructions');
|
|
657
|
-
expect(response).toHaveProperty('is_modeled_transition');
|
|
658
506
|
});
|
|
659
507
|
});
|
|
660
508
|
|
|
@@ -687,16 +535,7 @@ describe('Plugin System Integration Tests', () => {
|
|
|
687
535
|
commit_behaviour: 'none',
|
|
688
536
|
});
|
|
689
537
|
|
|
690
|
-
|
|
691
|
-
assertToolSuccess(result)
|
|
692
|
-
);
|
|
693
|
-
|
|
694
|
-
// VALIDATE: Workflow name must match selected workflow
|
|
695
|
-
expect(response.workflow.name).toBe('waterfall');
|
|
696
|
-
|
|
697
|
-
// VALIDATE: Initial phase must be valid for workflow
|
|
698
|
-
const states = response.workflow.states as Record<string, unknown>;
|
|
699
|
-
expect(states).toHaveProperty(response.phase);
|
|
538
|
+
assertValidStartDevelopmentResponse(assertToolSuccess(result));
|
|
700
539
|
});
|
|
701
540
|
|
|
702
541
|
it('should work with epcc workflow', async () => {
|
|
@@ -709,10 +548,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
709
548
|
assertToolSuccess(result)
|
|
710
549
|
);
|
|
711
550
|
|
|
712
|
-
// VALIDATE: Workflow name must match selected workflow
|
|
713
|
-
expect(response.workflow.name).toBe('epcc');
|
|
714
|
-
|
|
715
|
-
// VALIDATE: Initial phase must be explore
|
|
716
551
|
expect(response.phase).toBe('explore');
|
|
717
552
|
});
|
|
718
553
|
|
|
@@ -726,10 +561,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
726
561
|
assertToolSuccess(result)
|
|
727
562
|
);
|
|
728
563
|
|
|
729
|
-
// VALIDATE: Workflow name must match selected workflow
|
|
730
|
-
expect(response.workflow.name).toBe('tdd');
|
|
731
|
-
|
|
732
|
-
// VALIDATE: Initial phase must be explore
|
|
733
564
|
expect(response.phase).toBe('explore');
|
|
734
565
|
});
|
|
735
566
|
|
|
@@ -743,10 +574,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
743
574
|
assertToolSuccess(result)
|
|
744
575
|
);
|
|
745
576
|
|
|
746
|
-
// VALIDATE: Workflow name must match selected workflow
|
|
747
|
-
expect(response.workflow.name).toBe('minor');
|
|
748
|
-
|
|
749
|
-
// VALIDATE: Initial phase must be explore
|
|
750
577
|
expect(response.phase).toBe('explore');
|
|
751
578
|
});
|
|
752
579
|
|
|
@@ -756,17 +583,7 @@ describe('Plugin System Integration Tests', () => {
|
|
|
756
583
|
commit_behaviour: 'none',
|
|
757
584
|
});
|
|
758
585
|
|
|
759
|
-
|
|
760
|
-
assertToolSuccess(result)
|
|
761
|
-
);
|
|
762
|
-
|
|
763
|
-
// VALIDATE: Workflow name must match selected workflow
|
|
764
|
-
expect(response.workflow.name).toBe('bugfix');
|
|
765
|
-
|
|
766
|
-
// VALIDATE: Initial phase must be reproduce or analyze
|
|
767
|
-
const states = response.workflow.states as Record<string, unknown>;
|
|
768
|
-
expect(states).toHaveProperty(response.phase);
|
|
769
|
-
expect(['reproduce', 'analyze']).toContain(response.phase);
|
|
586
|
+
assertValidStartDevelopmentResponse(assertToolSuccess(result));
|
|
770
587
|
});
|
|
771
588
|
});
|
|
772
589
|
|
|
@@ -793,59 +610,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
793
610
|
}
|
|
794
611
|
});
|
|
795
612
|
|
|
796
|
-
it('should preserve conversation_id across tool calls', async () => {
|
|
797
|
-
const result1 = await client.callTool('start_development', {
|
|
798
|
-
workflow: 'waterfall',
|
|
799
|
-
commit_behaviour: 'none',
|
|
800
|
-
});
|
|
801
|
-
const response1 = assertValidStartDevelopmentResponse(
|
|
802
|
-
assertToolSuccess(result1)
|
|
803
|
-
);
|
|
804
|
-
const conversationId1 = response1.conversation_id;
|
|
805
|
-
|
|
806
|
-
// VALIDATE: conversation_id must be UUID format
|
|
807
|
-
expect(isValidUUID(conversationId1)).toBe(true);
|
|
808
|
-
|
|
809
|
-
// Make another call
|
|
810
|
-
const result2 = await client.callTool('whats_next', {
|
|
811
|
-
user_input: 'continue development',
|
|
812
|
-
});
|
|
813
|
-
const response2 = assertValidWhatsNextResponse(
|
|
814
|
-
assertToolSuccess(result2)
|
|
815
|
-
);
|
|
816
|
-
|
|
817
|
-
// VALIDATE: Conversation must be maintained
|
|
818
|
-
expect(response2.conversation_id).toBe(conversationId1);
|
|
819
|
-
});
|
|
820
|
-
|
|
821
|
-
it('should transition phases while maintaining conversation_id', async () => {
|
|
822
|
-
await initializeDevelopment(client, 'waterfall');
|
|
823
|
-
|
|
824
|
-
const result1 = await client.callTool('whats_next', {
|
|
825
|
-
user_input: 'test 1',
|
|
826
|
-
});
|
|
827
|
-
const response1 = assertValidWhatsNextResponse(
|
|
828
|
-
assertToolSuccess(result1)
|
|
829
|
-
);
|
|
830
|
-
const conversationId = response1.conversation_id;
|
|
831
|
-
|
|
832
|
-
// Transition to design phase
|
|
833
|
-
const result2 = await client.callTool('proceed_to_phase', {
|
|
834
|
-
target_phase: 'design',
|
|
835
|
-
reason: 'ready to design',
|
|
836
|
-
review_state: 'not-required',
|
|
837
|
-
});
|
|
838
|
-
const response2 = assertValidProceedToPhaseResponse(
|
|
839
|
-
assertToolSuccess(result2)
|
|
840
|
-
);
|
|
841
|
-
|
|
842
|
-
// VALIDATE: Conversation_id must remain the same
|
|
843
|
-
expect(response2.conversation_id).toBe(conversationId);
|
|
844
|
-
|
|
845
|
-
// VALIDATE: Phase must have changed
|
|
846
|
-
expect(response2.phase).toBe('design');
|
|
847
|
-
});
|
|
848
|
-
|
|
849
613
|
it('should handle phase transitions with proper state updates', async () => {
|
|
850
614
|
await initializeDevelopment(client, 'waterfall');
|
|
851
615
|
|
|
@@ -860,7 +624,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
860
624
|
(contents1[0] as Record<string, unknown>).text as string
|
|
861
625
|
);
|
|
862
626
|
|
|
863
|
-
// VALIDATE: Current phase must match expected
|
|
864
627
|
expect(stateData1.currentPhase).toBe('requirements');
|
|
865
628
|
|
|
866
629
|
// Transition
|
|
@@ -881,7 +644,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
881
644
|
(contents2[0] as Record<string, unknown>).text as string
|
|
882
645
|
);
|
|
883
646
|
|
|
884
|
-
// VALIDATE: Phase must have been updated
|
|
885
647
|
expect(stateData2.currentPhase).toBe('design');
|
|
886
648
|
});
|
|
887
649
|
});
|
|
@@ -922,19 +684,13 @@ describe('Plugin System Integration Tests', () => {
|
|
|
922
684
|
}
|
|
923
685
|
);
|
|
924
686
|
|
|
925
|
-
// VALIDATE: Should have error
|
|
926
687
|
expect(invalid.error).toBeDefined();
|
|
927
688
|
|
|
928
689
|
// Should still work afterwards
|
|
929
690
|
const recovery = await client.callTool('whats_next', {
|
|
930
691
|
user_input: 'recover',
|
|
931
692
|
});
|
|
932
|
-
|
|
933
|
-
assertToolSuccess(recovery)
|
|
934
|
-
);
|
|
935
|
-
|
|
936
|
-
// VALIDATE: Response must be valid
|
|
937
|
-
expect(isValidUUID(recoveryResponse.conversation_id)).toBe(true);
|
|
693
|
+
assertValidWhatsNextResponse(assertToolSuccess(recovery));
|
|
938
694
|
});
|
|
939
695
|
|
|
940
696
|
it('should handle missing workflow gracefully', async () => {
|
|
@@ -943,7 +699,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
943
699
|
commit_behaviour: 'none',
|
|
944
700
|
});
|
|
945
701
|
|
|
946
|
-
// VALIDATE: Should either error or handle gracefully
|
|
947
702
|
expect(result).toBeDefined();
|
|
948
703
|
});
|
|
949
704
|
|
|
@@ -958,7 +713,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
958
713
|
.text as string
|
|
959
714
|
);
|
|
960
715
|
|
|
961
|
-
// VALIDATE: Initial state must be valid
|
|
962
716
|
expect(data1.currentPhase).toBe('requirements');
|
|
963
717
|
|
|
964
718
|
// Cause an error
|
|
@@ -976,10 +730,8 @@ describe('Plugin System Integration Tests', () => {
|
|
|
976
730
|
.text as string
|
|
977
731
|
);
|
|
978
732
|
|
|
979
|
-
// VALIDATE: Phase must not have changed after error
|
|
980
733
|
expect(data2.currentPhase).toBe(data1.currentPhase);
|
|
981
734
|
|
|
982
|
-
// VALIDATE: Conversation must remain the same
|
|
983
735
|
expect(data2.conversationId).toBe(data1.conversationId);
|
|
984
736
|
});
|
|
985
737
|
});
|
|
@@ -1020,8 +772,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1020
772
|
assertToolSuccess(result)
|
|
1021
773
|
);
|
|
1022
774
|
|
|
1023
|
-
// VALIDATE: All required properties exist and are valid
|
|
1024
|
-
expect(isValidUUID(response.conversation_id)).toBe(true);
|
|
1025
775
|
await assertFileExists(response.plan_file_path);
|
|
1026
776
|
expect(response.phase).toBe('requirements');
|
|
1027
777
|
});
|
|
@@ -1036,7 +786,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1036
786
|
assertToolSuccess(result)
|
|
1037
787
|
);
|
|
1038
788
|
|
|
1039
|
-
// VALIDATE: Verify proper plan file structure
|
|
1040
789
|
const planContent = await fs.readFile(response.plan_file_path, 'utf-8');
|
|
1041
790
|
expect(planContent).toContain('## Explore');
|
|
1042
791
|
expect(planContent).toContain('## Plan');
|
|
@@ -1076,12 +825,10 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1076
825
|
)) as unknown;
|
|
1077
826
|
const resource = stateResource as Record<string, unknown>;
|
|
1078
827
|
|
|
1079
|
-
// VALIDATE: Resource must have contents array
|
|
1080
828
|
expect(resource).toHaveProperty('contents');
|
|
1081
829
|
expect(Array.isArray(resource.contents)).toBe(true);
|
|
1082
830
|
expect((resource.contents as unknown[]).length).toBeGreaterThan(0);
|
|
1083
831
|
|
|
1084
|
-
// VALIDATE: Content must be valid JSON with expected fields
|
|
1085
832
|
const content = (
|
|
1086
833
|
(resource.contents as unknown[])[0] as Record<string, unknown>
|
|
1087
834
|
).text as string;
|
|
@@ -1098,12 +845,10 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1098
845
|
)) as unknown;
|
|
1099
846
|
const resource = planResource as Record<string, unknown>;
|
|
1100
847
|
|
|
1101
|
-
// VALIDATE: Resource must have contents array
|
|
1102
848
|
expect(resource).toHaveProperty('contents');
|
|
1103
849
|
expect(Array.isArray(resource.contents)).toBe(true);
|
|
1104
850
|
expect((resource.contents as unknown[]).length).toBeGreaterThan(0);
|
|
1105
851
|
|
|
1106
|
-
// VALIDATE: Content must be non-empty string
|
|
1107
852
|
const content = (
|
|
1108
853
|
(resource.contents as unknown[])[0] as Record<string, unknown>
|
|
1109
854
|
).text as string;
|
|
@@ -1117,17 +862,14 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1117
862
|
)) as unknown;
|
|
1118
863
|
const resource = promptResource as Record<string, unknown>;
|
|
1119
864
|
|
|
1120
|
-
// VALIDATE: Resource must have contents array
|
|
1121
865
|
expect(resource).toHaveProperty('contents');
|
|
1122
866
|
expect(Array.isArray(resource.contents)).toBe(true);
|
|
1123
867
|
expect((resource.contents as unknown[]).length).toBeGreaterThan(0);
|
|
1124
868
|
|
|
1125
|
-
// VALIDATE: Content must be non-empty string
|
|
1126
869
|
const contentObj = (resource.contents as unknown[])[0] as Record<
|
|
1127
870
|
string,
|
|
1128
871
|
unknown
|
|
1129
872
|
>;
|
|
1130
|
-
// VALIDATE: Must have a string property with content
|
|
1131
873
|
// Try text first (primary), then content (secondary), then get string representation
|
|
1132
874
|
let content: string;
|
|
1133
875
|
if (typeof contentObj.text === 'string' && contentObj.text.length > 0) {
|
|
@@ -1186,9 +928,7 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1186
928
|
assertToolSuccess(result)
|
|
1187
929
|
);
|
|
1188
930
|
|
|
1189
|
-
// VALIDATE: Response indicates hooks were executed successfully
|
|
1190
931
|
// (plan file exists, instructions present, phase valid)
|
|
1191
|
-
expect(response.conversation_id).toBeDefined();
|
|
1192
932
|
expect(response.phase).toBe('requirements');
|
|
1193
933
|
expect(response.plan_file_path).toBeDefined();
|
|
1194
934
|
|
|
@@ -1219,10 +959,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1219
959
|
assertToolSuccess(whatsNextResult)
|
|
1220
960
|
);
|
|
1221
961
|
|
|
1222
|
-
// VALIDATE: State is consistent after hook execution
|
|
1223
|
-
expect(whatsNextResponse.conversation_id).toBe(
|
|
1224
|
-
startResponse.conversation_id
|
|
1225
|
-
);
|
|
1226
962
|
expect(whatsNextResponse.phase).toBe(startResponse.phase);
|
|
1227
963
|
expect(whatsNextResponse.plan_file_path).toBe(
|
|
1228
964
|
startResponse.plan_file_path
|
|
@@ -1243,13 +979,11 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1243
979
|
// Read and validate plan file
|
|
1244
980
|
const planContent = await fs.readFile(response.plan_file_path, 'utf-8');
|
|
1245
981
|
|
|
1246
|
-
// VALIDATE: Plan file structure intact (hooks shouldn't corrupt it)
|
|
1247
982
|
expect(planContent).toMatch(/^# /m); // Title
|
|
1248
983
|
expect(planContent).toMatch(/^## /m); // Sections
|
|
1249
984
|
expect(planContent).toContain('## Goal');
|
|
1250
985
|
expect(planContent).toContain('## Requirements');
|
|
1251
986
|
|
|
1252
|
-
// VALIDATE: No malformed content
|
|
1253
987
|
expect(planContent).not.toContain('undefined');
|
|
1254
988
|
expect(planContent).not.toContain('[object Object]');
|
|
1255
989
|
});
|
|
@@ -1273,9 +1007,7 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1273
1007
|
assertToolSuccess(result)
|
|
1274
1008
|
);
|
|
1275
1009
|
|
|
1276
|
-
// VALIDATE: Hooks executed for each workflow
|
|
1277
1010
|
await assertFileExists(response.plan_file_path);
|
|
1278
|
-
expect(response.conversation_id).toBeDefined();
|
|
1279
1011
|
|
|
1280
1012
|
await scenario.cleanup();
|
|
1281
1013
|
}
|
|
@@ -1317,17 +1049,13 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1317
1049
|
|
|
1318
1050
|
const response = assertToolSuccess(result);
|
|
1319
1051
|
|
|
1320
|
-
// VALIDATE: Response has no plugin internals
|
|
1321
1052
|
assertNoPluginLeak(response);
|
|
1322
1053
|
|
|
1323
|
-
// VALIDATE: Core response properties only (workflowDocumentationUrl is intentional - points to public docs)
|
|
1324
1054
|
expect(Object.keys(response).sort()).toEqual(
|
|
1325
1055
|
[
|
|
1326
|
-
'conversation_id',
|
|
1327
1056
|
'instructions',
|
|
1328
1057
|
'phase',
|
|
1329
1058
|
'plan_file_path',
|
|
1330
|
-
'workflow',
|
|
1331
1059
|
'workflowDocumentationUrl',
|
|
1332
1060
|
].sort()
|
|
1333
1061
|
);
|
|
@@ -1340,18 +1068,14 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1340
1068
|
commit_behaviour: 'none',
|
|
1341
1069
|
});
|
|
1342
1070
|
|
|
1343
|
-
|
|
1344
|
-
assertToolSuccess(startResult)
|
|
1345
|
-
);
|
|
1071
|
+
assertValidStartDevelopmentResponse(assertToolSuccess(startResult));
|
|
1346
1072
|
|
|
1347
1073
|
// Get whats_next
|
|
1348
1074
|
const whatsNextResult = await client.callTool('whats_next', {
|
|
1349
1075
|
user_input: 'next step',
|
|
1350
1076
|
});
|
|
1351
1077
|
|
|
1352
|
-
|
|
1353
|
-
assertToolSuccess(whatsNextResult)
|
|
1354
|
-
);
|
|
1078
|
+
assertValidWhatsNextResponse(assertToolSuccess(whatsNextResult));
|
|
1355
1079
|
|
|
1356
1080
|
// Transition phase
|
|
1357
1081
|
const transitionResult = await client.callTool('proceed_to_phase', {
|
|
@@ -1360,22 +1084,7 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1360
1084
|
review_state: 'not-required',
|
|
1361
1085
|
});
|
|
1362
1086
|
|
|
1363
|
-
|
|
1364
|
-
assertToolSuccess(transitionResult)
|
|
1365
|
-
);
|
|
1366
|
-
|
|
1367
|
-
// VALIDATE: All responses have consistent structure (plugins applied uniformly)
|
|
1368
|
-
expect(startResponse).toHaveProperty('conversation_id');
|
|
1369
|
-
expect(whatsNextResponse).toHaveProperty('conversation_id');
|
|
1370
|
-
expect(transitionResponse).toHaveProperty('conversation_id');
|
|
1371
|
-
|
|
1372
|
-
// VALIDATE: Same conversation across calls
|
|
1373
|
-
expect(whatsNextResponse.conversation_id).toBe(
|
|
1374
|
-
startResponse.conversation_id
|
|
1375
|
-
);
|
|
1376
|
-
expect(transitionResponse.conversation_id).toBe(
|
|
1377
|
-
startResponse.conversation_id
|
|
1378
|
-
);
|
|
1087
|
+
assertValidProceedToPhaseResponse(assertToolSuccess(transitionResult));
|
|
1379
1088
|
});
|
|
1380
1089
|
|
|
1381
1090
|
it('should preserve plugin boundaries (no cross-pollution)', async () => {
|
|
@@ -1387,15 +1096,11 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1387
1096
|
|
|
1388
1097
|
const response = assertToolSuccess(result);
|
|
1389
1098
|
|
|
1390
|
-
// VALIDATE: Response is clean (no plugin implementation details)
|
|
1391
1099
|
assertNoPluginLeak(response);
|
|
1392
1100
|
|
|
1393
|
-
// VALIDATE: All plugin functionality exposed only through standard response fields
|
|
1394
1101
|
expect(response).toHaveProperty('plan_file_path');
|
|
1395
1102
|
expect(response).toHaveProperty('instructions');
|
|
1396
|
-
expect(response).toHaveProperty('conversation_id');
|
|
1397
1103
|
|
|
1398
|
-
// VALIDATE: No plugin-specific fields
|
|
1399
1104
|
expect(response).not.toHaveProperty('_plugins');
|
|
1400
1105
|
expect(response).not.toHaveProperty('beads');
|
|
1401
1106
|
expect(response).not.toHaveProperty('taskBackendClient');
|
|
@@ -1434,7 +1139,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1434
1139
|
assertToolSuccess(result)
|
|
1435
1140
|
);
|
|
1436
1141
|
|
|
1437
|
-
// VALIDATE: Correct initial phase
|
|
1438
1142
|
expect(response.phase).toBe(WORKFLOW_INITIAL_PHASES.waterfall);
|
|
1439
1143
|
});
|
|
1440
1144
|
|
|
@@ -1454,7 +1158,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1454
1158
|
assertToolSuccess(result)
|
|
1455
1159
|
);
|
|
1456
1160
|
|
|
1457
|
-
// VALIDATE: Correct initial phase
|
|
1458
1161
|
expect(response.phase).toBe(WORKFLOW_INITIAL_PHASES.epcc);
|
|
1459
1162
|
});
|
|
1460
1163
|
|
|
@@ -1474,7 +1177,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1474
1177
|
assertToolSuccess(result)
|
|
1475
1178
|
);
|
|
1476
1179
|
|
|
1477
|
-
// VALIDATE: Correct initial phase
|
|
1478
1180
|
expect(response.phase).toBe(WORKFLOW_INITIAL_PHASES.tdd);
|
|
1479
1181
|
});
|
|
1480
1182
|
|
|
@@ -1494,7 +1196,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1494
1196
|
assertToolSuccess(result)
|
|
1495
1197
|
);
|
|
1496
1198
|
|
|
1497
|
-
// VALIDATE: Correct initial phase
|
|
1498
1199
|
expect(response.phase).toBe(WORKFLOW_INITIAL_PHASES.minor);
|
|
1499
1200
|
});
|
|
1500
1201
|
|
|
@@ -1514,7 +1215,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1514
1215
|
assertToolSuccess(result)
|
|
1515
1216
|
);
|
|
1516
1217
|
|
|
1517
|
-
// VALIDATE: Initial phase is one of expected options for bugfix
|
|
1518
1218
|
const expectedPhases = WORKFLOW_INITIAL_PHASES.bugfix;
|
|
1519
1219
|
expect(expectedPhases).toContain(response.phase);
|
|
1520
1220
|
});
|
|
@@ -1557,7 +1257,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1557
1257
|
assertToolSuccess(result)
|
|
1558
1258
|
);
|
|
1559
1259
|
|
|
1560
|
-
// VALIDATE: Instructions meet minimum length (substantive content)
|
|
1561
1260
|
expect(response.instructions.length).toBeGreaterThan(
|
|
1562
1261
|
MIN_INSTRUCTION_LENGTH
|
|
1563
1262
|
);
|
|
@@ -1575,7 +1274,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1575
1274
|
|
|
1576
1275
|
const planContent = await fs.readFile(response.plan_file_path, 'utf-8');
|
|
1577
1276
|
|
|
1578
|
-
// VALIDATE: Markdown structure
|
|
1579
1277
|
expect(planContent).toMatch(/^# /m); // Must have main title
|
|
1580
1278
|
expect(planContent).toMatch(/^## /m); // Must have sections
|
|
1581
1279
|
expect(planContent).not.toContain('[object Object]'); // No serialization errors
|
|
@@ -1593,7 +1291,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1593
1291
|
assertToolSuccess(startResult)
|
|
1594
1292
|
);
|
|
1595
1293
|
|
|
1596
|
-
// VALIDATE: Initial phase instructions mention phase name or key concepts
|
|
1597
1294
|
expect(startResponse.instructions).toMatch(/requirement|phase|task/i);
|
|
1598
1295
|
|
|
1599
1296
|
// Transition to design phase
|
|
@@ -1612,7 +1309,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1612
1309
|
assertToolSuccess(designWhatsNext)
|
|
1613
1310
|
);
|
|
1614
1311
|
|
|
1615
|
-
// VALIDATE: Design phase instructions are different and relevant
|
|
1616
1312
|
expect(designResponse.instructions).toBeDefined();
|
|
1617
1313
|
expect(designResponse.instructions.length).toBeGreaterThan(
|
|
1618
1314
|
MIN_INSTRUCTION_LENGTH
|
|
@@ -1668,7 +1364,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1668
1364
|
assertToolSuccess(whatsNextResult)
|
|
1669
1365
|
);
|
|
1670
1366
|
|
|
1671
|
-
// VALIDATE: Plan path unchanged
|
|
1672
1367
|
expect(whatsNextResponse.plan_file_path).toBe(planPath);
|
|
1673
1368
|
|
|
1674
1369
|
// Transition
|
|
@@ -1682,7 +1377,6 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1682
1377
|
assertToolSuccess(transitionResult)
|
|
1683
1378
|
);
|
|
1684
1379
|
|
|
1685
|
-
// VALIDATE: Plan path still unchanged
|
|
1686
1380
|
expect(transitionResponse.plan_file_path).toBe(planPath);
|
|
1687
1381
|
});
|
|
1688
1382
|
|
|
@@ -1718,10 +1412,8 @@ describe('Plugin System Integration Tests', () => {
|
|
|
1718
1412
|
'utf-8'
|
|
1719
1413
|
);
|
|
1720
1414
|
|
|
1721
|
-
// VALIDATE: File exists and has content
|
|
1722
1415
|
expect(finalContent.length).toBeGreaterThan(0);
|
|
1723
1416
|
|
|
1724
|
-
// VALIDATE: No corruption
|
|
1725
1417
|
expect(finalContent).not.toContain('[object Object]');
|
|
1726
1418
|
expect(finalContent).not.toContain('undefined');
|
|
1727
1419
|
});
|