@codemcp/workflows-core 3.1.22 → 3.2.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 (80) hide show
  1. package/package.json +8 -3
  2. package/resources/templates/architecture/arc42/arc42-template-EN.md +1077 -0
  3. package/resources/templates/architecture/arc42/images/01_2_iso-25010-topics-EN.drawio-2023.png +0 -0
  4. package/resources/templates/architecture/arc42/images/01_2_iso-25010-topics-EN.drawio.png +0 -0
  5. package/resources/templates/architecture/arc42/images/05_building_blocks-EN.png +0 -0
  6. package/resources/templates/architecture/arc42/images/08-concepts-EN.drawio.png +0 -0
  7. package/resources/templates/architecture/arc42/images/arc42-logo.png +0 -0
  8. package/resources/templates/architecture/c4.md +224 -0
  9. package/resources/templates/architecture/freestyle.md +53 -0
  10. package/resources/templates/architecture/none.md +17 -0
  11. package/resources/templates/design/comprehensive.md +207 -0
  12. package/resources/templates/design/freestyle.md +37 -0
  13. package/resources/templates/design/none.md +17 -0
  14. package/resources/templates/requirements/ears.md +90 -0
  15. package/resources/templates/requirements/freestyle.md +42 -0
  16. package/resources/templates/requirements/none.md +17 -0
  17. package/resources/workflows/big-bang-conversion.yaml +539 -0
  18. package/resources/workflows/boundary-testing.yaml +334 -0
  19. package/resources/workflows/bugfix.yaml +185 -0
  20. package/resources/workflows/business-analysis.yaml +671 -0
  21. package/resources/workflows/c4-analysis.yaml +485 -0
  22. package/resources/workflows/epcc.yaml +161 -0
  23. package/resources/workflows/greenfield.yaml +189 -0
  24. package/resources/workflows/minor.yaml +127 -0
  25. package/resources/workflows/posts.yaml +207 -0
  26. package/resources/workflows/slides.yaml +256 -0
  27. package/resources/workflows/tdd.yaml +157 -0
  28. package/resources/workflows/waterfall.yaml +195 -0
  29. package/.turbo/turbo-build.log +0 -4
  30. package/src/config-manager.ts +0 -96
  31. package/src/conversation-manager.ts +0 -489
  32. package/src/database.ts +0 -427
  33. package/src/file-detection-manager.ts +0 -302
  34. package/src/git-manager.ts +0 -64
  35. package/src/index.ts +0 -28
  36. package/src/instruction-generator.ts +0 -210
  37. package/src/interaction-logger.ts +0 -109
  38. package/src/logger.ts +0 -353
  39. package/src/path-validation-utils.ts +0 -261
  40. package/src/plan-manager.ts +0 -323
  41. package/src/project-docs-manager.ts +0 -523
  42. package/src/state-machine-loader.ts +0 -365
  43. package/src/state-machine-types.ts +0 -72
  44. package/src/state-machine.ts +0 -370
  45. package/src/system-prompt-generator.ts +0 -122
  46. package/src/template-manager.ts +0 -328
  47. package/src/transition-engine.ts +0 -386
  48. package/src/types.ts +0 -60
  49. package/src/workflow-manager.ts +0 -606
  50. package/test/unit/conversation-manager.test.ts +0 -179
  51. package/test/unit/custom-workflow-loading.test.ts +0 -174
  52. package/test/unit/directory-linking-and-extensions.test.ts +0 -338
  53. package/test/unit/file-linking-integration.test.ts +0 -256
  54. package/test/unit/git-commit-integration.test.ts +0 -91
  55. package/test/unit/git-manager.test.ts +0 -86
  56. package/test/unit/install-workflow.test.ts +0 -138
  57. package/test/unit/instruction-generator.test.ts +0 -247
  58. package/test/unit/list-workflows-filtering.test.ts +0 -68
  59. package/test/unit/none-template-functionality.test.ts +0 -224
  60. package/test/unit/project-docs-manager.test.ts +0 -337
  61. package/test/unit/state-machine-loader.test.ts +0 -234
  62. package/test/unit/template-manager.test.ts +0 -217
  63. package/test/unit/validate-workflow-name.test.ts +0 -150
  64. package/test/unit/workflow-domain-filtering.test.ts +0 -75
  65. package/test/unit/workflow-enum-generation.test.ts +0 -92
  66. package/test/unit/workflow-manager-enhanced-path-resolution.test.ts +0 -369
  67. package/test/unit/workflow-manager-path-resolution.test.ts +0 -150
  68. package/test/unit/workflow-migration.test.ts +0 -155
  69. package/test/unit/workflow-override-by-name.test.ts +0 -116
  70. package/test/unit/workflow-prioritization.test.ts +0 -38
  71. package/test/unit/workflow-validation.test.ts +0 -303
  72. package/test/utils/e2e-test-setup.ts +0 -453
  73. package/test/utils/run-server-in-dir.sh +0 -27
  74. package/test/utils/temp-files.ts +0 -308
  75. package/test/utils/test-access.ts +0 -79
  76. package/test/utils/test-helpers.ts +0 -286
  77. package/test/utils/test-setup.ts +0 -78
  78. package/tsconfig.build.json +0 -21
  79. package/tsconfig.json +0 -8
  80. package/vitest.config.ts +0 -18
