edsger 0.2.2 → 0.2.4
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 +17 -0
- package/dist/api/features/batch-operations.d.ts +16 -0
- package/dist/api/features/batch-operations.js +100 -0
- package/dist/api/features/index.d.ts +1 -0
- package/dist/api/features/index.js +1 -0
- package/dist/api/features/test-cases.d.ts +8 -0
- package/dist/api/features/test-cases.js +45 -0
- package/dist/api/features/user-stories.d.ts +8 -0
- package/dist/api/features/user-stories.js +45 -0
- package/dist/cli/commands/refactor-command.d.ts +2 -0
- package/dist/cli/commands/refactor-command.js +107 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +4 -99
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
- package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
- package/dist/phases/code-implementation/analyzer.d.ts +2 -0
- package/dist/phases/code-implementation/analyzer.js +308 -179
- package/dist/phases/code-implementation-verification/index.d.ts +1 -0
- package/dist/phases/code-implementation-verification/index.js +1 -0
- package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
- package/dist/phases/code-implementation-verification/verifier.js +196 -0
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +62 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +450 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +1 -0
- package/dist/phases/feature-analysis/analyzer.js +132 -213
- package/dist/phases/feature-analysis-verification/index.d.ts +1 -0
- package/dist/phases/feature-analysis-verification/index.js +1 -0
- package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
- package/dist/phases/feature-analysis-verification/verifier.js +147 -0
- package/dist/phases/pull-request/creator.js +10 -9
- package/dist/phases/technical-design/analyzer-helpers.d.ts +37 -0
- package/dist/phases/technical-design/analyzer-helpers.js +144 -0
- package/dist/phases/technical-design/analyzer.d.ts +3 -0
- package/dist/phases/technical-design/analyzer.js +282 -312
- package/dist/phases/technical-design-verification/index.d.ts +1 -0
- package/dist/phases/technical-design-verification/index.js +1 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +36 -0
- package/dist/phases/technical-design-verification/verifier.js +147 -0
- package/dist/prompts/checklist-verification.d.ts +11 -0
- package/dist/prompts/checklist-verification.js +153 -0
- package/dist/prompts/code-implementation-improvement.d.ts +5 -0
- package/dist/prompts/code-implementation-improvement.js +108 -0
- package/dist/prompts/code-implementation-verification.d.ts +3 -0
- package/dist/prompts/code-implementation-verification.js +176 -0
- package/dist/prompts/feature-analysis-improvement.d.ts +8 -0
- package/dist/prompts/feature-analysis-improvement.js +109 -0
- package/dist/prompts/feature-analysis.js +1 -1
- package/dist/prompts/formatters.d.ts +17 -4
- package/dist/prompts/formatters.js +41 -12
- package/dist/prompts/technical-design-improvement.d.ts +5 -0
- package/dist/prompts/technical-design-improvement.js +93 -0
- package/dist/prompts/technical-design-verification.d.ts +11 -0
- package/dist/prompts/technical-design-verification.js +134 -0
- package/dist/prompts/technical-design.js +1 -1
- package/dist/services/audit-logs.d.ts +60 -0
- package/dist/services/audit-logs.js +115 -0
- package/dist/services/checklist.d.ts +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/utils/image-downloader.d.ts +32 -0
- package/dist/utils/image-downloader.js +144 -0
- package/dist/workflow-runner/executors/phase-executor.js +56 -12
- package/package.json +1 -1
- package/dist/api/features.d.ts +0 -100
- package/dist/api/features.js +0 -219
- package/dist/logger.d.ts +0 -19
- package/dist/logger.js +0 -52
- package/dist/types.d.ts +0 -99
- package/dist/types.js +0 -1
- package/dist/workflow-runner/config/stage-configs.d.ts +0 -5
- package/dist/workflow-runner/config/stage-configs.js +0 -34
- package/dist/workflow-runner/core/feature-filter.test.d.ts +0 -4
- package/dist/workflow-runner/core/feature-filter.test.js +0 -127
- package/dist/workflow-runner/executors/stage-executor.d.ts +0 -8
- package/dist/workflow-runner/executors/stage-executor.js +0 -49
- package/dist/workflow-runner/feature-fetcher.d.ts +0 -41
- package/dist/workflow-runner/feature-fetcher.js +0 -121
- package/dist/workflow-runner/feature-service.d.ts +0 -17
- package/dist/workflow-runner/feature-service.js +0 -60
- package/dist/workflow-runner/pipeline.d.ts +0 -18
- package/dist/workflow-runner/pipeline.js +0 -197
- package/dist/workflow-runner/processor.d.ts +0 -40
- package/dist/workflow-runner/processor.js +0 -191
- package/dist/workflow-runner/status-updater.d.ts +0 -27
- package/dist/workflow-runner/status-updater.js +0 -80
- package/dist/workflow-runner/types.d.ts +0 -48
- package/dist/workflow-runner/types.js +0 -4
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Audit Logs Service
|
|
3
|
+
* Provides functions to log feature lifecycle events to the database
|
|
4
|
+
*/
|
|
5
|
+
import { callMcpEndpoint } from '../api/mcp-client.js';
|
|
6
|
+
import { logInfo, logError } from '../utils/logger.js';
|
|
7
|
+
/**
|
|
8
|
+
* Log a phase event (start, completion, or failure)
|
|
9
|
+
*/
|
|
10
|
+
export async function logFeaturePhaseEvent(mcpServerUrl, mcpToken, params, verbose) {
|
|
11
|
+
try {
|
|
12
|
+
const result = await callMcpEndpoint(mcpServerUrl, mcpToken, 'feature_audit_logs/create', {
|
|
13
|
+
feature_id: params.featureId,
|
|
14
|
+
event_type: params.eventType,
|
|
15
|
+
phase: params.phase,
|
|
16
|
+
source: 'pipeline',
|
|
17
|
+
result: params.result || 'info',
|
|
18
|
+
metadata: params.metadata || {},
|
|
19
|
+
error_message: params.errorMessage || null,
|
|
20
|
+
});
|
|
21
|
+
if (verbose) {
|
|
22
|
+
logInfo(`✅ Logged ${params.eventType} for phase ${params.phase}`);
|
|
23
|
+
}
|
|
24
|
+
return result?.id || null;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
// Always log errors, not just in verbose mode
|
|
28
|
+
logError(`Failed to log phase event: ${error instanceof Error ? error.message : String(error)}`);
|
|
29
|
+
if (verbose && error instanceof Error && error.stack) {
|
|
30
|
+
logError(`Stack trace: ${error.stack}`);
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Log a checklist validation event
|
|
37
|
+
*/
|
|
38
|
+
export async function logFeatureChecklistEvent(mcpServerUrl, mcpToken, params, verbose) {
|
|
39
|
+
try {
|
|
40
|
+
const result = await callMcpEndpoint(mcpServerUrl, mcpToken, 'feature_audit_logs/create', {
|
|
41
|
+
feature_id: params.featureId,
|
|
42
|
+
event_type: params.eventType,
|
|
43
|
+
source: 'pipeline',
|
|
44
|
+
result: params.result || 'success',
|
|
45
|
+
metadata: {
|
|
46
|
+
checklist_id: params.checklistId,
|
|
47
|
+
...(params.metadata || {}),
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
if (verbose) {
|
|
51
|
+
logInfo(`✅ Logged ${params.eventType} for checklist ${params.checklistId}`);
|
|
52
|
+
}
|
|
53
|
+
return result?.id || null;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// Always log errors, not just in verbose mode
|
|
57
|
+
logError(`Failed to log checklist event: ${error instanceof Error ? error.message : String(error)}`);
|
|
58
|
+
if (verbose && error instanceof Error && error.stack) {
|
|
59
|
+
logError(`Stack trace: ${error.stack}`);
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Log a verification event (dual-agent verification result)
|
|
66
|
+
*/
|
|
67
|
+
export async function logFeatureVerificationEvent(mcpServerUrl, mcpToken, params, verbose) {
|
|
68
|
+
try {
|
|
69
|
+
const eventType = params.result === 'success'
|
|
70
|
+
? 'verification_passed'
|
|
71
|
+
: 'verification_failed';
|
|
72
|
+
const result = await callMcpEndpoint(mcpServerUrl, mcpToken, 'feature_audit_logs/create', {
|
|
73
|
+
feature_id: params.featureId,
|
|
74
|
+
event_type: eventType,
|
|
75
|
+
phase: params.phase,
|
|
76
|
+
source: 'pipeline',
|
|
77
|
+
result: params.result,
|
|
78
|
+
metadata: {
|
|
79
|
+
iteration: params.iteration,
|
|
80
|
+
...params.verificationData,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
if (verbose) {
|
|
84
|
+
logInfo(`✅ Logged verification ${params.result} for phase ${params.phase} (iteration ${params.iteration})`);
|
|
85
|
+
}
|
|
86
|
+
return result?.id || null;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
// Always log errors, not just in verbose mode
|
|
90
|
+
logError(`Failed to log verification event: ${error instanceof Error ? error.message : String(error)}`);
|
|
91
|
+
if (verbose && error instanceof Error && error.stack) {
|
|
92
|
+
logError(`Stack trace: ${error.stack}`);
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get feature timeline (all audit logs)
|
|
99
|
+
*/
|
|
100
|
+
export async function getFeatureTimeline(mcpServerUrl, mcpToken, featureId, verbose) {
|
|
101
|
+
try {
|
|
102
|
+
const result = await callMcpEndpoint(mcpServerUrl, mcpToken, 'feature_audit_logs/list', {
|
|
103
|
+
feature_id: featureId,
|
|
104
|
+
});
|
|
105
|
+
return result?.logs || [];
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
// Always log errors, not just in verbose mode
|
|
109
|
+
logError(`Failed to get feature timeline: ${error instanceof Error ? error.message : String(error)}`);
|
|
110
|
+
if (verbose && error instanceof Error && error.stack) {
|
|
111
|
+
logError(`Stack trace: ${error.stack}`);
|
|
112
|
+
}
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export interface CliOptions {
|
|
|
30
30
|
implement?: string;
|
|
31
31
|
test?: string;
|
|
32
32
|
workflow?: boolean;
|
|
33
|
+
refactor?: boolean;
|
|
33
34
|
}
|
|
34
35
|
export type ReviewSeverity = 'error' | 'warning';
|
|
35
36
|
export type ExitCode = 0 | 1;
|
|
@@ -55,6 +56,24 @@ export interface FeatureAnalysisResult {
|
|
|
55
56
|
value?: any;
|
|
56
57
|
notes?: string;
|
|
57
58
|
}>;
|
|
59
|
+
verification_result?: {
|
|
60
|
+
all_verified: boolean;
|
|
61
|
+
total_items: number;
|
|
62
|
+
confirmed_count: number;
|
|
63
|
+
rejected_count: number;
|
|
64
|
+
uncertain_count: number;
|
|
65
|
+
item_verifications: Array<{
|
|
66
|
+
checklist_item_id: string;
|
|
67
|
+
is_satisfied: boolean;
|
|
68
|
+
verification_status: 'confirmed' | 'rejected' | 'uncertain';
|
|
69
|
+
verification_reason: string;
|
|
70
|
+
concerns?: string[];
|
|
71
|
+
improvement_suggestions?: string[];
|
|
72
|
+
}>;
|
|
73
|
+
summary: string;
|
|
74
|
+
overall_suggestions?: string[];
|
|
75
|
+
};
|
|
76
|
+
iterations?: number;
|
|
58
77
|
};
|
|
59
78
|
}
|
|
60
79
|
export interface FeatureData {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Downloaded image info
|
|
3
|
+
*/
|
|
4
|
+
export interface DownloadedImage {
|
|
5
|
+
url: string;
|
|
6
|
+
localPath: string;
|
|
7
|
+
alt: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Set current feature ID for image downloads
|
|
11
|
+
* Should be called at the start of pipeline execution
|
|
12
|
+
*/
|
|
13
|
+
export declare function setCurrentFeatureId(featureId: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Reset image cache (useful for testing)
|
|
16
|
+
*/
|
|
17
|
+
export declare function resetImageCache(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Download images from URLs to temporary directory for Claude Code to read
|
|
20
|
+
* Uses cache to avoid downloading same image multiple times
|
|
21
|
+
*
|
|
22
|
+
* @param markdown - Markdown content with image URLs
|
|
23
|
+
* @param featureId - Feature ID for directory naming
|
|
24
|
+
*/
|
|
25
|
+
export declare function downloadImagesForClaudeCode(markdown: string, featureId?: string): Promise<{
|
|
26
|
+
processedMarkdown: string;
|
|
27
|
+
downloadedImages: DownloadedImage[];
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Clean markdown by removing width attributes
|
|
31
|
+
*/
|
|
32
|
+
export declare function cleanMarkdownForClaudeCode(markdown: string): string;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createWriteStream } from 'fs';
|
|
2
|
+
import { mkdir, access } from 'fs/promises';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { pipeline } from 'stream/promises';
|
|
6
|
+
import { createHash } from 'crypto';
|
|
7
|
+
import { logInfo, logError } from './logger.js';
|
|
8
|
+
// Cache for downloaded images in current session
|
|
9
|
+
// Key: image URL, Value: local path
|
|
10
|
+
const imageCache = new Map();
|
|
11
|
+
// Current feature ID for directory naming
|
|
12
|
+
let currentFeatureId = null;
|
|
13
|
+
/**
|
|
14
|
+
* Generate hash from URL to use as filename
|
|
15
|
+
* This ensures same URL always maps to same file
|
|
16
|
+
*/
|
|
17
|
+
function hashUrl(url) {
|
|
18
|
+
return createHash('md5').update(url).digest('hex');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get or create temp directory for current feature
|
|
22
|
+
*/
|
|
23
|
+
function getTempDir(featureId) {
|
|
24
|
+
return join(tmpdir(), 'claude-code-images', `feature-${featureId}`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Set current feature ID for image downloads
|
|
28
|
+
* Should be called at the start of pipeline execution
|
|
29
|
+
*/
|
|
30
|
+
export function setCurrentFeatureId(featureId) {
|
|
31
|
+
if (currentFeatureId !== featureId) {
|
|
32
|
+
// Clear cache when switching to different feature
|
|
33
|
+
imageCache.clear();
|
|
34
|
+
currentFeatureId = featureId;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reset image cache (useful for testing)
|
|
39
|
+
*/
|
|
40
|
+
export function resetImageCache() {
|
|
41
|
+
imageCache.clear();
|
|
42
|
+
currentFeatureId = null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Download images from URLs to temporary directory for Claude Code to read
|
|
46
|
+
* Uses cache to avoid downloading same image multiple times
|
|
47
|
+
*
|
|
48
|
+
* @param markdown - Markdown content with image URLs
|
|
49
|
+
* @param featureId - Feature ID for directory naming
|
|
50
|
+
*/
|
|
51
|
+
export async function downloadImagesForClaudeCode(markdown, featureId) {
|
|
52
|
+
if (!markdown) {
|
|
53
|
+
return { processedMarkdown: markdown, downloadedImages: [] };
|
|
54
|
+
}
|
|
55
|
+
// Use provided featureId or fall back to currentFeatureId or timestamp
|
|
56
|
+
const effectiveFeatureId = featureId || currentFeatureId || Date.now().toString();
|
|
57
|
+
// Extract all image URLs from markdown
|
|
58
|
+
const imageRegex = /!\[([^\]]*)\]\(([^)]+)\)(?:\{width=\d+\})?/g;
|
|
59
|
+
const matches = Array.from(markdown.matchAll(imageRegex));
|
|
60
|
+
if (matches.length === 0) {
|
|
61
|
+
return { processedMarkdown: markdown, downloadedImages: [] };
|
|
62
|
+
}
|
|
63
|
+
// Create temp directory for this feature
|
|
64
|
+
const tempDir = getTempDir(effectiveFeatureId);
|
|
65
|
+
await mkdir(tempDir, { recursive: true });
|
|
66
|
+
const downloadedImages = [];
|
|
67
|
+
let processedMarkdown = markdown;
|
|
68
|
+
// Download each image (or use cached version)
|
|
69
|
+
for (let i = 0; i < matches.length; i++) {
|
|
70
|
+
const match = matches[i];
|
|
71
|
+
const alt = match[1] || '';
|
|
72
|
+
const url = match[2];
|
|
73
|
+
try {
|
|
74
|
+
// Check if image is already cached
|
|
75
|
+
let localPath = imageCache.get(url);
|
|
76
|
+
if (localPath) {
|
|
77
|
+
// Verify cached file still exists
|
|
78
|
+
try {
|
|
79
|
+
await access(localPath);
|
|
80
|
+
logInfo(`Using cached image: ${url}`);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Cached file no longer exists, remove from cache
|
|
84
|
+
imageCache.delete(url);
|
|
85
|
+
localPath = undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!localPath) {
|
|
89
|
+
// Download image
|
|
90
|
+
logInfo(`Downloading image ${i + 1}/${matches.length}: ${url}`);
|
|
91
|
+
const response = await fetch(url);
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
logError(`Failed to download image: ${response.statusText}`);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
// Determine file extension from URL or content-type
|
|
97
|
+
let extension = 'png';
|
|
98
|
+
const urlExt = url.split('.').pop()?.toLowerCase();
|
|
99
|
+
if (urlExt && ['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(urlExt)) {
|
|
100
|
+
extension = urlExt;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const contentType = response.headers.get('content-type');
|
|
104
|
+
if (contentType?.includes('jpeg'))
|
|
105
|
+
extension = 'jpg';
|
|
106
|
+
else if (contentType?.includes('png'))
|
|
107
|
+
extension = 'png';
|
|
108
|
+
else if (contentType?.includes('gif'))
|
|
109
|
+
extension = 'gif';
|
|
110
|
+
else if (contentType?.includes('webp'))
|
|
111
|
+
extension = 'webp';
|
|
112
|
+
}
|
|
113
|
+
// Use hash of URL as filename (ensures same URL = same file)
|
|
114
|
+
const urlHash = hashUrl(url);
|
|
115
|
+
const filename = `${urlHash}.${extension}`;
|
|
116
|
+
localPath = join(tempDir, filename);
|
|
117
|
+
// Use Node.js streams to save the file
|
|
118
|
+
const fileStream = createWriteStream(localPath);
|
|
119
|
+
if (response.body) {
|
|
120
|
+
await pipeline(response.body, fileStream);
|
|
121
|
+
}
|
|
122
|
+
// Cache the downloaded image
|
|
123
|
+
imageCache.set(url, localPath);
|
|
124
|
+
logInfo(`Downloaded to: ${localPath}`);
|
|
125
|
+
}
|
|
126
|
+
downloadedImages.push({ url, localPath, alt });
|
|
127
|
+
// Replace URL with local path in markdown
|
|
128
|
+
processedMarkdown = processedMarkdown.replace(match[0], ``);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
logError(`Failed to download image ${url}: ${error}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { processedMarkdown, downloadedImages };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Clean markdown by removing width attributes
|
|
138
|
+
*/
|
|
139
|
+
export function cleanMarkdownForClaudeCode(markdown) {
|
|
140
|
+
if (!markdown)
|
|
141
|
+
return markdown;
|
|
142
|
+
// Remove {width=600} syntax to keep pure markdown
|
|
143
|
+
return markdown.replace(/!\[([^\]]*)\]\(([^)]+)\)\{width=\d+\}/g, '');
|
|
144
|
+
}
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
import { updateFeatureStatusForPhase } from '../../api/features/index.js';
|
|
5
5
|
import { phaseConfigs } from '../config/phase-configs.js';
|
|
6
6
|
import { getChecklistsForPhase, validateChecklistsForPhase, validateRequiredChecklistResults, processChecklistResultsFromResponse, processChecklistItemResultsFromResponse, } from '../../services/checklist.js';
|
|
7
|
+
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
7
8
|
// Higher-order function for phase execution
|
|
8
9
|
export const createPhaseRunner = (phaseConfig) => async (options, config) => {
|
|
9
10
|
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
10
11
|
const { name, checkRequirements, execute, requirementsError } = phaseConfig;
|
|
12
|
+
// Track phase duration for logging
|
|
13
|
+
const phaseStartTime = Date.now();
|
|
11
14
|
try {
|
|
12
15
|
// Check requirements
|
|
13
16
|
const hasRequirements = await checkRequirements();
|
|
@@ -24,6 +27,16 @@ export const createPhaseRunner = (phaseConfig) => async (options, config) => {
|
|
|
24
27
|
if (verbose) {
|
|
25
28
|
console.log(`🎯 Starting ${name} for: ${featureId}`);
|
|
26
29
|
}
|
|
30
|
+
// Log phase start
|
|
31
|
+
await logFeaturePhaseEvent(mcpServerUrl, mcpToken, {
|
|
32
|
+
featureId,
|
|
33
|
+
eventType: 'phase_started',
|
|
34
|
+
phase: name.replace(/-/g, '_'),
|
|
35
|
+
result: 'info',
|
|
36
|
+
metadata: {
|
|
37
|
+
timestamp: new Date().toISOString(),
|
|
38
|
+
},
|
|
39
|
+
}, verbose);
|
|
27
40
|
// Fetch checklists for this phase as context
|
|
28
41
|
let checklistContext = null;
|
|
29
42
|
try {
|
|
@@ -42,18 +55,6 @@ export const createPhaseRunner = (phaseConfig) => async (options, config) => {
|
|
|
42
55
|
}
|
|
43
56
|
// Execute the phase with checklist context
|
|
44
57
|
const result = await execute(options, config, checklistContext);
|
|
45
|
-
console.log({
|
|
46
|
-
result,
|
|
47
|
-
});
|
|
48
|
-
console.log({
|
|
49
|
-
status: result.status,
|
|
50
|
-
});
|
|
51
|
-
console.log({
|
|
52
|
-
data: result.data,
|
|
53
|
-
});
|
|
54
|
-
console.log({
|
|
55
|
-
checklist_item_results: result.data?.checklist_item_results,
|
|
56
|
-
});
|
|
57
58
|
// Process checklist results from phase response if phase was successful
|
|
58
59
|
if (result.status === 'success') {
|
|
59
60
|
try {
|
|
@@ -154,6 +155,35 @@ export const createPhaseRunner = (phaseConfig) => async (options, config) => {
|
|
|
154
155
|
};
|
|
155
156
|
}
|
|
156
157
|
}
|
|
158
|
+
// Log phase completion
|
|
159
|
+
const phaseEndTime = Date.now();
|
|
160
|
+
const phaseDuration = phaseEndTime - phaseStartTime;
|
|
161
|
+
if (result.status === 'success') {
|
|
162
|
+
await logFeaturePhaseEvent(mcpServerUrl, mcpToken, {
|
|
163
|
+
featureId,
|
|
164
|
+
eventType: 'phase_completed',
|
|
165
|
+
phase: name.replace(/-/g, '_'),
|
|
166
|
+
result: 'success',
|
|
167
|
+
metadata: {
|
|
168
|
+
duration_ms: phaseDuration,
|
|
169
|
+
iterations: result.data?.iterations,
|
|
170
|
+
artifacts: result.data,
|
|
171
|
+
checklist_validation: checklistValidation,
|
|
172
|
+
},
|
|
173
|
+
}, verbose);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
await logFeaturePhaseEvent(mcpServerUrl, mcpToken, {
|
|
177
|
+
featureId,
|
|
178
|
+
eventType: 'phase_failed',
|
|
179
|
+
phase: name.replace(/-/g, '_'),
|
|
180
|
+
result: 'error',
|
|
181
|
+
metadata: {
|
|
182
|
+
duration_ms: phaseDuration,
|
|
183
|
+
},
|
|
184
|
+
errorMessage: result.summary || 'Phase execution failed',
|
|
185
|
+
}, verbose);
|
|
186
|
+
}
|
|
157
187
|
return {
|
|
158
188
|
featureId,
|
|
159
189
|
phase: name,
|
|
@@ -169,6 +199,20 @@ export const createPhaseRunner = (phaseConfig) => async (options, config) => {
|
|
|
169
199
|
};
|
|
170
200
|
}
|
|
171
201
|
catch (error) {
|
|
202
|
+
// Log phase failure for exceptions
|
|
203
|
+
const phaseEndTime = Date.now();
|
|
204
|
+
const phaseDuration = phaseEndTime - phaseStartTime;
|
|
205
|
+
await logFeaturePhaseEvent(mcpServerUrl, mcpToken, {
|
|
206
|
+
featureId,
|
|
207
|
+
eventType: 'phase_failed',
|
|
208
|
+
phase: name.replace(/-/g, '_'),
|
|
209
|
+
result: 'error',
|
|
210
|
+
metadata: {
|
|
211
|
+
duration_ms: phaseDuration,
|
|
212
|
+
error_type: 'exception',
|
|
213
|
+
},
|
|
214
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
215
|
+
}, verbose);
|
|
172
216
|
return {
|
|
173
217
|
featureId,
|
|
174
218
|
phase: name,
|
package/package.json
CHANGED
package/dist/api/features.d.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
export interface FeatureInfo {
|
|
2
|
-
id: string;
|
|
3
|
-
name: string;
|
|
4
|
-
description?: string;
|
|
5
|
-
technical_design?: string;
|
|
6
|
-
status: string;
|
|
7
|
-
product_id: string;
|
|
8
|
-
created_at?: string;
|
|
9
|
-
updated_at?: string;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Get feature details by ID
|
|
13
|
-
*/
|
|
14
|
-
export declare function getFeature(mcpServerUrl: string, mcpToken: string, featureId: string, verbose?: boolean): Promise<FeatureInfo>;
|
|
15
|
-
/**
|
|
16
|
-
* Update feature with new data
|
|
17
|
-
*/
|
|
18
|
-
export declare function updateFeature(mcpServerUrl: string, mcpToken: string, featureId: string, updates: {
|
|
19
|
-
technical_design?: string;
|
|
20
|
-
status?: string;
|
|
21
|
-
pull_request_url?: string;
|
|
22
|
-
}, verbose?: boolean): Promise<boolean>;
|
|
23
|
-
/**
|
|
24
|
-
* Update technical design for a feature
|
|
25
|
-
*/
|
|
26
|
-
export declare function updateTechnicalDesign(mcpServerUrl: string, mcpToken: string, featureId: string, technicalDesign: string, verbose?: boolean): Promise<boolean>;
|
|
27
|
-
/**
|
|
28
|
-
* Update feature status
|
|
29
|
-
*/
|
|
30
|
-
export declare function updateFeatureStatus(mcpServerUrl: string, mcpToken: string, featureId: string, status: string, verbose?: boolean): Promise<boolean>;
|
|
31
|
-
export interface UserStory {
|
|
32
|
-
id: string;
|
|
33
|
-
title: string;
|
|
34
|
-
description: string;
|
|
35
|
-
status: string;
|
|
36
|
-
created_at?: string;
|
|
37
|
-
updated_at?: string;
|
|
38
|
-
[key: string]: any;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Get user stories for a feature
|
|
42
|
-
*/
|
|
43
|
-
export declare function getUserStories(mcpServerUrl: string, mcpToken: string, featureId: string, verbose?: boolean): Promise<UserStory[]>;
|
|
44
|
-
/**
|
|
45
|
-
* Create a new user story for a feature
|
|
46
|
-
*/
|
|
47
|
-
export declare function createUserStory(mcpServerUrl: string, mcpToken: string, featureId: string, userStory: {
|
|
48
|
-
title: string;
|
|
49
|
-
description: string;
|
|
50
|
-
status?: string;
|
|
51
|
-
}, verbose?: boolean): Promise<boolean>;
|
|
52
|
-
/**
|
|
53
|
-
* Create multiple user stories for a feature
|
|
54
|
-
*/
|
|
55
|
-
export declare function createUserStories(mcpServerUrl: string, mcpToken: string, featureId: string, userStories: Array<{
|
|
56
|
-
title: string;
|
|
57
|
-
description: string;
|
|
58
|
-
status?: string;
|
|
59
|
-
}>, verbose?: boolean): Promise<boolean>;
|
|
60
|
-
export interface TestCase {
|
|
61
|
-
id: string;
|
|
62
|
-
name: string;
|
|
63
|
-
description: string;
|
|
64
|
-
is_critical: boolean;
|
|
65
|
-
created_at?: string;
|
|
66
|
-
updated_at?: string;
|
|
67
|
-
[key: string]: any;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Get test cases for a feature
|
|
71
|
-
*/
|
|
72
|
-
export declare function getTestCases(mcpServerUrl: string, mcpToken: string, featureId: string, verbose?: boolean): Promise<TestCase[]>;
|
|
73
|
-
/**
|
|
74
|
-
* Create a new test case for a feature
|
|
75
|
-
*/
|
|
76
|
-
export declare function createTestCase(mcpServerUrl: string, mcpToken: string, featureId: string, testCase: {
|
|
77
|
-
name: string;
|
|
78
|
-
description: string;
|
|
79
|
-
is_critical?: boolean;
|
|
80
|
-
}, verbose?: boolean): Promise<boolean>;
|
|
81
|
-
/**
|
|
82
|
-
* Create multiple test cases for a feature
|
|
83
|
-
*/
|
|
84
|
-
export declare function createTestCases(mcpServerUrl: string, mcpToken: string, featureId: string, testCases: Array<{
|
|
85
|
-
name: string;
|
|
86
|
-
description: string;
|
|
87
|
-
is_critical?: boolean;
|
|
88
|
-
}>, verbose?: boolean): Promise<boolean>;
|
|
89
|
-
/**
|
|
90
|
-
* Filter features by status
|
|
91
|
-
*/
|
|
92
|
-
export declare function filterFeaturesByStatus(features: FeatureInfo[], status: string): FeatureInfo[];
|
|
93
|
-
/**
|
|
94
|
-
* Sort features by updated_at (most recent first)
|
|
95
|
-
*/
|
|
96
|
-
export declare function sortFeaturesByUpdatedAt(features: FeatureInfo[]): FeatureInfo[];
|
|
97
|
-
/**
|
|
98
|
-
* Get features with ready_for_dev status for a product
|
|
99
|
-
*/
|
|
100
|
-
export declare function getReadyForDevFeatures(mcpServerUrl: string, mcpToken: string, productId: string, verbose?: boolean): Promise<FeatureInfo[]>;
|