@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,24 @@
1
+ /**
2
+ * Configuration Manager
3
+ *
4
+ * Handles loading and validation of project configuration from .vibe/config.yaml
5
+ */
6
+ export interface ProjectConfig {
7
+ enabled_workflows?: string[];
8
+ }
9
+ /**
10
+ * Manages project configuration loading and validation
11
+ */
12
+ export declare class ConfigManager {
13
+ private static readonly CONFIG_FILENAME;
14
+ /**
15
+ * Load project configuration from .vibe/config.yaml
16
+ * Returns null if no config file exists (backward compatibility)
17
+ * Throws error for invalid configuration
18
+ */
19
+ static loadProjectConfig(projectPath: string): ProjectConfig | null;
20
+ /**
21
+ * Validate configuration structure and content
22
+ */
23
+ private static validateConfig;
24
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Configuration Manager
3
+ *
4
+ * Handles loading and validation of project configuration from .vibe/config.yaml
5
+ */
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import yaml from 'js-yaml';
9
+ import { createLogger } from './logger.js';
10
+ const logger = createLogger('ConfigManager');
11
+ /**
12
+ * Manages project configuration loading and validation
13
+ */
14
+ export class ConfigManager {
15
+ static CONFIG_FILENAME = 'config.yaml';
16
+ /**
17
+ * Load project configuration from .vibe/config.yaml
18
+ * Returns null if no config file exists (backward compatibility)
19
+ * Throws error for invalid configuration
20
+ */
21
+ static loadProjectConfig(projectPath) {
22
+ const configPath = path.join(projectPath, '.vibe', this.CONFIG_FILENAME);
23
+ // No config file = backward compatibility (all workflows available)
24
+ if (!fs.existsSync(configPath)) {
25
+ logger.debug('No config file found, using defaults', { configPath });
26
+ return null;
27
+ }
28
+ try {
29
+ const configContent = fs.readFileSync(configPath, 'utf-8');
30
+ const config = yaml.load(configContent);
31
+ this.validateConfig(config, configPath);
32
+ logger.info('Loaded project configuration', {
33
+ configPath,
34
+ enabledWorkflows: config.enabled_workflows?.length || 0,
35
+ });
36
+ return config;
37
+ }
38
+ catch (error) {
39
+ if (error instanceof yaml.YAMLException) {
40
+ throw new Error(`Invalid YAML in config file ${configPath}: ${error.message}`);
41
+ }
42
+ throw new Error(`Failed to load config file ${configPath}: ${error}`);
43
+ }
44
+ }
45
+ /**
46
+ * Validate configuration structure and content
47
+ */
48
+ static validateConfig(config, configPath) {
49
+ if (!config || typeof config !== 'object') {
50
+ throw new Error(`Invalid config file ${configPath}: must be a YAML object`);
51
+ }
52
+ if (config.enabled_workflows !== undefined) {
53
+ if (!Array.isArray(config.enabled_workflows)) {
54
+ throw new Error(`Invalid config file ${configPath}: enabled_workflows must be an array`);
55
+ }
56
+ if (config.enabled_workflows.length === 0) {
57
+ throw new Error(`Invalid config file ${configPath}: enabled_workflows cannot be empty`);
58
+ }
59
+ // Validate all entries are strings
60
+ for (const workflow of config.enabled_workflows) {
61
+ if (typeof workflow !== 'string' || workflow.trim() === '') {
62
+ throw new Error(`Invalid config file ${configPath}: all workflow names must be non-empty strings`);
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ //# sourceMappingURL=config-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../src/config-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAM7C;;GAEG;AACH,MAAM,OAAO,aAAa;IAChB,MAAM,CAAU,eAAe,GAAG,aAAa,CAAC;IAExD;;;;OAIG;IACI,MAAM,CAAC,iBAAiB,CAAC,WAAmB;QACjD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;QAEzE,oEAAoE;QACpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,KAAK,CAAC,sCAAsC,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YACrE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAkB,CAAC;YAEzD,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAExC,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE;gBAC1C,UAAU;gBACV,gBAAgB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,IAAI,CAAC;aACxD,CAAC,CAAC;YAEH,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,IAAI,CAAC,aAAa,EAAE,CAAC;gBACxC,MAAM,IAAI,KAAK,CACb,+BAA+B,UAAU,KAAK,KAAK,CAAC,OAAO,EAAE,CAC9D,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,UAAU,KAAK,KAAK,EAAE,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,cAAc,CAC3B,MAAqB,EACrB,UAAkB;QAElB,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CACb,uBAAuB,UAAU,yBAAyB,CAC3D,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,CACb,uBAAuB,UAAU,sCAAsC,CACxE,CAAC;YACJ,CAAC;YAED,IAAI,MAAM,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1C,MAAM,IAAI,KAAK,CACb,uBAAuB,UAAU,qCAAqC,CACvE,CAAC;YACJ,CAAC;YAED,mCAAmC;YACnC,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;gBAChD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;oBAC3D,MAAM,IAAI,KAAK,CACb,uBAAuB,UAAU,gDAAgD,CAClF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Conversation Manager
3
+ *
4
+ * Handles conversation identification, state persistence, and coordination
5
+ * between components. Generates unique conversation identifiers from
6
+ * project path + git branch combination.
7
+ */
8
+ import { Database } from './database.js';
9
+ import type { ConversationState, ConversationContext } from './types.js';
10
+ import { WorkflowManager } from './workflow-manager.js';
11
+ export declare class ConversationManager {
12
+ private database;
13
+ private projectPath;
14
+ private workflowManager;
15
+ constructor(database: Database, workflowManager: WorkflowManager, projectPath: string);
16
+ /**
17
+ * Get conversation state by ID
18
+ */
19
+ getConversationState(conversationId: string): Promise<ConversationState | null>;
20
+ /**
21
+ * Get the current conversation context
22
+ *
23
+ * Detects the current project path and git branch, then retrieves an existing
24
+ * conversation state for this context. Does NOT create a new conversation.
25
+ *
26
+ * @throws Error if no conversation exists for this context
27
+ */
28
+ getConversationContext(): Promise<ConversationContext>;
29
+ /**
30
+ * Create a new conversation context
31
+ *
32
+ * This should only be called by the start_development tool to explicitly
33
+ * create a new conversation with a selected workflow.
34
+ *
35
+ * @param workflowName - The workflow to use for this conversation
36
+ * @returns The newly created conversation context
37
+ */
38
+ createConversationContext(workflowName: string): Promise<ConversationContext>;
39
+ /**
40
+ * Update the conversation state
41
+ *
42
+ * @param conversationId - ID of the conversation to update
43
+ * @param updates - Partial state updates to apply
44
+ */
45
+ updateConversationState(conversationId: string, updates: Partial<Pick<ConversationState, 'currentPhase' | 'planFilePath' | 'workflowName' | 'gitCommitConfig' | 'requireReviewsBeforePhaseTransition'>>): Promise<void>;
46
+ /**
47
+ * Create a new conversation state
48
+ *
49
+ * @param conversationId - ID for the new conversation
50
+ * @param projectPath - Path to the project
51
+ * @param gitBranch - Git branch name
52
+ */
53
+ private createNewConversationState;
54
+ /**
55
+ * Generate a unique conversation ID based on project path and git branch
56
+ *
57
+ * @param projectPath - Path to the project
58
+ * @param gitBranch - Git branch name
59
+ */
60
+ private generateConversationId;
61
+ /**
62
+ * Get the current project path
63
+ */
64
+ private getProjectPath;
65
+ /**
66
+ * Get the current git branch for a project
67
+ *
68
+ * @param projectPath - Path to the project
69
+ */
70
+ private getGitBranch;
71
+ /**
72
+ * Check if a conversation has any previous interactions
73
+ * Used to determine if this is the first interaction in a conversation
74
+ */
75
+ hasInteractions(conversationId: string): Promise<boolean>;
76
+ /**
77
+ * Reset conversation data (hybrid approach)
78
+ */
79
+ resetConversation(confirm: boolean, reason?: string): Promise<{
80
+ success: boolean;
81
+ resetItems: string[];
82
+ conversationId: string;
83
+ message: string;
84
+ }>;
85
+ /**
86
+ * Validate reset request parameters
87
+ */
88
+ private validateResetRequest;
89
+ /**
90
+ * Verify that reset cleanup was successful
91
+ */
92
+ private verifyResetCleanup;
93
+ /**
94
+ * Clean up conversation data (used internally)
95
+ */
96
+ cleanupConversationData(conversationId: string): Promise<void>;
97
+ }
@@ -0,0 +1,367 @@
1
+ /**
2
+ * Conversation Manager
3
+ *
4
+ * Handles conversation identification, state persistence, and coordination
5
+ * between components. Generates unique conversation identifiers from
6
+ * project path + git branch combination.
7
+ */
8
+ import { execSync } from 'node:child_process';
9
+ import { resolve } from 'node:path';
10
+ import { existsSync } from 'node:fs';
11
+ import { createLogger } from './logger.js';
12
+ import { PlanManager } from './plan-manager.js';
13
+ const logger = createLogger('ConversationManager');
14
+ export class ConversationManager {
15
+ database;
16
+ projectPath;
17
+ workflowManager;
18
+ constructor(database, workflowManager, projectPath) {
19
+ this.database = database;
20
+ this.workflowManager = workflowManager;
21
+ this.projectPath = projectPath;
22
+ }
23
+ /**
24
+ * Get conversation state by ID
25
+ */
26
+ async getConversationState(conversationId) {
27
+ return await this.database.getConversationState(conversationId);
28
+ }
29
+ /**
30
+ * Get the current conversation context
31
+ *
32
+ * Detects the current project path and git branch, then retrieves an existing
33
+ * conversation state for this context. Does NOT create a new conversation.
34
+ *
35
+ * @throws Error if no conversation exists for this context
36
+ */
37
+ async getConversationContext() {
38
+ const projectPath = this.getProjectPath();
39
+ const gitBranch = this.getGitBranch(projectPath);
40
+ logger.debug('Getting conversation context', { projectPath, gitBranch });
41
+ // Generate a unique conversation ID based on project path and git branch
42
+ const conversationId = this.generateConversationId(projectPath, gitBranch);
43
+ // Try to find existing conversation state
44
+ const state = await this.database.getConversationState(conversationId);
45
+ // If no existing state, throw an error - conversation must be created with start_development first
46
+ if (!state) {
47
+ logger.warn('No conversation found for context', {
48
+ projectPath,
49
+ gitBranch,
50
+ conversationId,
51
+ });
52
+ throw new Error('No development conversation exists for this project. Use the start_development tool first to initialize development with a workflow.');
53
+ }
54
+ // Return the conversation context
55
+ return {
56
+ conversationId: state.conversationId,
57
+ projectPath: state.projectPath,
58
+ gitBranch: state.gitBranch,
59
+ currentPhase: state.currentPhase,
60
+ planFilePath: state.planFilePath,
61
+ workflowName: state.workflowName,
62
+ };
63
+ }
64
+ /**
65
+ * Create a new conversation context
66
+ *
67
+ * This should only be called by the start_development tool to explicitly
68
+ * create a new conversation with a selected workflow.
69
+ *
70
+ * @param workflowName - The workflow to use for this conversation
71
+ * @returns The newly created conversation context
72
+ */
73
+ async createConversationContext(workflowName) {
74
+ const projectPath = this.getProjectPath();
75
+ const gitBranch = this.getGitBranch(projectPath);
76
+ logger.debug('Creating conversation context', {
77
+ projectPath,
78
+ gitBranch,
79
+ workflowName,
80
+ });
81
+ // Generate a unique conversation ID based on project path and git branch
82
+ const conversationId = this.generateConversationId(projectPath, gitBranch);
83
+ // Check if a conversation already exists
84
+ const existingState = await this.database.getConversationState(conversationId);
85
+ if (existingState) {
86
+ logger.debug('Conversation already exists, returning existing context', {
87
+ conversationId,
88
+ });
89
+ return {
90
+ conversationId: existingState.conversationId,
91
+ projectPath: existingState.projectPath,
92
+ gitBranch: existingState.gitBranch,
93
+ currentPhase: existingState.currentPhase,
94
+ planFilePath: existingState.planFilePath,
95
+ workflowName: existingState.workflowName,
96
+ };
97
+ }
98
+ // Create a new conversation state
99
+ const state = await this.createNewConversationState(conversationId, projectPath, gitBranch, workflowName);
100
+ // Return the conversation context
101
+ return {
102
+ conversationId: state.conversationId,
103
+ projectPath: state.projectPath,
104
+ gitBranch: state.gitBranch,
105
+ currentPhase: state.currentPhase,
106
+ planFilePath: state.planFilePath,
107
+ workflowName: state.workflowName,
108
+ };
109
+ }
110
+ /**
111
+ * Update the conversation state
112
+ *
113
+ * @param conversationId - ID of the conversation to update
114
+ * @param updates - Partial state updates to apply
115
+ */
116
+ async updateConversationState(conversationId, updates) {
117
+ logger.debug('Updating conversation state', { conversationId, updates });
118
+ // Get current state
119
+ const currentState = await this.database.getConversationState(conversationId);
120
+ if (!currentState) {
121
+ throw new Error(`Conversation state not found for ID: ${conversationId}`);
122
+ }
123
+ // Apply updates
124
+ const updatedState = {
125
+ ...currentState,
126
+ ...updates,
127
+ updatedAt: new Date().toISOString(),
128
+ };
129
+ // Save updated state
130
+ await this.database.saveConversationState(updatedState);
131
+ logger.info('Conversation state updated', {
132
+ conversationId,
133
+ currentPhase: updatedState.currentPhase,
134
+ });
135
+ }
136
+ /**
137
+ * Create a new conversation state
138
+ *
139
+ * @param conversationId - ID for the new conversation
140
+ * @param projectPath - Path to the project
141
+ * @param gitBranch - Git branch name
142
+ */
143
+ async createNewConversationState(conversationId, projectPath, gitBranch, workflowName = 'waterfall') {
144
+ logger.info('Creating new conversation state', {
145
+ conversationId,
146
+ projectPath,
147
+ gitBranch,
148
+ });
149
+ const timestamp = new Date().toISOString();
150
+ // Generate a plan file path based on the branch name
151
+ const planFileName = gitBranch === 'main' || gitBranch === 'master'
152
+ ? 'development-plan.md'
153
+ : `development-plan-${gitBranch}.md`;
154
+ const planFilePath = resolve(projectPath, '.vibe', planFileName);
155
+ // Get initial state from the appropriate workflow
156
+ const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
157
+ const initialPhase = stateMachine.initial_state;
158
+ // Create new state
159
+ const newState = {
160
+ conversationId,
161
+ projectPath,
162
+ gitBranch,
163
+ currentPhase: initialPhase,
164
+ planFilePath,
165
+ workflowName,
166
+ requireReviewsBeforePhaseTransition: false, // Default to false for new conversations
167
+ createdAt: timestamp,
168
+ updatedAt: timestamp,
169
+ };
170
+ // Save to database
171
+ await this.database.saveConversationState(newState);
172
+ logger.info('New conversation state created', {
173
+ conversationId,
174
+ planFilePath,
175
+ initialPhase,
176
+ });
177
+ return newState;
178
+ }
179
+ /**
180
+ * Generate a unique conversation ID based on project path and git branch
181
+ *
182
+ * @param projectPath - Path to the project
183
+ * @param gitBranch - Git branch name
184
+ */
185
+ generateConversationId(projectPath, gitBranch) {
186
+ // Extract project name from path
187
+ const projectName = projectPath.split('/').pop() || 'unknown-project';
188
+ // Clean branch name for use in ID
189
+ const cleanBranch = gitBranch
190
+ .replace(/[^a-zA-Z0-9-]/g, '-')
191
+ .replace(/-+/g, '-')
192
+ .replace(/^-|-$/g, '');
193
+ // For tests, use a deterministic ID
194
+ if (process.env.NODE_ENV === 'test') {
195
+ return `${projectName}-${cleanBranch}-p423k1`;
196
+ }
197
+ // Generate a deterministic ID based on project path and branch
198
+ // This ensures the same project/branch combination always gets the same conversation ID
199
+ let hash = 0;
200
+ const str = `${projectPath}:${gitBranch}`;
201
+ for (let i = 0; i < str.length; i++) {
202
+ const char = str.charCodeAt(i);
203
+ hash = (hash << 5) - hash + char;
204
+ hash = hash & hash; // Convert to 32-bit integer
205
+ }
206
+ const hashStr = Math.abs(hash).toString(36).substring(0, 6);
207
+ return `${projectName}-${cleanBranch}-${hashStr}`;
208
+ }
209
+ /**
210
+ * Get the current project path
211
+ */
212
+ getProjectPath() {
213
+ return this.projectPath;
214
+ }
215
+ /**
216
+ * Get the current git branch for a project
217
+ *
218
+ * @param projectPath - Path to the project
219
+ */
220
+ getGitBranch(projectPath) {
221
+ try {
222
+ // Check if this is a git repository
223
+ if (!existsSync(`${projectPath}/.git`)) {
224
+ logger.debug('Not a git repository, using "default" as branch name', {
225
+ projectPath,
226
+ });
227
+ return 'default';
228
+ }
229
+ // Get current branch name
230
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', {
231
+ cwd: projectPath,
232
+ encoding: 'utf-8',
233
+ stdio: ['ignore', 'pipe', 'ignore'], // Suppress stderr to avoid "fatal: not a git repository" warnings
234
+ }).trim();
235
+ logger.debug('Detected git branch', { projectPath, branch });
236
+ return branch;
237
+ }
238
+ catch (_error) {
239
+ logger.debug('Failed to get git branch, using "default" as branch name', {
240
+ projectPath,
241
+ });
242
+ return 'default';
243
+ }
244
+ }
245
+ /**
246
+ * Check if a conversation has any previous interactions
247
+ * Used to determine if this is the first interaction in a conversation
248
+ */
249
+ async hasInteractions(conversationId) {
250
+ try {
251
+ // Get all interactions for this conversation
252
+ const interactions = await this.database.getInteractionsByConversationId(conversationId);
253
+ const count = interactions.length;
254
+ logger.debug('Checked interaction count for conversation', {
255
+ conversationId,
256
+ count,
257
+ });
258
+ return count > 0;
259
+ }
260
+ catch (error) {
261
+ logger.error('Failed to check interaction count', error, {
262
+ conversationId,
263
+ });
264
+ // If we can't check, assume this is the first interaction to be safe
265
+ return false;
266
+ }
267
+ }
268
+ /**
269
+ * Reset conversation data (hybrid approach)
270
+ */
271
+ async resetConversation(confirm, reason) {
272
+ logger.info('Starting conversation reset', { confirm, reason });
273
+ // Validate reset request
274
+ this.validateResetRequest(confirm);
275
+ const context = await this.getConversationContext();
276
+ const resetItems = [];
277
+ try {
278
+ // Step 1: Soft delete interaction logs
279
+ await this.database.softDeleteInteractionLogs(context.conversationId, reason);
280
+ resetItems.push('interaction_logs');
281
+ logger.debug('Interaction logs soft deleted');
282
+ // Step 2: Hard delete conversation state
283
+ await this.database.deleteConversationState(context.conversationId);
284
+ resetItems.push('conversation_state');
285
+ logger.debug('Conversation state hard deleted');
286
+ // Step 3: Hard delete plan file
287
+ const planManager = new PlanManager();
288
+ await planManager.deletePlanFile(context.planFilePath);
289
+ resetItems.push('plan_file');
290
+ logger.debug('Plan file deleted');
291
+ // Verify cleanup
292
+ await this.verifyResetCleanup(context.conversationId, context.planFilePath);
293
+ const message = `Successfully reset conversation ${context.conversationId}. Reset items: ${resetItems.join(', ')}${reason ? `. Reason: ${reason}` : ''}`;
294
+ logger.info('Conversation reset completed successfully', {
295
+ conversationId: context.conversationId,
296
+ resetItems,
297
+ reason,
298
+ });
299
+ return {
300
+ success: true,
301
+ resetItems,
302
+ conversationId: context.conversationId,
303
+ message,
304
+ };
305
+ }
306
+ catch (error) {
307
+ logger.error('Failed to reset conversation', error, {
308
+ conversationId: context.conversationId,
309
+ resetItems,
310
+ reason,
311
+ });
312
+ throw new Error(`Reset failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
313
+ }
314
+ }
315
+ /**
316
+ * Validate reset request parameters
317
+ */
318
+ validateResetRequest(confirm) {
319
+ if (!confirm) {
320
+ throw new Error('Reset operation requires explicit confirmation. Set confirm parameter to true.');
321
+ }
322
+ }
323
+ /**
324
+ * Verify that reset cleanup was successful
325
+ */
326
+ async verifyResetCleanup(conversationId, planFilePath) {
327
+ logger.debug('Verifying reset cleanup', { conversationId, planFilePath });
328
+ try {
329
+ // Check that conversation state is deleted
330
+ const state = await this.database.getConversationState(conversationId);
331
+ if (state) {
332
+ throw new Error('Conversation state was not properly deleted');
333
+ }
334
+ // Check that plan file is deleted
335
+ const planManager = new PlanManager();
336
+ const isDeleted = await planManager.ensurePlanFileDeleted(planFilePath);
337
+ if (!isDeleted) {
338
+ throw new Error('Plan file was not properly deleted');
339
+ }
340
+ logger.debug('Reset cleanup verification successful');
341
+ }
342
+ catch (error) {
343
+ logger.error('Reset cleanup verification failed', error);
344
+ throw error;
345
+ }
346
+ }
347
+ /**
348
+ * Clean up conversation data (used internally)
349
+ */
350
+ async cleanupConversationData(conversationId) {
351
+ logger.debug('Cleaning up conversation data', { conversationId });
352
+ try {
353
+ // This method can be used for additional cleanup if needed
354
+ // Currently, the main cleanup is handled by resetConversation
355
+ await this.database.softDeleteInteractionLogs(conversationId);
356
+ await this.database.deleteConversationState(conversationId);
357
+ logger.debug('Conversation data cleanup completed', { conversationId });
358
+ }
359
+ catch (error) {
360
+ logger.error('Failed to cleanup conversation data', error, {
361
+ conversationId,
362
+ });
363
+ throw error;
364
+ }
365
+ }
366
+ }
367
+ //# sourceMappingURL=conversation-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-manager.js","sourceRoot":"","sources":["../src/conversation-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Database module for persistent state storage
3
+ *
4
+ * Manages SQLite database for conversation state persistence.
5
+ * Stores minimal state information to survive server restarts.
6
+ * Also stores interaction logs for auditing and debugging.
7
+ */
8
+ import type { ConversationState, InteractionLog } from './types.js';
9
+ export declare class Database {
10
+ private db;
11
+ private dbPath;
12
+ constructor(projectPath: string);
13
+ /**
14
+ * Initialize database connection and create tables
15
+ */
16
+ initialize(): Promise<void>;
17
+ /**
18
+ * Helper method to run queries with promises
19
+ */
20
+ private runQuery;
21
+ /**
22
+ * Helper method to get single row with promises
23
+ */
24
+ private getRow;
25
+ /**
26
+ * Helper method to get multiple rows with promises
27
+ */
28
+ private getAllRows;
29
+ /**
30
+ * Get conversation state by ID
31
+ */
32
+ getConversationState(conversationId: string): Promise<ConversationState | null>;
33
+ /**
34
+ * Save or update conversation state
35
+ */
36
+ saveConversationState(state: ConversationState): Promise<void>;
37
+ /**
38
+ * Find conversation by project path and git branch
39
+ */
40
+ findConversationByProject(projectPath: string, gitBranch: string): Promise<ConversationState | null>;
41
+ /**
42
+ * Delete conversation state
43
+ */
44
+ deleteConversationState(conversationId: string): Promise<void>;
45
+ /**
46
+ * Log an interaction to the database
47
+ */
48
+ logInteraction(log: InteractionLog): Promise<void>;
49
+ /**
50
+ * Get all interactions for a specific conversation
51
+ */
52
+ getInteractionsByConversationId(conversationId: string): Promise<InteractionLog[]>;
53
+ /**
54
+ * Run database migrations to add new columns
55
+ */
56
+ private runMigrations;
57
+ /**
58
+ * Soft delete interaction logs for a conversation
59
+ */
60
+ softDeleteInteractionLogs(conversationId: string, reason?: string): Promise<void>;
61
+ /**
62
+ * Get active (non-reset) interaction logs for a conversation
63
+ */
64
+ getActiveInteractionLogs(conversationId: string): Promise<InteractionLog[]>;
65
+ /**
66
+ * Get all interaction logs including reset ones for a conversation
67
+ */
68
+ getAllInteractionLogsIncludingReset(conversationId: string): Promise<InteractionLog[]>;
69
+ /**
70
+ * Close database connection
71
+ */
72
+ close(): Promise<void>;
73
+ }