@@ -1,365 +0,0 @@
1
- /**
2
- * State Machine Loader
3
- *
4
- * Loads and validates YAML-based state machine definitions
5
- */
6
-
7
- import fs from 'node:fs';
8
- import yaml from 'js-yaml';
9
- import path from 'node:path';
10
- import { fileURLToPath } from 'node:url';
11
- import { createRequire } from 'node:module';
12
- import { createLogger } from './logger.js';
13
- import { YamlStateMachine, YamlTransition } from './state-machine-types.js';
14
-
15
- const logger = createLogger('StateMachineLoader');
16
-
17
- /**
18
- * Loads and manages YAML-based state machine definitions
19
- */
20
- export class StateMachineLoader {
21
- private stateMachine: YamlStateMachine | null = null;
22
- private validPhases: Set<string> = new Set();
23
-
24
- /**
25
- * Get all valid phases from the loaded state machine
26
- */
27
- public getValidPhases(): string[] {
28
- if (!this.stateMachine) {
29
- throw new Error('State machine not loaded');
30
- }
31
- return Array.from(this.validPhases);
32
- }
33
-
34
- /**
35
- * Get the initial state from the loaded state machine
36
- */
37
- public getInitialState(): string {
38
- if (!this.stateMachine) {
39
- throw new Error('State machine not loaded');
40
- }
41
- return this.stateMachine.initial_state;
42
- }
43
-
44
- /**
45
- * Load state machine from YAML file
46
- *
47
- * Checks for custom state machine file in project directory first,
48
- * then falls back to waterfall workflow as default
49
- */
50
- public loadStateMachine(projectPath: string): YamlStateMachine {
51
- // Check for custom state machine file in project directory
52
- const customFilePaths = [
53
- path.join(projectPath, '.vibe', 'workflow.yaml'),
54
- path.join(projectPath, '.vibe', 'workflow.yml'),
55
- ];
56
-
57
- // Try to load custom state machine file
58
- for (const filePath of customFilePaths) {
59
- if (fs.existsSync(filePath)) {
60
- logger.info('Loading custom state machine file', { filePath });
61
- try {
62
- return this.loadFromFile(filePath);
63
- } catch (error) {
64
- logger.warn(
65
- 'Failed to load custom state machine, falling back to default',
66
- {
67
- filePath,
68
- error: (error as Error).message,
69
- }
70
- );
71
- // Continue to try next file or fall back to default
72
- }
73
- }
74
- }
75
-
76
- // Fall back to waterfall workflow as default
77
- const defaultFilePath = this.resolveWorkflowPath('waterfall.yaml');
78
-
79
- logger.info('Loading default state machine file', { defaultFilePath });
80
- return this.loadFromFile(defaultFilePath);
81
- }
82
-
83
- /**
84
- * Resolve workflow path using similar strategy as TemplateManager
85
- */
86
- private resolveWorkflowPath(filename: string): string {
87
- const strategies: string[] = [];
88
-
89
- // Strategy 1: Local resources directory (symlinked from root)
90
- strategies.push(
91
- path.join(
92
- path.dirname(fileURLToPath(import.meta.url)),
93
- '../resources/workflows',
94
- filename
95
- )
96
- );
97
-
98
- // Strategy 2: From compiled dist directory
99
- const currentFileUrl = import.meta.url;
100
- if (currentFileUrl.startsWith('file://')) {
101
- const currentFilePath = fileURLToPath(currentFileUrl);
102
- // From dist/state-machine-loader.js -> ../resources/workflows
103
- strategies.push(
104
- path.join(
105
- path.dirname(currentFilePath),
106
- '../resources/workflows',
107
- filename
108
- )
109
- );
110
- }
111
-
112
- // Strategy 3: Current working directory (for development)
113
- strategies.push(path.join(process.cwd(), 'resources/workflows', filename));
114
-
115
- // Strategy 4: From node_modules
116
- strategies.push(
117
- path.join(
118
- process.cwd(),
119
- 'node_modules/@codemcp/workflows-core/resources/workflows',
120
- filename
121
- )
122
- );
123
-
124
- // Strategy 5: From package directory (for development)
125
- try {
126
- const require = createRequire(import.meta.url);
127
- const packagePath = require.resolve(
128
- '@codemcp/workflows-core/package.json'
129
- );
130
- const packageDir = path.dirname(packagePath);
131
- strategies.push(path.join(packageDir, 'resources/workflows', filename));
132
- } catch (_error) {
133
- // Ignore if package not found
134
- }
135
-
136
- // Find the first existing path
137
- for (const strategy of strategies) {
138
- try {
139
- // This will throw if path doesn't exist
140
- fs.accessSync(strategy);
141
- logger.debug('Using workflow path', { path: strategy });
142
- return strategy;
143
- } catch (_error) {
144
- // Continue to next strategy
145
- }
146
- }
147
-
148
- // Fallback to first strategy if none found
149
- const fallback = strategies[0];
150
- logger.warn('No workflow path found, using fallback', { path: fallback });
151
- return fallback;
152
- }
153
-
154
- public loadFromFile(filePath: string): YamlStateMachine {
155
- try {
156
- const yamlContent = fs.readFileSync(path.resolve(filePath), 'utf8');
157
- const stateMachine = yaml.load(yamlContent) as YamlStateMachine;
158
-
159
- // Validate the state machine
160
- this.validateStateMachine(stateMachine);
161
-
162
- // Store valid phases for later validation
163
- this.validPhases = new Set(Object.keys(stateMachine.states));
164
-
165
- this.stateMachine = stateMachine;
166
- logger.info('State machine loaded successfully', {
167
- name: stateMachine.name,
168
- stateCount: Object.keys(stateMachine.states).length,
169
- phases: Array.from(this.validPhases),
170
- });
171
-
172
- return stateMachine;
173
- } catch (error) {
174
- logger.error('Failed to load state machine', error as Error);
175
- throw new Error(
176
- `Failed to load state machine: ${(error as Error).message}`
177
- );
178
- }
179
- }
180
-
181
- /**
182
- * Validate the state machine structure and references
183
- */
184
- private validateStateMachine(stateMachine: YamlStateMachine): void {
185
- // Check required properties
186
- if (
187
- !stateMachine.name ||
188
- !stateMachine.description ||
189
- !stateMachine.initial_state ||
190
- !stateMachine.states
191
- ) {
192
- throw new Error('State machine is missing required properties');
193
- }
194
-
195
- // Get all state names
196
- const stateNames = Object.keys(stateMachine.states);
197
-
198
- // Check initial state is valid
199
- if (!stateNames.includes(stateMachine.initial_state)) {
200
- throw new Error(
201
- `Initial state "${stateMachine.initial_state}" is not defined in states`
202
- );
203
- }
204
-
205
- // Validate states and transitions
206
- for (const [stateName, state] of Object.entries(stateMachine.states)) {
207
- // Check required state properties
208
- if (!state.description || !state.default_instructions) {
209
- throw new Error(
210
- `State "${stateName}" is missing required properties (description or default_instructions)`
211
- );
212
- }
213
-
214
- if (!state.transitions || !Array.isArray(state.transitions)) {
215
- throw new Error(
216
- `State "${stateName}" has invalid transitions property`
217
- );
218
- }
219
-
220
- for (const transition of state.transitions) {
221
- if (!stateNames.includes(transition.to)) {
222
- throw new Error(
223
- `State "${stateName}" has transition to unknown state "${transition.to}"`
224
- );
225
- }
226
-
227
- if (!transition.transition_reason) {
228
- throw new Error(
229
- `Transition from "${stateName}" to "${transition.to}" is missing transition_reason`
230
- );
231
- }
232
- }
233
- }
234
-
235
- logger.debug('State machine validation successful');
236
- }
237
-
238
- /**
239
- * Get transition instructions for a specific state change
240
- */
241
- public getTransitionInstructions(
242
- fromState: string,
243
- toState: string,
244
- trigger?: string
245
- ): { instructions: string; transitionReason: string; isModeled: boolean } {
246
- if (!this.stateMachine) {
247
- throw new Error('State machine not loaded');
248
- }
249
-
250
- // Get target state definition
251
- const targetState = this.stateMachine.states[toState];
252
- if (!targetState) {
253
- throw new Error(`Target state "${toState}" not found`);
254
- }
255
-
256
- // Look for a modeled transition first
257
- const fromStateDefinition = this.stateMachine.states[fromState];
258
- if (fromStateDefinition) {
259
- const transition = fromStateDefinition.transitions.find(
260
- t => t.to === toState && (!trigger || t.trigger === trigger)
261
- );
262
-
263
- if (transition) {
264
- // For modeled transitions, compose instructions
265
- let composedInstructions = targetState.default_instructions;
266
-
267
- // If transition has specific instructions, use those instead of default
268
- if (transition.instructions) {
269
- composedInstructions = transition.instructions;
270
- }
271
-
272
- // If transition has additional instructions, combine them
273
- if (transition.additional_instructions) {
274
- composedInstructions = `${composedInstructions}\n\n**Additional Context:**\n${transition.additional_instructions}`;
275
- }
276
-
277
- return {
278
- instructions: composedInstructions,
279
- transitionReason: transition.transition_reason,
280
- isModeled: true,
281
- };
282
- }
283
- }
284
-
285
- // Fall back to target state's default instructions for unmodeled transitions
286
- return {
287
- instructions: targetState.default_instructions,
288
- transitionReason: `Direct transition to ${toState} phase`,
289
- isModeled: false,
290
- };
291
- }
292
-
293
- /**
294
- * Get all possible transitions from a given state
295
- */
296
- public getPossibleTransitions(fromState: string): YamlTransition[] {
297
- if (!this.stateMachine) {
298
- throw new Error('State machine not loaded');
299
- }
300
-
301
- const stateDefinition = this.stateMachine.states[fromState];
302
- return stateDefinition ? stateDefinition.transitions : [];
303
- }
304
-
305
- /**
306
- * Check if a transition is modeled (shown in state diagram)
307
- */
308
- public isModeledTransition(fromState: string, toState: string): boolean {
309
- if (!this.stateMachine) {
310
- throw new Error('State machine not loaded');
311
- }
312
-
313
- const stateDefinition = this.stateMachine.states[fromState];
314
- if (!stateDefinition) return false;
315
-
316
- return stateDefinition.transitions.some(t => t.to === toState);
317
- }
318
-
319
- /**
320
- * Check if a phase is valid in the current state machine
321
- */
322
- public isValidPhase(phase: string): boolean {
323
- return this.validPhases.has(phase);
324
- }
325
-
326
- /**
327
- * Get phase-specific instructions for continuing work in current phase
328
- */
329
- public getContinuePhaseInstructions(phase: string): string {
330
- if (!this.stateMachine) {
331
- throw new Error('State machine not loaded');
332
- }
333
-
334
- const stateDefinition = this.stateMachine.states[phase];
335
- if (!stateDefinition) {
336
- logger.error('Unknown phase', new Error(`Unknown phase: ${phase}`));
337
- throw new Error(`Unknown phase: ${phase}`);
338
- }
339
-
340
- // Look for a self-transition (continue in same phase)
341
- const continueTransition = stateDefinition.transitions.find(
342
- t => t.to === phase
343
- );
344
-
345
- if (continueTransition) {
346
- // Compose instructions for continue transition
347
- let composedInstructions = stateDefinition.default_instructions;
348
-
349
- // If transition has specific instructions, use those instead of default
350
- if (continueTransition.instructions) {
351
- composedInstructions = continueTransition.instructions;
352
- }
353
-
354
- // If transition has additional instructions, combine them
355
- if (continueTransition.additional_instructions) {
356
- composedInstructions = `${composedInstructions}\n\n**Additional Context:**\n${continueTransition.additional_instructions}`;
357
- }
358
-
359
- return composedInstructions;
360
- }
361
-
362
- // Fall back to default instructions for the phase
363
- return stateDefinition.default_instructions;
364
- }
365
- }
@@ -1,72 +0,0 @@
1
- /**
2
- * State Machine Types
3
- *
4
- * Type definitions for YAML-based state machine
5
- */
6
-
7
- /**
8
- * Transition between states
9
- */
10
- export interface YamlTransition {
11
- /** Event that triggers this transition */
12
- trigger: string;
13
-
14
- /** Target state after transition */
15
- to: string;
16
-
17
- /** Instructions to provide when this transition occurs (optional - uses target state default if not provided) */
18
- instructions?: string;
19
-
20
- /** Additional instructions to combine with target state's default instructions (optional) */
21
- additional_instructions?: string;
22
-
23
- /** Reason for this transition */
24
- transition_reason: string;
25
-
26
- /** Optional review perspectives for this transition */
27
- review_perspectives?: Array<{
28
- perspective: string;
29
- prompt: string;
30
- }>;
31
- }
32
-
33
- /**
34
- * State definition
35
- */
36
- export interface YamlState {
37
- /** Description of this state */
38
- description: string;
39
-
40
- /** Default instructions when entering this state */
41
- default_instructions: string;
42
-
43
- /** Transitions from this state */
44
- transitions: YamlTransition[];
45
- }
46
-
47
- /**
48
- * Complete state machine definition
49
- */
50
- export interface YamlStateMachine {
51
- /** Name of the state machine */
52
- name: string;
53
-
54
- /** Description of the state machine's purpose */
55
- description: string;
56
-
57
- /** The starting state of the machine */
58
- initial_state: string;
59
-
60
- /** Map of states in the state machine */
61
- states: Record<string, YamlState>;
62
-
63
- /** Optional metadata for enhanced discoverability */
64
- metadata?: {
65
- complexity?: 'low' | 'medium' | 'high';
66
- domain: string;
67
- bestFor?: string[];
68
- useCases?: string[];
69
- examples?: string[];
70
- requiresDocumentation?: boolean;
71
- };
72
- }