@krr2020/taskflow-core 0.1.0-beta.3 → 0.1.0-beta.5
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/README.md +1 -1
- package/dist/cli/index.js +42 -4
- package/dist/commands/base.d.ts +41 -0
- package/dist/commands/base.js +141 -0
- package/dist/commands/configure.d.ts +29 -0
- package/dist/commands/configure.js +187 -0
- package/dist/commands/init.js +21 -7
- package/dist/commands/prd/create.d.ts +1 -1
- package/dist/commands/prd/create.js +29 -11
- package/dist/commands/prd/generate-arch.d.ts +1 -1
- package/dist/commands/prd/generate-arch.js +6 -5
- package/dist/commands/retro/list.js +6 -5
- package/dist/commands/tasks/generate.d.ts +1 -1
- package/dist/commands/tasks/generate.js +83 -56
- package/dist/commands/upgrade.js +49 -16
- package/dist/commands/workflow/check.d.ts +17 -0
- package/dist/commands/workflow/check.js +482 -35
- package/dist/commands/workflow/commit.js +117 -60
- package/dist/commands/workflow/do.d.ts +1 -0
- package/dist/commands/workflow/do.js +206 -13
- package/dist/commands/workflow/next.js +4 -4
- package/dist/commands/workflow/resume.js +9 -6
- package/dist/commands/workflow/start.js +11 -11
- package/dist/index.d.ts +4 -0
- package/dist/index.js +6 -0
- package/dist/lib/config-paths.d.ts +15 -15
- package/dist/lib/config-paths.js +20 -15
- package/dist/lib/file-validator.d.ts +119 -0
- package/dist/lib/file-validator.js +291 -0
- package/dist/lib/git.js +4 -2
- package/dist/lib/log-parser.d.ts +91 -0
- package/dist/lib/log-parser.js +178 -0
- package/dist/lib/retrospective.d.ts +27 -0
- package/dist/lib/retrospective.js +111 -1
- package/dist/lib/types.d.ts +19 -6
- package/dist/lib/types.js +20 -1
- package/dist/lib/validation.d.ts +0 -3
- package/dist/lib/validation.js +1 -15
- package/dist/llm/base.d.ts +52 -0
- package/dist/llm/base.js +35 -0
- package/dist/llm/factory.d.ts +39 -0
- package/dist/llm/factory.js +102 -0
- package/dist/llm/index.d.ts +7 -0
- package/dist/llm/index.js +7 -0
- package/dist/llm/model-selector.d.ts +71 -0
- package/dist/llm/model-selector.js +139 -0
- package/dist/llm/providers/anthropic.d.ts +31 -0
- package/dist/llm/providers/anthropic.js +116 -0
- package/dist/llm/providers/index.d.ts +6 -0
- package/dist/llm/providers/index.js +6 -0
- package/dist/llm/providers/ollama.d.ts +28 -0
- package/dist/llm/providers/ollama.js +91 -0
- package/dist/llm/providers/openai-compatible.d.ts +30 -0
- package/dist/llm/providers/openai-compatible.js +93 -0
- package/dist/schemas/config.d.ts +82 -0
- package/dist/schemas/config.js +35 -0
- package/dist/schemas/task.d.ts +2 -2
- package/dist/state-machine.d.ts +12 -0
- package/dist/state-machine.js +2 -2
- package/package.json +1 -1
- package/dist/lib/package-manager.d.ts +0 -17
- package/dist/lib/package-manager.js +0 -53
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from "./cli/index.js";
|
|
|
7
7
|
// Export command base (includes CommandContext and CommandResult)
|
|
8
8
|
export * from "./commands/base.js";
|
|
9
9
|
// Export all commands
|
|
10
|
+
export * from "./commands/configure.js";
|
|
10
11
|
export * from "./commands/init.js";
|
|
11
12
|
export * from "./commands/prd/create.js";
|
|
12
13
|
export * from "./commands/prd/generate-arch.js";
|
|
@@ -29,8 +30,13 @@ export * from "./lib/config-paths.js";
|
|
|
29
30
|
export * from "./lib/data-access.js";
|
|
30
31
|
// Export errors
|
|
31
32
|
export * from "./lib/errors.js";
|
|
33
|
+
export * from "./lib/file-validator.js";
|
|
32
34
|
export * from "./lib/git.js";
|
|
35
|
+
// Export log parser and file validator
|
|
36
|
+
export * from "./lib/log-parser.js";
|
|
33
37
|
export * from "./lib/output.js";
|
|
34
38
|
export * from "./lib/retrospective.js";
|
|
35
39
|
export { parseTaskId, STATUS_TRANSITIONS, TaskStatusSchema, } from "./lib/types.js";
|
|
36
40
|
export * from "./lib/validation.js";
|
|
41
|
+
// Export LLM providers
|
|
42
|
+
export * from "./llm/index.js";
|
|
@@ -11,23 +11,23 @@ export declare function getProjectPaths(projectRoot: string): {
|
|
|
11
11
|
configPath: string;
|
|
12
12
|
};
|
|
13
13
|
export declare const PROJECT_INDEX_FILE = "project-index.json";
|
|
14
|
-
export declare const RETROSPECTIVE_FILE = "
|
|
14
|
+
export declare const RETROSPECTIVE_FILE = "retrospective.md";
|
|
15
15
|
export declare const CONFIG_FILE = "taskflow.config.json";
|
|
16
16
|
export declare const TEMPLATE_FILES: {
|
|
17
17
|
readonly protocols: {
|
|
18
|
-
readonly aiProtocol: "protocols/
|
|
19
|
-
readonly taskGenerator: "protocols/
|
|
20
|
-
readonly taskExecutor: "protocols/
|
|
18
|
+
readonly aiProtocol: "protocols/ai-protocol.md";
|
|
19
|
+
readonly taskGenerator: "protocols/task-generator.md";
|
|
20
|
+
readonly taskExecutor: "protocols/task-executor.md";
|
|
21
21
|
};
|
|
22
22
|
readonly prd: {
|
|
23
|
-
readonly prdGenerator: "prd/
|
|
23
|
+
readonly prdGenerator: "prd/prd-generator.md";
|
|
24
24
|
};
|
|
25
25
|
readonly project: {
|
|
26
|
-
readonly codingStandards: "project/
|
|
27
|
-
readonly architectureRules: "project/
|
|
26
|
+
readonly codingStandards: "project/coding-standards.md";
|
|
27
|
+
readonly architectureRules: "project/architecture-rules.md";
|
|
28
28
|
};
|
|
29
29
|
readonly retrospective: {
|
|
30
|
-
readonly retrospective: "retrospective/
|
|
30
|
+
readonly retrospective: "retrospective/retrospective.md";
|
|
31
31
|
};
|
|
32
32
|
readonly skills: {
|
|
33
33
|
readonly backend: "skills/backend.md";
|
|
@@ -39,13 +39,13 @@ export declare const TEMPLATE_FILES: {
|
|
|
39
39
|
};
|
|
40
40
|
};
|
|
41
41
|
export declare const REF_FILES: {
|
|
42
|
-
readonly aiProtocol: "
|
|
43
|
-
readonly taskGenerator: "
|
|
44
|
-
readonly taskExecutor: "
|
|
45
|
-
readonly prdGenerator: "
|
|
46
|
-
readonly codingStandards: "
|
|
47
|
-
readonly architectureRules: "
|
|
48
|
-
readonly retrospective: "
|
|
42
|
+
readonly aiProtocol: "ai-protocol.md";
|
|
43
|
+
readonly taskGenerator: "task-generator.md";
|
|
44
|
+
readonly taskExecutor: "task-executor.md";
|
|
45
|
+
readonly prdGenerator: "prd-generator.md";
|
|
46
|
+
readonly codingStandards: "coding-standards.md";
|
|
47
|
+
readonly architectureRules: "architecture-rules.md";
|
|
48
|
+
readonly retrospective: "retrospective.md";
|
|
49
49
|
};
|
|
50
50
|
export declare const SKILL_FILES: {
|
|
51
51
|
readonly backend: "skills/backend.md";
|
package/dist/lib/config-paths.js
CHANGED
|
@@ -25,26 +25,26 @@ export function getProjectPaths(projectRoot) {
|
|
|
25
25
|
// File Names
|
|
26
26
|
// ============================================================================
|
|
27
27
|
export const PROJECT_INDEX_FILE = "project-index.json";
|
|
28
|
-
export const RETROSPECTIVE_FILE = "
|
|
28
|
+
export const RETROSPECTIVE_FILE = "retrospective.md";
|
|
29
29
|
export const CONFIG_FILE = "taskflow.config.json";
|
|
30
30
|
// ============================================================================
|
|
31
31
|
// Template Structure (source paths in package)
|
|
32
32
|
// ============================================================================
|
|
33
33
|
export const TEMPLATE_FILES = {
|
|
34
34
|
protocols: {
|
|
35
|
-
aiProtocol: "protocols/
|
|
36
|
-
taskGenerator: "protocols/
|
|
37
|
-
taskExecutor: "protocols/
|
|
35
|
+
aiProtocol: "protocols/ai-protocol.md",
|
|
36
|
+
taskGenerator: "protocols/task-generator.md",
|
|
37
|
+
taskExecutor: "protocols/task-executor.md",
|
|
38
38
|
},
|
|
39
39
|
prd: {
|
|
40
|
-
prdGenerator: "prd/
|
|
40
|
+
prdGenerator: "prd/prd-generator.md",
|
|
41
41
|
},
|
|
42
42
|
project: {
|
|
43
|
-
codingStandards: "project/
|
|
44
|
-
architectureRules: "project/
|
|
43
|
+
codingStandards: "project/coding-standards.md",
|
|
44
|
+
architectureRules: "project/architecture-rules.md",
|
|
45
45
|
},
|
|
46
46
|
retrospective: {
|
|
47
|
-
retrospective: "retrospective/
|
|
47
|
+
retrospective: "retrospective/retrospective.md",
|
|
48
48
|
},
|
|
49
49
|
skills: {
|
|
50
50
|
backend: "skills/backend.md",
|
|
@@ -59,12 +59,12 @@ export const TEMPLATE_FILES = {
|
|
|
59
59
|
// Reference Files (destination paths in user's .taskflow/ref directory)
|
|
60
60
|
// ============================================================================
|
|
61
61
|
export const REF_FILES = {
|
|
62
|
-
aiProtocol: "
|
|
63
|
-
taskGenerator: "
|
|
64
|
-
taskExecutor: "
|
|
65
|
-
prdGenerator: "
|
|
66
|
-
codingStandards: "
|
|
67
|
-
architectureRules: "
|
|
62
|
+
aiProtocol: "ai-protocol.md",
|
|
63
|
+
taskGenerator: "task-generator.md",
|
|
64
|
+
taskExecutor: "task-executor.md",
|
|
65
|
+
prdGenerator: "prd-generator.md",
|
|
66
|
+
codingStandards: "coding-standards.md",
|
|
67
|
+
architectureRules: "architecture-rules.md",
|
|
68
68
|
retrospective: RETROSPECTIVE_FILE,
|
|
69
69
|
};
|
|
70
70
|
export const SKILL_FILES = {
|
|
@@ -118,7 +118,12 @@ export function getProjectIndexPath(tasksDir) {
|
|
|
118
118
|
return path.join(tasksDir, PROJECT_INDEX_FILE);
|
|
119
119
|
}
|
|
120
120
|
export function getFeatureFilePath(tasksDir, featurePath) {
|
|
121
|
-
|
|
121
|
+
// If the path ends in .json, return it as is (relative to tasksDir)
|
|
122
|
+
if (featurePath.endsWith(".json")) {
|
|
123
|
+
return path.join(tasksDir, featurePath);
|
|
124
|
+
}
|
|
125
|
+
// Otherwise assume it's a directory and look for a json file with the same name as the directory
|
|
126
|
+
return path.join(tasksDir, featurePath, `${path.basename(featurePath)}.json`);
|
|
122
127
|
}
|
|
123
128
|
export function getRefFilePath(refDir, filename) {
|
|
124
129
|
return path.join(refDir, filename);
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Validator
|
|
3
|
+
* Validates code files using LLM to provide fix suggestions and guidance
|
|
4
|
+
*/
|
|
5
|
+
import type { LLMProvider } from "../llm/base.js";
|
|
6
|
+
export interface ValidationResult {
|
|
7
|
+
/**
|
|
8
|
+
* File path
|
|
9
|
+
*/
|
|
10
|
+
file: string;
|
|
11
|
+
/**
|
|
12
|
+
* Whether file passed validation
|
|
13
|
+
*/
|
|
14
|
+
passed: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Issues found
|
|
17
|
+
*/
|
|
18
|
+
issues: ValidationIssue[];
|
|
19
|
+
/**
|
|
20
|
+
* Suggestions for fixes
|
|
21
|
+
*/
|
|
22
|
+
suggestions: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Validation summary
|
|
25
|
+
*/
|
|
26
|
+
summary: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ValidationIssue {
|
|
29
|
+
/**
|
|
30
|
+
* Severity of the issue
|
|
31
|
+
*/
|
|
32
|
+
severity: "error" | "warning" | "info";
|
|
33
|
+
/**
|
|
34
|
+
* Line number (if available)
|
|
35
|
+
*/
|
|
36
|
+
line?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Issue description
|
|
39
|
+
*/
|
|
40
|
+
message: string;
|
|
41
|
+
/**
|
|
42
|
+
* Code or type of issue
|
|
43
|
+
*/
|
|
44
|
+
code?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Suggested fix
|
|
47
|
+
*/
|
|
48
|
+
suggestedFix?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface ValidatorOptions {
|
|
51
|
+
/**
|
|
52
|
+
* Provider to use for validation
|
|
53
|
+
*/
|
|
54
|
+
provider: LLMProvider;
|
|
55
|
+
/**
|
|
56
|
+
* Whether to include context in validation
|
|
57
|
+
*/
|
|
58
|
+
includeContext?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Whether to provide fix suggestions
|
|
61
|
+
*/
|
|
62
|
+
provideFixes?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Maximum issues to report
|
|
65
|
+
*/
|
|
66
|
+
maxIssues?: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* File Validator class
|
|
70
|
+
* Validates code files using LLM for analysis and fix suggestions
|
|
71
|
+
*/
|
|
72
|
+
export declare class FileValidator {
|
|
73
|
+
private options;
|
|
74
|
+
constructor(options: ValidatorOptions);
|
|
75
|
+
/**
|
|
76
|
+
* Validate a file
|
|
77
|
+
*/
|
|
78
|
+
validate(filePath: string): Promise<ValidationResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Validate multiple files
|
|
81
|
+
*/
|
|
82
|
+
validateFiles(filePaths: string[]): Promise<ValidationResult[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Validate file content
|
|
85
|
+
*/
|
|
86
|
+
validateContent(filePath: string, content: string): Promise<ValidationResult>;
|
|
87
|
+
/**
|
|
88
|
+
* Create validation prompt
|
|
89
|
+
*/
|
|
90
|
+
private createValidationPrompt;
|
|
91
|
+
/**
|
|
92
|
+
* Truncate content to fit within context limits
|
|
93
|
+
*/
|
|
94
|
+
private truncateContent;
|
|
95
|
+
/**
|
|
96
|
+
* Parse validation response from LLM
|
|
97
|
+
*/
|
|
98
|
+
private parseValidationResponse;
|
|
99
|
+
/**
|
|
100
|
+
* Extract suggestions from issues
|
|
101
|
+
*/
|
|
102
|
+
private extractSuggestions;
|
|
103
|
+
/**
|
|
104
|
+
* Create validation summary
|
|
105
|
+
*/
|
|
106
|
+
private createSummary;
|
|
107
|
+
/**
|
|
108
|
+
* Create fallback result when LLM fails
|
|
109
|
+
*/
|
|
110
|
+
private createFallbackResult;
|
|
111
|
+
/**
|
|
112
|
+
* Format validation result for display
|
|
113
|
+
*/
|
|
114
|
+
formatResult(result: ValidationResult): string;
|
|
115
|
+
/**
|
|
116
|
+
* Format multiple validation results
|
|
117
|
+
*/
|
|
118
|
+
formatResults(results: ValidationResult[]): string;
|
|
119
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Validator
|
|
3
|
+
* Validates code files using LLM to provide fix suggestions and guidance
|
|
4
|
+
*/
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
/**
|
|
7
|
+
* File Validator class
|
|
8
|
+
* Validates code files using LLM for analysis and fix suggestions
|
|
9
|
+
*/
|
|
10
|
+
export class FileValidator {
|
|
11
|
+
options;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate a file
|
|
17
|
+
*/
|
|
18
|
+
async validate(filePath) {
|
|
19
|
+
const content = await readFile(filePath, "utf-8");
|
|
20
|
+
return this.validateContent(filePath, content);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Validate multiple files
|
|
24
|
+
*/
|
|
25
|
+
async validateFiles(filePaths) {
|
|
26
|
+
const results = [];
|
|
27
|
+
for (const filePath of filePaths) {
|
|
28
|
+
const result = await this.validate(filePath);
|
|
29
|
+
results.push(result);
|
|
30
|
+
}
|
|
31
|
+
return results;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate file content
|
|
35
|
+
*/
|
|
36
|
+
async validateContent(filePath, content) {
|
|
37
|
+
const provider = this.options.provider;
|
|
38
|
+
// Create validation prompt
|
|
39
|
+
const messages = [
|
|
40
|
+
{
|
|
41
|
+
role: "user",
|
|
42
|
+
content: this.createValidationPrompt(filePath, content),
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
try {
|
|
46
|
+
// Call LLM for validation
|
|
47
|
+
const response = await provider.generate(messages, {
|
|
48
|
+
maxTokens: 2000,
|
|
49
|
+
temperature: 0.3, // Lower temperature for more deterministic results
|
|
50
|
+
});
|
|
51
|
+
// Parse LLM response
|
|
52
|
+
const issues = this.parseValidationResponse(response.content);
|
|
53
|
+
const suggestions = this.extractSuggestions(issues);
|
|
54
|
+
// Determine if passed
|
|
55
|
+
const hasErrors = issues.some((i) => i.severity === "error");
|
|
56
|
+
const hasWarnings = issues.some((i) => i.severity === "warning");
|
|
57
|
+
const summary = this.createSummary(issues, filePath);
|
|
58
|
+
return {
|
|
59
|
+
file: filePath,
|
|
60
|
+
passed: !hasErrors && !hasWarnings,
|
|
61
|
+
issues,
|
|
62
|
+
suggestions,
|
|
63
|
+
summary,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
// Fallback to basic validation if LLM fails
|
|
68
|
+
return this.createFallbackResult(filePath, content, error);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create validation prompt
|
|
73
|
+
*/
|
|
74
|
+
createValidationPrompt(filePath, content) {
|
|
75
|
+
const fileName = filePath.split("/").pop() || "";
|
|
76
|
+
const fileExtension = fileName.split(".").pop() || "";
|
|
77
|
+
const prompt = `Analyze the following ${fileExtension} file and identify any issues:
|
|
78
|
+
|
|
79
|
+
File: ${fileName}
|
|
80
|
+
Path: ${filePath}
|
|
81
|
+
|
|
82
|
+
\`\`\`$${fileExtension}
|
|
83
|
+
${this.truncateContent(content)}
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
Please provide:
|
|
87
|
+
1. Any syntax errors or type errors
|
|
88
|
+
2. Any logical errors or bugs
|
|
89
|
+
3. Code quality issues (naming, complexity, etc.)
|
|
90
|
+
4. Security concerns
|
|
91
|
+
5. Performance concerns
|
|
92
|
+
6. Suggested fixes for issues found
|
|
93
|
+
|
|
94
|
+
Format your response as JSON:
|
|
95
|
+
\`\`\`json
|
|
96
|
+
{
|
|
97
|
+
"issues": [
|
|
98
|
+
{
|
|
99
|
+
"severity": "error" | "warning" | "info",
|
|
100
|
+
"line": number,
|
|
101
|
+
"message": string,
|
|
102
|
+
"code": string,
|
|
103
|
+
"suggestedFix": string
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"suggestions": ["string", "string"]
|
|
107
|
+
}
|
|
108
|
+
\`\`\`
|
|
109
|
+
|
|
110
|
+
If no issues are found, respond with:
|
|
111
|
+
\`\`\`json
|
|
112
|
+
{
|
|
113
|
+
"issues": [],
|
|
114
|
+
"suggestions": ["File looks good"]
|
|
115
|
+
}
|
|
116
|
+
\`\`\``;
|
|
117
|
+
return prompt;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Truncate content to fit within context limits
|
|
121
|
+
*/
|
|
122
|
+
truncateContent(content, maxLength = 8000) {
|
|
123
|
+
if (content.length <= maxLength) {
|
|
124
|
+
return content;
|
|
125
|
+
}
|
|
126
|
+
// Return first part with indicator
|
|
127
|
+
return `${content.substring(0, maxLength)}\n\n... (content truncated)`;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Parse validation response from LLM
|
|
131
|
+
*/
|
|
132
|
+
parseValidationResponse(response) {
|
|
133
|
+
try {
|
|
134
|
+
// Try to extract JSON from response
|
|
135
|
+
const jsonMatch = response.match(/```json\s*([\s\S]*?)\s*```/);
|
|
136
|
+
if (jsonMatch?.[1]) {
|
|
137
|
+
const parsed = JSON.parse(jsonMatch[1]);
|
|
138
|
+
return parsed.issues ?? [];
|
|
139
|
+
}
|
|
140
|
+
// Try to parse entire response as JSON
|
|
141
|
+
const parsed = JSON.parse(response);
|
|
142
|
+
return parsed.issues ?? [];
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// If parsing fails, return empty issues
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Extract suggestions from issues
|
|
151
|
+
*/
|
|
152
|
+
extractSuggestions(issues) {
|
|
153
|
+
const suggestions = [];
|
|
154
|
+
for (const issue of issues) {
|
|
155
|
+
if (issue.suggestedFix) {
|
|
156
|
+
suggestions.push(issue.suggestedFix);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Add general suggestions if needed
|
|
160
|
+
if (issues.length === 0) {
|
|
161
|
+
suggestions.push("No issues found in the file");
|
|
162
|
+
}
|
|
163
|
+
return suggestions;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Create validation summary
|
|
167
|
+
*/
|
|
168
|
+
createSummary(issues, filePath) {
|
|
169
|
+
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
170
|
+
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
171
|
+
const infoCount = issues.filter((i) => i.severity === "info").length;
|
|
172
|
+
const fileName = filePath.split("/").pop() || "";
|
|
173
|
+
if (errorCount === 0 && warningCount === 0 && infoCount === 0) {
|
|
174
|
+
return `${fileName}: No issues found`;
|
|
175
|
+
}
|
|
176
|
+
const parts = [`${fileName}:`];
|
|
177
|
+
if (errorCount > 0) {
|
|
178
|
+
parts.push(`${errorCount} error${errorCount > 1 ? "s" : ""}`);
|
|
179
|
+
}
|
|
180
|
+
if (warningCount > 0) {
|
|
181
|
+
parts.push(`${warningCount} warning${warningCount > 1 ? "s" : ""}`);
|
|
182
|
+
}
|
|
183
|
+
if (infoCount > 0) {
|
|
184
|
+
parts.push(`${infoCount} info`);
|
|
185
|
+
}
|
|
186
|
+
return parts.join(" ");
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Create fallback result when LLM fails
|
|
190
|
+
*/
|
|
191
|
+
createFallbackResult(filePath, content, error) {
|
|
192
|
+
const fileName = filePath.split("/").pop() || "";
|
|
193
|
+
// Basic validation checks
|
|
194
|
+
const issues = [];
|
|
195
|
+
if (content.trim().length === 0) {
|
|
196
|
+
issues.push({
|
|
197
|
+
severity: "error",
|
|
198
|
+
message: "File is empty",
|
|
199
|
+
code: "EMPTY_FILE",
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (content.length > 100000) {
|
|
203
|
+
issues.push({
|
|
204
|
+
severity: "warning",
|
|
205
|
+
message: "File is very large, may affect validation",
|
|
206
|
+
code: "LARGE_FILE",
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
file: filePath,
|
|
211
|
+
passed: issues.length === 0,
|
|
212
|
+
issues,
|
|
213
|
+
suggestions: [
|
|
214
|
+
`Validation error: ${error.message}`,
|
|
215
|
+
"AI validation unavailable - showing basic checks only",
|
|
216
|
+
],
|
|
217
|
+
summary: `${fileName}: Basic validation only (${issues.length} issue${issues.length > 1 ? "s" : ""})`,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Format validation result for display
|
|
222
|
+
*/
|
|
223
|
+
formatResult(result) {
|
|
224
|
+
const lines = [];
|
|
225
|
+
lines.push(`\n${"=".repeat(60)}`);
|
|
226
|
+
lines.push(`File: ${result.file}`);
|
|
227
|
+
lines.push(`Status: ${result.passed ? "✓ PASSED" : "✗ FAILED"}`);
|
|
228
|
+
lines.push("=".repeat(60));
|
|
229
|
+
lines.push("");
|
|
230
|
+
if (result.issues.length > 0) {
|
|
231
|
+
lines.push("Issues:");
|
|
232
|
+
lines.push("");
|
|
233
|
+
for (const issue of result.issues.slice(0, this.options.maxIssues || 10)) {
|
|
234
|
+
const icon = issue.severity === "error"
|
|
235
|
+
? "✗"
|
|
236
|
+
: issue.severity === "warning"
|
|
237
|
+
? "⚠"
|
|
238
|
+
: "ℹ";
|
|
239
|
+
lines.push(` ${icon} ${issue.message}`);
|
|
240
|
+
if (issue.line) {
|
|
241
|
+
lines.push(` Line: ${issue.line}`);
|
|
242
|
+
}
|
|
243
|
+
if (issue.code) {
|
|
244
|
+
lines.push(` Code: ${issue.code}`);
|
|
245
|
+
}
|
|
246
|
+
if (issue.suggestedFix) {
|
|
247
|
+
lines.push(` Fix: ${issue.suggestedFix}`);
|
|
248
|
+
}
|
|
249
|
+
lines.push("");
|
|
250
|
+
}
|
|
251
|
+
if (result.issues.length > (this.options.maxIssues || 10)) {
|
|
252
|
+
const remaining = result.issues.length - (this.options.maxIssues || 10);
|
|
253
|
+
lines.push(` ... and ${remaining} more issue${remaining > 1 ? "s" : ""} (truncated)`);
|
|
254
|
+
lines.push("");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (result.suggestions.length > 0) {
|
|
258
|
+
lines.push("Suggestions:");
|
|
259
|
+
lines.push("");
|
|
260
|
+
for (const suggestion of result.suggestions) {
|
|
261
|
+
lines.push(` • ${suggestion}`);
|
|
262
|
+
}
|
|
263
|
+
lines.push("");
|
|
264
|
+
}
|
|
265
|
+
lines.push(`Summary: ${result.summary}`);
|
|
266
|
+
lines.push("");
|
|
267
|
+
return lines.join("\n");
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Format multiple validation results
|
|
271
|
+
*/
|
|
272
|
+
formatResults(results) {
|
|
273
|
+
const lines = [];
|
|
274
|
+
lines.push(`\n${"=".repeat(80)}`);
|
|
275
|
+
lines.push("Validation Report");
|
|
276
|
+
lines.push("=".repeat(80));
|
|
277
|
+
const passedCount = results.filter((r) => r.passed).length;
|
|
278
|
+
const failedCount = results.filter((r) => !r.passed).length;
|
|
279
|
+
const totalIssues = results.reduce((sum, r) => sum + r.issues.length, 0);
|
|
280
|
+
lines.push(`Files: ${results.length}`);
|
|
281
|
+
lines.push(`Passed: ${passedCount}`);
|
|
282
|
+
lines.push(`Failed: ${failedCount}`);
|
|
283
|
+
lines.push(`Total Issues: ${totalIssues}`);
|
|
284
|
+
lines.push("=".repeat(80));
|
|
285
|
+
lines.push("");
|
|
286
|
+
for (const result of results) {
|
|
287
|
+
lines.push(this.formatResult(result));
|
|
288
|
+
}
|
|
289
|
+
return lines.join("\n");
|
|
290
|
+
}
|
|
291
|
+
}
|
package/dist/lib/git.js
CHANGED
|
@@ -100,8 +100,10 @@ export function verifyBranch(story) {
|
|
|
100
100
|
console.log("Pulling latest changes...");
|
|
101
101
|
execaSync("git", ["pull"], { stdio: "inherit" });
|
|
102
102
|
}
|
|
103
|
-
catch {
|
|
104
|
-
//
|
|
103
|
+
catch (error) {
|
|
104
|
+
// Warn but proceed - branch may be outdated or have no upstream
|
|
105
|
+
console.warn(`Warning: git pull failed - ${error instanceof Error ? error.message : String(error)}`);
|
|
106
|
+
console.warn("Branch may be outdated. Consider pulling manually before merging.");
|
|
105
107
|
}
|
|
106
108
|
execaSync("git", ["checkout", "-b", expected], { stdio: "inherit" });
|
|
107
109
|
console.log("✓ Branch created and checked out");
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log Parser
|
|
3
|
+
* Extracts errors and diagnostic information from build/test logs
|
|
4
|
+
*/
|
|
5
|
+
export interface ParsedError {
|
|
6
|
+
/**
|
|
7
|
+
* File path (relative or absolute)
|
|
8
|
+
*/
|
|
9
|
+
file: string;
|
|
10
|
+
/**
|
|
11
|
+
* Line number where error occurred
|
|
12
|
+
*/
|
|
13
|
+
line: number;
|
|
14
|
+
/**
|
|
15
|
+
* Column number where error occurred
|
|
16
|
+
*/
|
|
17
|
+
column: number;
|
|
18
|
+
/**
|
|
19
|
+
* Error message
|
|
20
|
+
*/
|
|
21
|
+
message: string;
|
|
22
|
+
/**
|
|
23
|
+
* Error code or type (e.g., TS2322, E404)
|
|
24
|
+
*/
|
|
25
|
+
code: string;
|
|
26
|
+
/**
|
|
27
|
+
* Error severity (error, warning, info)
|
|
28
|
+
*/
|
|
29
|
+
severity: "error" | "warning" | "info";
|
|
30
|
+
/**
|
|
31
|
+
* Context lines around the error
|
|
32
|
+
*/
|
|
33
|
+
context?: string[];
|
|
34
|
+
/**
|
|
35
|
+
* Raw log line
|
|
36
|
+
*/
|
|
37
|
+
raw: string;
|
|
38
|
+
}
|
|
39
|
+
export interface LogParseResult {
|
|
40
|
+
/**
|
|
41
|
+
* Parsed errors
|
|
42
|
+
*/
|
|
43
|
+
errors: ParsedError[];
|
|
44
|
+
/**
|
|
45
|
+
* Warning count
|
|
46
|
+
*/
|
|
47
|
+
warningCount: number;
|
|
48
|
+
/**
|
|
49
|
+
* Error count
|
|
50
|
+
*/
|
|
51
|
+
errorCount: number;
|
|
52
|
+
/**
|
|
53
|
+
* Success indicator (no errors found)
|
|
54
|
+
*/
|
|
55
|
+
success: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Log Parser class
|
|
59
|
+
* Parses build/test logs to extract errors and diagnostics
|
|
60
|
+
*/
|
|
61
|
+
export declare class LogParser {
|
|
62
|
+
private patterns;
|
|
63
|
+
/**
|
|
64
|
+
* Parse log string
|
|
65
|
+
*/
|
|
66
|
+
parse(logContent: string): LogParseResult;
|
|
67
|
+
/**
|
|
68
|
+
* Parse log file
|
|
69
|
+
*/
|
|
70
|
+
parseFile(filePath: string): Promise<LogParseResult>;
|
|
71
|
+
/**
|
|
72
|
+
* Create error from regex match
|
|
73
|
+
*/
|
|
74
|
+
private createErrorFromMatch;
|
|
75
|
+
/**
|
|
76
|
+
* Group errors by file
|
|
77
|
+
*/
|
|
78
|
+
groupErrorsByFile(errors: ParsedError[]): Map<string, ParsedError[]>;
|
|
79
|
+
/**
|
|
80
|
+
* Filter errors by severity
|
|
81
|
+
*/
|
|
82
|
+
filterBySeverity(errors: ParsedError[], severity: "error" | "warning" | "info"): ParsedError[];
|
|
83
|
+
/**
|
|
84
|
+
* Filter errors by file
|
|
85
|
+
*/
|
|
86
|
+
filterByFile(errors: ParsedError[], filePattern: string): ParsedError[];
|
|
87
|
+
/**
|
|
88
|
+
* Format error for display
|
|
89
|
+
*/
|
|
90
|
+
formatError(error: ParsedError): string;
|
|
91
|
+
}
|