@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,323 @@
1
+ /**
2
+ * Plan Manager
3
+ *
4
+ * Handles the creation, updating, and maintenance of project development plan files.
5
+ * Manages markdown plan files that serve as long-term project memory.
6
+ * Supports custom state machine definitions for dynamic plan file generation.
7
+ */
8
+
9
+ import { writeFile, readFile, access } from 'node:fs/promises';
10
+ import { dirname } from 'node:path';
11
+ import { mkdir } from 'node:fs/promises';
12
+ import { createLogger } from './logger.js';
13
+
14
+ import type { YamlStateMachine } from './state-machine-types.js';
15
+
16
+ const logger = createLogger('PlanManager');
17
+
18
+ export interface PlanFileInfo {
19
+ path: string;
20
+ exists: boolean;
21
+ content?: string;
22
+ }
23
+
24
+ export class PlanManager {
25
+ private stateMachine: YamlStateMachine | null = null;
26
+
27
+ /**
28
+ * Set the state machine definition for dynamic plan generation
29
+ */
30
+ setStateMachine(stateMachine: YamlStateMachine): void {
31
+ this.stateMachine = stateMachine;
32
+ logger.debug('State machine set for plan manager', {
33
+ name: stateMachine.name,
34
+ phases: Object.keys(stateMachine.states),
35
+ });
36
+ }
37
+
38
+ /**
39
+ * Get plan file information
40
+ */
41
+ async getPlanFileInfo(planFilePath: string): Promise<PlanFileInfo> {
42
+ try {
43
+ await access(planFilePath);
44
+ const content = await readFile(planFilePath, 'utf-8');
45
+ return {
46
+ path: planFilePath,
47
+ exists: true,
48
+ content,
49
+ };
50
+ } catch (_error) {
51
+ return {
52
+ path: planFilePath,
53
+ exists: false,
54
+ };
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Create initial plan file if it doesn't exist
60
+ */
61
+ async ensurePlanFile(
62
+ planFilePath: string,
63
+ projectPath: string,
64
+ gitBranch: string
65
+ ): Promise<void> {
66
+ logger.debug('Ensuring plan file exists', {
67
+ planFilePath,
68
+ projectPath,
69
+ gitBranch,
70
+ });
71
+
72
+ const planInfo = await this.getPlanFileInfo(planFilePath);
73
+
74
+ if (!planInfo.exists) {
75
+ logger.info('Plan file not found, creating initial plan', {
76
+ planFilePath,
77
+ });
78
+ await this.createInitialPlanFile(planFilePath, projectPath, gitBranch);
79
+ logger.info('Initial plan file created successfully', { planFilePath });
80
+ } else {
81
+ logger.debug('Plan file already exists', { planFilePath });
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Create initial plan file with template content
87
+ */
88
+ private async createInitialPlanFile(
89
+ planFilePath: string,
90
+ projectPath: string,
91
+ gitBranch: string
92
+ ): Promise<void> {
93
+ logger.debug('Creating initial plan file', { planFilePath });
94
+
95
+ try {
96
+ // Ensure directory exists
97
+ await mkdir(dirname(planFilePath), { recursive: true });
98
+ logger.debug('Plan file directory ensured', {
99
+ directory: dirname(planFilePath),
100
+ });
101
+
102
+ const projectName = projectPath.split('/').pop() || 'Unknown Project';
103
+ const branchInfo = gitBranch !== 'no-git' ? ` (${gitBranch} branch)` : '';
104
+
105
+ const initialContent = this.generateInitialPlanContent(
106
+ projectName,
107
+ branchInfo
108
+ );
109
+
110
+ await writeFile(planFilePath, initialContent, 'utf-8');
111
+ logger.info('Initial plan file written successfully', {
112
+ planFilePath,
113
+ contentLength: initialContent.length,
114
+ projectName,
115
+ });
116
+ } catch (error) {
117
+ logger.error('Failed to create initial plan file', error as Error, {
118
+ planFilePath,
119
+ });
120
+ throw error;
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Generate initial plan file content based on state machine definition
126
+ */
127
+ private generateInitialPlanContent(
128
+ projectName: string,
129
+ branchInfo: string
130
+ ): string {
131
+ const timestamp = new Date().toISOString().split('T')[0];
132
+
133
+ if (!this.stateMachine) {
134
+ throw new Error(
135
+ 'State machine not set. This should not happen as state machine is always loaded.'
136
+ );
137
+ }
138
+
139
+ const phases = Object.keys(this.stateMachine.states);
140
+ const initialPhase = this.stateMachine.initial_state;
141
+
142
+ const documentationUrl = this.generateWorkflowDocumentationUrl(
143
+ this.stateMachine.name
144
+ );
145
+
146
+ let content = `# Development Plan: ${projectName}${branchInfo}
147
+
148
+ *Generated on ${timestamp} by Vibe Feature MCP*
149
+ *Workflow: ${
150
+ documentationUrl
151
+ ? '[' + this.stateMachine.name + ']' + '(' + documentationUrl + ')'
152
+ : this.stateMachine.name
153
+ }*
154
+
155
+ ## Goal
156
+ *Define what you're building or fixing - this will be updated as requirements are gathered*
157
+
158
+ ## ${this.capitalizePhase(initialPhase)}
159
+ ### Tasks
160
+ - [ ] *Tasks will be added as they are identified*
161
+
162
+ ### Completed
163
+ - [x] Created development plan file
164
+
165
+ `;
166
+
167
+ // Generate simple sections for each phase
168
+ for (const phase of phases) {
169
+ if (phase !== initialPhase) {
170
+ content += `## ${this.capitalizePhase(phase)}
171
+ ### Tasks
172
+ - [ ] *To be added when this phase becomes active*
173
+
174
+ ### Completed
175
+ *None yet*
176
+
177
+ `;
178
+ }
179
+ }
180
+
181
+ content += `## Key Decisions
182
+ *Important decisions will be documented here as they are made*
183
+
184
+ ## Notes
185
+ *Additional context and observations*
186
+
187
+ ---
188
+ *This plan is maintained by the LLM. Tool responses provide guidance on which section to focus on and what tasks to work on.*
189
+ `;
190
+
191
+ return content;
192
+ }
193
+
194
+ /**
195
+ * Update plan file with new content (this is typically done by the LLM)
196
+ */
197
+ async updatePlanFile(planFilePath: string, content: string): Promise<void> {
198
+ // Ensure directory exists
199
+ await mkdir(dirname(planFilePath), { recursive: true });
200
+
201
+ await writeFile(planFilePath, content, 'utf-8');
202
+ }
203
+
204
+ /**
205
+ * Get plan file content for LLM context
206
+ */
207
+ async getPlanFileContent(planFilePath: string): Promise<string> {
208
+ const planInfo = await this.getPlanFileInfo(planFilePath);
209
+
210
+ if (!planInfo.exists) {
211
+ return 'Plan file does not exist yet. It will be created when the LLM updates it.';
212
+ }
213
+
214
+ return planInfo.content || '';
215
+ }
216
+
217
+ /**
218
+ * Generate phase-specific plan file guidance based on state machine
219
+ */
220
+ generatePlanFileGuidance(phase: string): string {
221
+ if (!this.stateMachine) {
222
+ throw new Error(
223
+ 'State machine not set. This should not happen as state machine is always loaded.'
224
+ );
225
+ }
226
+
227
+ const phaseDefinition = this.stateMachine.states[phase];
228
+ if (!phaseDefinition) {
229
+ logger.warn('Unknown phase for plan file guidance', { phase });
230
+ return `Update the ${this.capitalizePhase(phase)} section with current progress and mark completed tasks.`;
231
+ }
232
+
233
+ const capitalizedPhase = this.capitalizePhase(phase);
234
+
235
+ return `Update the ${capitalizedPhase} section with progress. Mark completed tasks with [x] and add new tasks as they are identified.`;
236
+ }
237
+
238
+ /**
239
+ * Delete plan file
240
+ */
241
+ async deletePlanFile(planFilePath: string): Promise<boolean> {
242
+ logger.debug('Deleting plan file', { planFilePath });
243
+
244
+ try {
245
+ // Check if file exists first
246
+ await access(planFilePath);
247
+
248
+ // Import unlink dynamically to avoid issues
249
+ const { unlink } = await import('node:fs/promises');
250
+ await unlink(planFilePath);
251
+
252
+ logger.info('Plan file deleted successfully', { planFilePath });
253
+ return true;
254
+ } catch (error: unknown) {
255
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
256
+ logger.debug('Plan file does not exist, nothing to delete', {
257
+ planFilePath,
258
+ });
259
+ return true; // Consider it successful if file doesn't exist
260
+ }
261
+
262
+ logger.error('Failed to delete plan file', error as Error, {
263
+ planFilePath,
264
+ });
265
+ throw error;
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Ensure plan file is deleted (verify deletion)
271
+ */
272
+ async ensurePlanFileDeleted(planFilePath: string): Promise<boolean> {
273
+ logger.debug('Ensuring plan file is deleted', { planFilePath });
274
+
275
+ try {
276
+ await access(planFilePath);
277
+ // If we reach here, file still exists
278
+ logger.warn('Plan file still exists after deletion attempt', {
279
+ planFilePath,
280
+ });
281
+ return false;
282
+ } catch (error: unknown) {
283
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
284
+ logger.debug('Plan file successfully deleted (does not exist)', {
285
+ planFilePath,
286
+ });
287
+ return true;
288
+ }
289
+
290
+ // Some other error occurred
291
+ logger.error('Error checking plan file deletion', error as Error, {
292
+ planFilePath,
293
+ });
294
+ throw error;
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Capitalize phase name for display
300
+ */
301
+ private capitalizePhase(phase: string): string {
302
+ return phase
303
+ .split('_')
304
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
305
+ .join(' ');
306
+ }
307
+
308
+ /**
309
+ * Generate workflow documentation URL for predefined workflows
310
+ * Returns undefined for custom workflows
311
+ */
312
+ private generateWorkflowDocumentationUrl(
313
+ workflowName: string
314
+ ): string | undefined {
315
+ // Don't generate URL for custom workflows
316
+ if (workflowName === 'custom') {
317
+ return undefined;
318
+ }
319
+
320
+ // Generate URL for predefined workflows
321
+ return `https://mrsimpson.github.io/responsible-vibe-mcp/workflows/${workflowName}`;
322
+ }
323
+ }