@codemcp/workflows-core 3.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/LICENSE +674 -0
  3. package/dist/config-manager.d.ts +24 -0
  4. package/dist/config-manager.js +68 -0
  5. package/dist/config-manager.js.map +1 -0
  6. package/dist/conversation-manager.d.ts +97 -0
  7. package/dist/conversation-manager.js +367 -0
  8. package/dist/conversation-manager.js.map +1 -0
  9. package/dist/database.d.ts +73 -0
  10. package/dist/database.js +500 -0
  11. package/dist/database.js.map +1 -0
  12. package/dist/file-detection-manager.d.ts +53 -0
  13. package/dist/file-detection-manager.js +221 -0
  14. package/dist/file-detection-manager.js.map +1 -0
  15. package/dist/git-manager.d.ts +14 -0
  16. package/dist/git-manager.js +59 -0
  17. package/dist/git-manager.js.map +1 -0
  18. package/dist/index.d.ts +19 -0
  19. package/dist/index.js +25 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/instruction-generator.d.ts +69 -0
  22. package/dist/instruction-generator.js +133 -0
  23. package/dist/instruction-generator.js.map +1 -0
  24. package/dist/interaction-logger.d.ts +37 -0
  25. package/dist/interaction-logger.js +87 -0
  26. package/dist/interaction-logger.js.map +1 -0
  27. package/dist/logger.d.ts +64 -0
  28. package/dist/logger.js +283 -0
  29. package/dist/logger.js.map +1 -0
  30. package/dist/path-validation-utils.d.ts +51 -0
  31. package/dist/path-validation-utils.js +202 -0
  32. package/dist/path-validation-utils.js.map +1 -0
  33. package/dist/plan-manager.d.ts +65 -0
  34. package/dist/plan-manager.js +256 -0
  35. package/dist/plan-manager.js.map +1 -0
  36. package/dist/project-docs-manager.d.ts +119 -0
  37. package/dist/project-docs-manager.js +357 -0
  38. package/dist/project-docs-manager.js.map +1 -0
  39. package/dist/state-machine-loader.d.ts +60 -0
  40. package/dist/state-machine-loader.js +235 -0
  41. package/dist/state-machine-loader.js.map +1 -0
  42. package/dist/state-machine-types.d.ts +58 -0
  43. package/dist/state-machine-types.js +7 -0
  44. package/dist/state-machine-types.js.map +1 -0
  45. package/dist/state-machine.d.ts +52 -0
  46. package/dist/state-machine.js +256 -0
  47. package/dist/state-machine.js.map +1 -0
  48. package/dist/system-prompt-generator.d.ts +17 -0
  49. package/dist/system-prompt-generator.js +113 -0
  50. package/dist/system-prompt-generator.js.map +1 -0
  51. package/dist/template-manager.d.ts +61 -0
  52. package/dist/template-manager.js +229 -0
  53. package/dist/template-manager.js.map +1 -0
  54. package/dist/transition-engine.d.ts +70 -0
  55. package/dist/transition-engine.js +240 -0
  56. package/dist/transition-engine.js.map +1 -0
  57. package/dist/types.d.ts +56 -0
  58. package/dist/types.js +5 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/workflow-manager.d.ts +89 -0
  61. package/dist/workflow-manager.js +466 -0
  62. package/dist/workflow-manager.js.map +1 -0
  63. package/package.json +27 -0
  64. package/src/config-manager.ts +96 -0
  65. package/src/conversation-manager.ts +492 -0
  66. package/src/database.ts +685 -0
  67. package/src/file-detection-manager.ts +302 -0
  68. package/src/git-manager.ts +64 -0
  69. package/src/index.ts +28 -0
  70. package/src/instruction-generator.ts +210 -0
  71. package/src/interaction-logger.ts +109 -0
  72. package/src/logger.ts +353 -0
  73. package/src/path-validation-utils.ts +261 -0
  74. package/src/plan-manager.ts +323 -0
  75. package/src/project-docs-manager.ts +522 -0
  76. package/src/state-machine-loader.ts +308 -0
  77. package/src/state-machine-types.ts +72 -0
  78. package/src/state-machine.ts +370 -0
  79. package/src/system-prompt-generator.ts +122 -0
  80. package/src/template-manager.ts +321 -0
  81. package/src/transition-engine.ts +386 -0
  82. package/src/types.ts +60 -0
  83. package/src/workflow-manager.ts +601 -0
  84. package/test/unit/conversation-manager.test.ts +179 -0
  85. package/test/unit/custom-workflow-loading.test.ts +174 -0
  86. package/test/unit/directory-linking-and-extensions.test.ts +338 -0
  87. package/test/unit/file-linking-integration.test.ts +256 -0
  88. package/test/unit/git-commit-integration.test.ts +91 -0
  89. package/test/unit/git-manager.test.ts +86 -0
  90. package/test/unit/install-workflow.test.ts +138 -0
  91. package/test/unit/instruction-generator.test.ts +247 -0
  92. package/test/unit/list-workflows-filtering.test.ts +68 -0
  93. package/test/unit/none-template-functionality.test.ts +224 -0
  94. package/test/unit/project-docs-manager.test.ts +337 -0
  95. package/test/unit/state-machine-loader.test.ts +234 -0
  96. package/test/unit/template-manager.test.ts +217 -0
  97. package/test/unit/validate-workflow-name.test.ts +150 -0
  98. package/test/unit/workflow-domain-filtering.test.ts +75 -0
  99. package/test/unit/workflow-enum-generation.test.ts +92 -0
  100. package/test/unit/workflow-manager-enhanced-path-resolution.test.ts +369 -0
  101. package/test/unit/workflow-manager-path-resolution.test.ts +150 -0
  102. package/test/unit/workflow-migration.test.ts +155 -0
  103. package/test/unit/workflow-override-by-name.test.ts +116 -0
  104. package/test/unit/workflow-prioritization.test.ts +38 -0
  105. package/test/unit/workflow-validation.test.ts +303 -0
  106. package/test/utils/e2e-test-setup.ts +453 -0
  107. package/test/utils/run-server-in-dir.sh +27 -0
  108. package/test/utils/temp-files.ts +308 -0
  109. package/test/utils/test-access.ts +79 -0
  110. package/test/utils/test-helpers.ts +286 -0
  111. package/test/utils/test-setup.ts +78 -0
  112. package/tsconfig.build.json +21 -0
  113. package/tsconfig.json +8 -0
  114. package/vitest.config.ts +18 -0
