@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.
- package/.turbo/turbo-build.log +4 -0
- package/LICENSE +674 -0
- package/dist/config-manager.d.ts +24 -0
- package/dist/config-manager.js +68 -0
- package/dist/config-manager.js.map +1 -0
- package/dist/conversation-manager.d.ts +97 -0
- package/dist/conversation-manager.js +367 -0
- package/dist/conversation-manager.js.map +1 -0
- package/dist/database.d.ts +73 -0
- package/dist/database.js +500 -0
- package/dist/database.js.map +1 -0
- package/dist/file-detection-manager.d.ts +53 -0
- package/dist/file-detection-manager.js +221 -0
- package/dist/file-detection-manager.js.map +1 -0
- package/dist/git-manager.d.ts +14 -0
- package/dist/git-manager.js +59 -0
- package/dist/git-manager.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/instruction-generator.d.ts +69 -0
- package/dist/instruction-generator.js +133 -0
- package/dist/instruction-generator.js.map +1 -0
- package/dist/interaction-logger.d.ts +37 -0
- package/dist/interaction-logger.js +87 -0
- package/dist/interaction-logger.js.map +1 -0
- package/dist/logger.d.ts +64 -0
- package/dist/logger.js +283 -0
- package/dist/logger.js.map +1 -0
- package/dist/path-validation-utils.d.ts +51 -0
- package/dist/path-validation-utils.js +202 -0
- package/dist/path-validation-utils.js.map +1 -0
- package/dist/plan-manager.d.ts +65 -0
- package/dist/plan-manager.js +256 -0
- package/dist/plan-manager.js.map +1 -0
- package/dist/project-docs-manager.d.ts +119 -0
- package/dist/project-docs-manager.js +357 -0
- package/dist/project-docs-manager.js.map +1 -0
- package/dist/state-machine-loader.d.ts +60 -0
- package/dist/state-machine-loader.js +235 -0
- package/dist/state-machine-loader.js.map +1 -0
- package/dist/state-machine-types.d.ts +58 -0
- package/dist/state-machine-types.js +7 -0
- package/dist/state-machine-types.js.map +1 -0
- package/dist/state-machine.d.ts +52 -0
- package/dist/state-machine.js +256 -0
- package/dist/state-machine.js.map +1 -0
- package/dist/system-prompt-generator.d.ts +17 -0
- package/dist/system-prompt-generator.js +113 -0
- package/dist/system-prompt-generator.js.map +1 -0
- package/dist/template-manager.d.ts +61 -0
- package/dist/template-manager.js +229 -0
- package/dist/template-manager.js.map +1 -0
- package/dist/transition-engine.d.ts +70 -0
- package/dist/transition-engine.js +240 -0
- package/dist/transition-engine.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/workflow-manager.d.ts +89 -0
- package/dist/workflow-manager.js +466 -0
- package/dist/workflow-manager.js.map +1 -0
- package/package.json +27 -0
- package/src/config-manager.ts +96 -0
- package/src/conversation-manager.ts +492 -0
- package/src/database.ts +685 -0
- package/src/file-detection-manager.ts +302 -0
- package/src/git-manager.ts +64 -0
- package/src/index.ts +28 -0
- package/src/instruction-generator.ts +210 -0
- package/src/interaction-logger.ts +109 -0
- package/src/logger.ts +353 -0
- package/src/path-validation-utils.ts +261 -0
- package/src/plan-manager.ts +323 -0
- package/src/project-docs-manager.ts +522 -0
- package/src/state-machine-loader.ts +308 -0
- package/src/state-machine-types.ts +72 -0
- package/src/state-machine.ts +370 -0
- package/src/system-prompt-generator.ts +122 -0
- package/src/template-manager.ts +321 -0
- package/src/transition-engine.ts +386 -0
- package/src/types.ts +60 -0
- package/src/workflow-manager.ts +601 -0
- package/test/unit/conversation-manager.test.ts +179 -0
- package/test/unit/custom-workflow-loading.test.ts +174 -0
- package/test/unit/directory-linking-and-extensions.test.ts +338 -0
- package/test/unit/file-linking-integration.test.ts +256 -0
- package/test/unit/git-commit-integration.test.ts +91 -0
- package/test/unit/git-manager.test.ts +86 -0
- package/test/unit/install-workflow.test.ts +138 -0
- package/test/unit/instruction-generator.test.ts +247 -0
- package/test/unit/list-workflows-filtering.test.ts +68 -0
- package/test/unit/none-template-functionality.test.ts +224 -0
- package/test/unit/project-docs-manager.test.ts +337 -0
- package/test/unit/state-machine-loader.test.ts +234 -0
- package/test/unit/template-manager.test.ts +217 -0
- package/test/unit/validate-workflow-name.test.ts +150 -0
- package/test/unit/workflow-domain-filtering.test.ts +75 -0
- package/test/unit/workflow-enum-generation.test.ts +92 -0
- package/test/unit/workflow-manager-enhanced-path-resolution.test.ts +369 -0
- package/test/unit/workflow-manager-path-resolution.test.ts +150 -0
- package/test/unit/workflow-migration.test.ts +155 -0
- package/test/unit/workflow-override-by-name.test.ts +116 -0
- package/test/unit/workflow-prioritization.test.ts +38 -0
- package/test/unit/workflow-validation.test.ts +303 -0
- package/test/utils/e2e-test-setup.ts +453 -0
- package/test/utils/run-server-in-dir.sh +27 -0
- package/test/utils/temp-files.ts +308 -0
- package/test/utils/test-access.ts +79 -0
- package/test/utils/test-helpers.ts +286 -0
- package/test/utils/test-setup.ts +78 -0
- package/tsconfig.build.json +21 -0
- package/tsconfig.json +8 -0
- 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
|
+
}
|