@@ -0,0 +1,357 @@
1
+ /**
2
+ * Project Docs Manager
3
+ *
4
+ * Manages project documentation artifacts (architecture.md, requirements.md, design.md)
5
+ * separate from the workflow-specific plan files. Handles creation, validation, and
6
+ * path resolution for project documents. Now supports both template creation and
7
+ * file linking via symlinks.
8
+ */
9
+ import { writeFile, access, mkdir, unlink, symlink, lstat, stat, readdir, } from 'node:fs/promises';
10
+ import { join, dirname, relative, extname, basename } from 'node:path';
11
+ import { createLogger } from './logger.js';
12
+ import { TemplateManager } from './template-manager.js';
13
+ const logger = createLogger('ProjectDocsManager');
14
+ export class ProjectDocsManager {
15
+ templateManager; // Make public for access from other classes
16
+ constructor() {
17
+ this.templateManager = new TemplateManager();
18
+ }
19
+ /**
20
+ * Get project docs directory path
21
+ */
22
+ getDocsPath(projectPath) {
23
+ return join(projectPath, '.vibe', 'docs');
24
+ }
25
+ /**
26
+ * Determine the appropriate extension for a document based on source path
27
+ */
28
+ async getDocumentExtension(sourcePath) {
29
+ if (!sourcePath) {
30
+ return '.md'; // Default for templates
31
+ }
32
+ try {
33
+ const stats = await stat(sourcePath);
34
+ if (stats.isDirectory()) {
35
+ return ''; // No extension for directories
36
+ }
37
+ // For files, preserve the original extension
38
+ const ext = extname(sourcePath);
39
+ return ext || '.md'; // Default to .md if no extension
40
+ }
41
+ catch (_error) {
42
+ return '.md'; // Default if we can't stat the source
43
+ }
44
+ }
45
+ /**
46
+ * Get the target filename for a document type
47
+ */
48
+ async getDocumentFilename(type, sourcePath) {
49
+ const extension = await this.getDocumentExtension(sourcePath);
50
+ // Always use the standardized document type name
51
+ // This ensures consistent symlink names regardless of source path
52
+ return extension === '' ? type : `${type}${extension}`;
53
+ }
54
+ /**
55
+ * Get paths for all project documents
56
+ */
57
+ getDocumentPaths(projectPath) {
58
+ const docsPath = this.getDocsPath(projectPath);
59
+ return {
60
+ architecture: join(docsPath, 'architecture.md'),
61
+ requirements: join(docsPath, 'requirements.md'),
62
+ design: join(docsPath, 'design.md'),
63
+ };
64
+ }
65
+ /**
66
+ * Get paths for all project documents with dynamic extensions based on source paths
67
+ */
68
+ async getDocumentPathsWithExtensions(projectPath, sourcePaths) {
69
+ const docsPath = this.getDocsPath(projectPath);
70
+ const archFilename = await this.getDocumentFilename('architecture', sourcePaths?.architecture);
71
+ const reqFilename = await this.getDocumentFilename('requirements', sourcePaths?.requirements);
72
+ const designFilename = await this.getDocumentFilename('design', sourcePaths?.design);
73
+ return {
74
+ architecture: join(docsPath, archFilename),
75
+ requirements: join(docsPath, reqFilename),
76
+ design: join(docsPath, designFilename),
77
+ };
78
+ }
79
+ /**
80
+ * Check which project documents exist
81
+ */
82
+ async getProjectDocsInfo(projectPath) {
83
+ const paths = this.getDocumentPaths(projectPath);
84
+ const checkExists = async (path) => {
85
+ try {
86
+ await access(path);
87
+ return true;
88
+ }
89
+ catch (_error) {
90
+ return false;
91
+ }
92
+ };
93
+ // Check for documents with different extensions using simple logic
94
+ const checkExistsWithExtensions = async (basePath, docType) => {
95
+ // First check the default .md path
96
+ if (await checkExists(basePath)) {
97
+ return { exists: true, actualPath: basePath };
98
+ }
99
+ // Check for the document type with any extension or as directory
100
+ const docsDir = dirname(basePath);
101
+ try {
102
+ const entries = await readdir(docsDir);
103
+ // Look for entries that match the document type exactly or start with it
104
+ for (const entry of entries) {
105
+ const entryWithoutExt = entry.replace(/\.[^/.]+$/, '');
106
+ if (entryWithoutExt === docType || entry === docType) {
107
+ const entryPath = join(docsDir, entry);
108
+ if (await checkExists(entryPath)) {
109
+ return { exists: true, actualPath: entryPath };
110
+ }
111
+ }
112
+ }
113
+ }
114
+ catch (_error) {
115
+ // Directory might not exist yet
116
+ }
117
+ return { exists: false, actualPath: basePath };
118
+ };
119
+ const archResult = await checkExistsWithExtensions(paths.architecture, 'architecture');
120
+ const reqResult = await checkExistsWithExtensions(paths.requirements, 'requirements');
121
+ const designResult = await checkExistsWithExtensions(paths.design, 'design');
122
+ return {
123
+ architecture: {
124
+ path: archResult.actualPath,
125
+ exists: archResult.exists,
126
+ },
127
+ requirements: {
128
+ path: reqResult.actualPath,
129
+ exists: reqResult.exists,
130
+ },
131
+ design: {
132
+ path: designResult.actualPath,
133
+ exists: designResult.exists,
134
+ },
135
+ };
136
+ }
137
+ /**
138
+ * Create project documents using templates (legacy method for backward compatibility)
139
+ */
140
+ async createProjectDocs(projectPath, options) {
141
+ const result = await this.createOrLinkProjectDocs(projectPath, options, {});
142
+ return {
143
+ created: result.created,
144
+ skipped: result.skipped,
145
+ };
146
+ }
147
+ /**
148
+ * Create or link project documents using templates and/or file paths
149
+ */
150
+ async createOrLinkProjectDocs(projectPath, templateOptions, filePaths) {
151
+ const defaults = await this.templateManager.getDefaults();
152
+ const finalTemplateOptions = { ...defaults, ...templateOptions };
153
+ const docsPath = this.getDocsPath(projectPath);
154
+ // Use dynamic paths that consider source file extensions
155
+ const paths = await this.getDocumentPathsWithExtensions(projectPath, filePaths);
156
+ // Check existing documents using the old static paths for backward compatibility
157
+ const info = await this.getProjectDocsInfo(projectPath);
158
+ // Ensure docs directory exists
159
+ await mkdir(docsPath, { recursive: true });
160
+ const created = [];
161
+ const linked = [];
162
+ const skipped = [];
163
+ // Handle architecture document
164
+ if (!info.architecture.exists) {
165
+ if (filePaths?.architecture) {
166
+ await this.createSymlink(filePaths.architecture, paths.architecture);
167
+ const filename = basename(paths.architecture);
168
+ linked.push(filename);
169
+ }
170
+ else {
171
+ await this.createDocument('architecture', finalTemplateOptions.architecture, paths.architecture, docsPath);
172
+ const filename = basename(paths.architecture);
173
+ created.push(filename);
174
+ }
175
+ }
176
+ else {
177
+ skipped.push('architecture.md');
178
+ }
179
+ // Handle requirements document
180
+ if (!info.requirements.exists) {
181
+ if (filePaths?.requirements) {
182
+ await this.createSymlink(filePaths.requirements, paths.requirements);
183
+ const filename = basename(paths.requirements);
184
+ linked.push(filename);
185
+ }
186
+ else {
187
+ await this.createDocument('requirements', finalTemplateOptions.requirements, paths.requirements, docsPath);
188
+ const filename = basename(paths.requirements);
189
+ created.push(filename);
190
+ }
191
+ }
192
+ else {
193
+ skipped.push('requirements.md');
194
+ }
195
+ // Handle design document
196
+ if (!info.design.exists) {
197
+ if (filePaths?.design) {
198
+ await this.createSymlink(filePaths.design, paths.design);
199
+ const filename = basename(paths.design);
200
+ linked.push(filename);
201
+ }
202
+ else {
203
+ await this.createDocument('design', finalTemplateOptions.design, paths.design, docsPath);
204
+ const filename = basename(paths.design);
205
+ created.push(filename);
206
+ }
207
+ }
208
+ else {
209
+ skipped.push('design.md');
210
+ }
211
+ logger.info('Project docs creation/linking completed', {
212
+ created,
213
+ linked,
214
+ skipped,
215
+ projectPath,
216
+ templateOptions: finalTemplateOptions,
217
+ filePaths,
218
+ });
219
+ return { created, linked, skipped };
220
+ }
221
+ /**
222
+ * Create a symlink to an existing file
223
+ */
224
+ async createSymlink(sourcePath, targetPath) {
225
+ try {
226
+ // Remove existing file/symlink if it exists
227
+ await this.removeExistingDocument(targetPath);
228
+ // Create relative symlink for better portability
229
+ const targetDir = dirname(targetPath);
230
+ const relativePath = relative(targetDir, sourcePath);
231
+ await symlink(relativePath, targetPath);
232
+ logger.debug('Symlink created successfully', {
233
+ sourcePath,
234
+ targetPath,
235
+ relativePath,
236
+ });
237
+ }
238
+ catch (error) {
239
+ logger.error('Failed to create symlink', error, {
240
+ sourcePath,
241
+ targetPath,
242
+ });
243
+ throw new Error(`Failed to create symlink: ${error instanceof Error ? error.message : 'Unknown error'}`);
244
+ }
245
+ }
246
+ /**
247
+ * Remove existing document or symlink
248
+ */
249
+ async removeExistingDocument(documentPath) {
250
+ try {
251
+ const stats = await lstat(documentPath);
252
+ await unlink(documentPath);
253
+ logger.debug('Existing document removed', {
254
+ documentPath,
255
+ wasSymlink: stats.isSymbolicLink(),
256
+ });
257
+ }
258
+ catch (error) {
259
+ // File doesn't exist, which is fine
260
+ if (error instanceof Error &&
261
+ 'code' in error &&
262
+ error.code !== 'ENOENT') {
263
+ logger.debug('Failed to remove existing document', {
264
+ documentPath,
265
+ error: error instanceof Error ? error.message : 'Unknown error',
266
+ });
267
+ }
268
+ }
269
+ }
270
+ /**
271
+ * Create a single document from template
272
+ */
273
+ async createDocument(type, template, documentPath, docsPath) {
274
+ try {
275
+ const templateResult = await this.templateManager.loadTemplate(type, template);
276
+ // Write the main document
277
+ await writeFile(documentPath, templateResult.content, 'utf-8');
278
+ // Write additional files (like images for arc42)
279
+ if (templateResult.additionalFiles) {
280
+ for (const file of templateResult.additionalFiles) {
281
+ const filePath = join(docsPath, file.relativePath);
282
+ const fileDir = dirname(filePath);
283
+ // Ensure directory exists
284
+ await mkdir(fileDir, { recursive: true });
285
+ // Write file
286
+ await writeFile(filePath, file.content);
287
+ }
288
+ }
289
+ logger.debug(`Created ${type} document`, { documentPath, template });
290
+ }
291
+ catch (error) {
292
+ logger.error(`Failed to create ${type} document`, error, {
293
+ documentPath,
294
+ template,
295
+ });
296
+ throw error;
297
+ }
298
+ }
299
+ /**
300
+ * Get variable substitutions for workflow instructions
301
+ */
302
+ getVariableSubstitutions(projectPath) {
303
+ const paths = this.getDocumentPaths(projectPath);
304
+ return {
305
+ $ARCHITECTURE_DOC: paths.architecture,
306
+ $REQUIREMENTS_DOC: paths.requirements,
307
+ $DESIGN_DOC: paths.design,
308
+ };
309
+ }
310
+ /**
311
+ * Get variable substitutions for workflow instructions with dynamic paths
312
+ */
313
+ async getVariableSubstitutionsWithExtensions(projectPath, sourcePaths) {
314
+ const paths = await this.getDocumentPathsWithExtensions(projectPath, sourcePaths);
315
+ return {
316
+ $ARCHITECTURE_DOC: paths.architecture,
317
+ $REQUIREMENTS_DOC: paths.requirements,
318
+ $DESIGN_DOC: paths.design,
319
+ };
320
+ }
321
+ /**
322
+ * Read a project document - returns the path for LLM to read as needed
323
+ */
324
+ async readDocument(projectPath, type) {
325
+ // Use the dynamic path detection to get the actual document path
326
+ const docsInfo = await this.getProjectDocsInfo(projectPath);
327
+ const documentPath = docsInfo[type].path;
328
+ if (!docsInfo[type].exists) {
329
+ throw new Error(`${type} document not found: ${documentPath}`);
330
+ }
331
+ // Return the pure path for the LLM to read as needed
332
+ // This is more efficient for large documents and gives LLM full control
333
+ return documentPath;
334
+ }
335
+ /**
336
+ * Check if all project documents exist
337
+ */
338
+ async allDocumentsExist(projectPath) {
339
+ const info = await this.getProjectDocsInfo(projectPath);
340
+ return (info.architecture.exists && info.requirements.exists && info.design.exists);
341
+ }
342
+ /**
343
+ * Check if a document is a symlink
344
+ */
345
+ async isSymlink(projectPath, type) {
346
+ const paths = this.getDocumentPaths(projectPath);
347
+ const documentPath = paths[type];
348
+ try {
349
+ const stats = await lstat(documentPath);
350
+ return stats.isSymbolicLink();
351
+ }
352
+ catch (_error) {
353
+ return false;
354
+ }
355
+ }
356
+ }
357
+ //# sourceMappingURL=project-docs-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-docs-manager.js","sourceRoot":"","sources":["../src/project-docs-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * State Machine Loader
3
+ *
4
+ * Loads and validates YAML-based state machine definitions
5
+ */
6
+ import { YamlStateMachine, YamlTransition } from './state-machine-types.js';
7
+ /**
8
+ * Loads and manages YAML-based state machine definitions
9
+ */
10
+ export declare class StateMachineLoader {
11
+ private stateMachine;
12
+ private validPhases;
13
+ /**
14
+ * Get all valid phases from the loaded state machine
15
+ */
16
+ getValidPhases(): string[];
17
+ /**
18
+ * Get the initial state from the loaded state machine
19
+ */
20
+ getInitialState(): string;
21
+ /**
22
+ * Load state machine from YAML file
23
+ *
24
+ * Checks for custom state machine file in project directory first,
25
+ * then falls back to waterfall workflow as default
26
+ */
27
+ loadStateMachine(projectPath: string): YamlStateMachine;
28
+ /**
29
+ * Load state machine from specific file path
30
+ */
31
+ loadFromFile(filePath: string): YamlStateMachine;
32
+ /**
33
+ * Validate the state machine structure and references
34
+ */
35
+ private validateStateMachine;
36
+ /**
37
+ * Get transition instructions for a specific state change
38
+ */
39
+ getTransitionInstructions(fromState: string, toState: string, trigger?: string): {
40
+ instructions: string;
41
+ transitionReason: string;
42
+ isModeled: boolean;
43
+ };
44
+ /**
45
+ * Get all possible transitions from a given state
46
+ */
47
+ getPossibleTransitions(fromState: string): YamlTransition[];
48
+ /**
49
+ * Check if a transition is modeled (shown in state diagram)
50
+ */
51
+ isModeledTransition(fromState: string, toState: string): boolean;
52
+ /**
53
+ * Check if a phase is valid in the current state machine
54
+ */
55
+ isValidPhase(phase: string): boolean;
56
+ /**
57
+ * Get phase-specific instructions for continuing work in current phase
58
+ */
59
+ getContinuePhaseInstructions(phase: string): string;
60
+ }
@@ -0,0 +1,235 @@
1
+ /**
2
+ * State Machine Loader
3
+ *
4
+ * Loads and validates YAML-based state machine definitions
5
+ */
6
+ import fs from 'node:fs';
7
+ import yaml from 'js-yaml';
8
+ import path from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+ import { createLogger } from './logger.js';
11
+ const logger = createLogger('StateMachineLoader');
12
+ /**
13
+ * Loads and manages YAML-based state machine definitions
14
+ */
15
+ export class StateMachineLoader {
16
+ stateMachine = null;
17
+ validPhases = new Set();
18
+ /**
19
+ * Get all valid phases from the loaded state machine
20
+ */
21
+ getValidPhases() {
22
+ if (!this.stateMachine) {
23
+ throw new Error('State machine not loaded');
24
+ }
25
+ return Array.from(this.validPhases);
26
+ }
27
+ /**
28
+ * Get the initial state from the loaded state machine
29
+ */
30
+ getInitialState() {
31
+ if (!this.stateMachine) {
32
+ throw new Error('State machine not loaded');
33
+ }
34
+ return this.stateMachine.initial_state;
35
+ }
36
+ /**
37
+ * Load state machine from YAML file
38
+ *
39
+ * Checks for custom state machine file in project directory first,
40
+ * then falls back to waterfall workflow as default
41
+ */
42
+ loadStateMachine(projectPath) {
43
+ // Check for custom state machine file in project directory
44
+ const customFilePaths = [
45
+ path.join(projectPath, '.vibe', 'workflow.yaml'),
46
+ path.join(projectPath, '.vibe', 'workflow.yml'),
47
+ ];
48
+ // Try to load custom state machine file
49
+ for (const filePath of customFilePaths) {
50
+ if (fs.existsSync(filePath)) {
51
+ logger.info('Loading custom state machine file', { filePath });
52
+ try {
53
+ return this.loadFromFile(filePath);
54
+ }
55
+ catch (error) {
56
+ logger.warn('Failed to load custom state machine, falling back to default', {
57
+ filePath,
58
+ error: error.message,
59
+ });
60
+ // Continue to try next file or fall back to default
61
+ }
62
+ }
63
+ }
64
+ // Fall back to waterfall workflow as default
65
+ // Use import.meta.url to get the current file's path in ESM
66
+ const currentFileUrl = import.meta.url;
67
+ const currentFilePath = fileURLToPath(currentFileUrl);
68
+ // Go up from packages/core/dist/ to project root (4 levels up)
69
+ const projectRoot = path.dirname(path.dirname(path.dirname(path.dirname(currentFilePath))));
70
+ const defaultFilePath = path.join(projectRoot, 'resources', 'workflows', 'waterfall.yaml');
71
+ logger.info('Loading default state machine file', { defaultFilePath });
72
+ return this.loadFromFile(defaultFilePath);
73
+ }
74
+ /**
75
+ * Load state machine from specific file path
76
+ */
77
+ loadFromFile(filePath) {
78
+ try {
79
+ const yamlContent = fs.readFileSync(path.resolve(filePath), 'utf8');
80
+ const stateMachine = yaml.load(yamlContent);
81
+ // Validate the state machine
82
+ this.validateStateMachine(stateMachine);
83
+ // Store valid phases for later validation
84
+ this.validPhases = new Set(Object.keys(stateMachine.states));
85
+ this.stateMachine = stateMachine;
86
+ logger.info('State machine loaded successfully', {
87
+ name: stateMachine.name,
88
+ stateCount: Object.keys(stateMachine.states).length,
89
+ phases: Array.from(this.validPhases),
90
+ });
91
+ return stateMachine;
92
+ }
93
+ catch (error) {
94
+ logger.error('Failed to load state machine', error);
95
+ throw new Error(`Failed to load state machine: ${error.message}`);
96
+ }
97
+ }
98
+ /**
99
+ * Validate the state machine structure and references
100
+ */
101
+ validateStateMachine(stateMachine) {
102
+ // Check required properties
103
+ if (!stateMachine.name ||
104
+ !stateMachine.description ||
105
+ !stateMachine.initial_state ||
106
+ !stateMachine.states) {
107
+ throw new Error('State machine is missing required properties');
108
+ }
109
+ // Get all state names
110
+ const stateNames = Object.keys(stateMachine.states);
111
+ // Check initial state is valid
112
+ if (!stateNames.includes(stateMachine.initial_state)) {
113
+ throw new Error(`Initial state "${stateMachine.initial_state}" is not defined in states`);
114
+ }
115
+ // Validate states and transitions
116
+ for (const [stateName, state] of Object.entries(stateMachine.states)) {
117
+ // Check required state properties
118
+ if (!state.description || !state.default_instructions) {
119
+ throw new Error(`State "${stateName}" is missing required properties (description or default_instructions)`);
120
+ }
121
+ if (!state.transitions || !Array.isArray(state.transitions)) {
122
+ throw new Error(`State "${stateName}" has invalid transitions property`);
123
+ }
124
+ for (const transition of state.transitions) {
125
+ if (!stateNames.includes(transition.to)) {
126
+ throw new Error(`State "${stateName}" has transition to unknown state "${transition.to}"`);
127
+ }
128
+ if (!transition.transition_reason) {
129
+ throw new Error(`Transition from "${stateName}" to "${transition.to}" is missing transition_reason`);
130
+ }
131
+ }
132
+ }
133
+ logger.debug('State machine validation successful');
134
+ }
135
+ /**
136
+ * Get transition instructions for a specific state change
137
+ */
138
+ getTransitionInstructions(fromState, toState, trigger) {
139
+ if (!this.stateMachine) {
140
+ throw new Error('State machine not loaded');
141
+ }
142
+ // Get target state definition
143
+ const targetState = this.stateMachine.states[toState];
144
+ if (!targetState) {
145
+ throw new Error(`Target state "${toState}" not found`);
146
+ }
147
+ // Look for a modeled transition first
148
+ const fromStateDefinition = this.stateMachine.states[fromState];
149
+ if (fromStateDefinition) {
150
+ const transition = fromStateDefinition.transitions.find(t => t.to === toState && (!trigger || t.trigger === trigger));
151
+ if (transition) {
152
+ // For modeled transitions, compose instructions
153
+ let composedInstructions = targetState.default_instructions;
154
+ // If transition has specific instructions, use those instead of default
155
+ if (transition.instructions) {
156
+ composedInstructions = transition.instructions;
157
+ }
158
+ // If transition has additional instructions, combine them
159
+ if (transition.additional_instructions) {
160
+ composedInstructions = `${composedInstructions}\n\n**Additional Context:**\n${transition.additional_instructions}`;
161
+ }
162
+ return {
163
+ instructions: composedInstructions,
164
+ transitionReason: transition.transition_reason,
165
+ isModeled: true,
166
+ };
167
+ }
168
+ }
169
+ // Fall back to target state's default instructions for unmodeled transitions
170
+ return {
171
+ instructions: targetState.default_instructions,
172
+ transitionReason: `Direct transition to ${toState} phase`,
173
+ isModeled: false,
174
+ };
175
+ }
176
+ /**
177
+ * Get all possible transitions from a given state
178
+ */
179
+ getPossibleTransitions(fromState) {
180
+ if (!this.stateMachine) {
181
+ throw new Error('State machine not loaded');
182
+ }
183
+ const stateDefinition = this.stateMachine.states[fromState];
184
+ return stateDefinition ? stateDefinition.transitions : [];
185
+ }
186
+ /**
187
+ * Check if a transition is modeled (shown in state diagram)
188
+ */
189
+ isModeledTransition(fromState, toState) {
190
+ if (!this.stateMachine) {
191
+ throw new Error('State machine not loaded');
192
+ }
193
+ const stateDefinition = this.stateMachine.states[fromState];
194
+ if (!stateDefinition)
195
+ return false;
196
+ return stateDefinition.transitions.some(t => t.to === toState);
197
+ }
198
+ /**
199
+ * Check if a phase is valid in the current state machine
200
+ */
201
+ isValidPhase(phase) {
202
+ return this.validPhases.has(phase);
203
+ }
204
+ /**
205
+ * Get phase-specific instructions for continuing work in current phase
206
+ */
207
+ getContinuePhaseInstructions(phase) {
208
+ if (!this.stateMachine) {
209
+ throw new Error('State machine not loaded');
210
+ }
211
+ const stateDefinition = this.stateMachine.states[phase];
212
+ if (!stateDefinition) {
213
+ logger.error('Unknown phase', new Error(`Unknown phase: ${phase}`));
214
+ throw new Error(`Unknown phase: ${phase}`);
215
+ }
216
+ // Look for a self-transition (continue in same phase)
217
+ const continueTransition = stateDefinition.transitions.find(t => t.to === phase);
218
+ if (continueTransition) {
219
+ // Compose instructions for continue transition
220
+ let composedInstructions = stateDefinition.default_instructions;
221
+ // If transition has specific instructions, use those instead of default
222
+ if (continueTransition.instructions) {
223
+ composedInstructions = continueTransition.instructions;
224
+ }
225
+ // If transition has additional instructions, combine them
226
+ if (continueTransition.additional_instructions) {
227
+ composedInstructions = `${composedInstructions}\n\n**Additional Context:**\n${continueTransition.additional_instructions}`;
228
+ }
229
+ return composedInstructions;
230
+ }
231
+ // Fall back to default instructions for the phase
232
+ return stateDefinition.default_instructions;
233
+ }
234
+ }
235
+ //# sourceMappingURL=state-machine-loader.js.map