@zibby/core 0.4.5 โ 0.5.0
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/dist/index.js +147 -150
- package/dist/package.json +1 -8
- package/dist/register-built-in-strategies.js +32 -32
- package/dist/strategies/claude-strategy.js +2 -2
- package/dist/strategies/index.js +45 -45
- package/dist/utils/run-index-post-cli.js +1 -4
- package/package.json +1 -8
- package/dist/templates/browser-test-automation/README.md +0 -136
- package/dist/templates/browser-test-automation/chat.mjs +0 -36
- package/dist/templates/browser-test-automation/graph.mjs +0 -80
- package/dist/templates/browser-test-automation/nodes/cache-replay.mjs +0 -213
- package/dist/templates/browser-test-automation/nodes/execute-live.mjs +0 -254
- package/dist/templates/browser-test-automation/nodes/generate-script.mjs +0 -108
- package/dist/templates/browser-test-automation/nodes/index.mjs +0 -4
- package/dist/templates/browser-test-automation/nodes/preflight.mjs +0 -94
- package/dist/templates/browser-test-automation/nodes/utils.mjs +0 -297
- package/dist/templates/browser-test-automation/pipeline-ids.js +0 -12
- package/dist/templates/browser-test-automation/result-handler.mjs +0 -327
- package/dist/templates/browser-test-automation/run-index.mjs +0 -420
- package/dist/templates/browser-test-automation/run_test.json +0 -358
- package/dist/templates/browser-test-automation/state.js +0 -61
- package/dist/templates/code-analysis/README.md +0 -60
- package/dist/templates/code-analysis/graph.js +0 -72
- package/dist/templates/code-analysis/graph.mjs +0 -33
- package/dist/templates/code-analysis/index.js +0 -18
- package/dist/templates/code-analysis/nodes/analyze-ticket-node.js +0 -204
- package/dist/templates/code-analysis/nodes/create-pr-node.js +0 -175
- package/dist/templates/code-analysis/nodes/finalize-node.js +0 -118
- package/dist/templates/code-analysis/nodes/generate-code-node.js +0 -425
- package/dist/templates/code-analysis/nodes/generate-test-cases-node.js +0 -376
- package/dist/templates/code-analysis/nodes/services/prMetaService.js +0 -86
- package/dist/templates/code-analysis/nodes/setup-node.js +0 -142
- package/dist/templates/code-analysis/prompts/analyze-ticket.md +0 -181
- package/dist/templates/code-analysis/prompts/generate-code.md +0 -33
- package/dist/templates/code-analysis/prompts/generate-test-cases.md +0 -110
- package/dist/templates/code-analysis/state.js +0 -48
- package/dist/templates/generate-test-cases/README.md +0 -72
- package/dist/templates/generate-test-cases/graph.mjs +0 -46
- package/dist/templates/generate-test-cases/nodes/generate-test-cases-node.js +0 -381
- package/dist/templates/generate-test-cases/nodes/setup-node.js +0 -142
- package/dist/templates/generate-test-cases/state.js +0 -54
- package/dist/templates/global-setup.js +0 -56
- package/dist/templates/index.js +0 -147
- package/dist/templates/register-nodes.js +0 -24
- package/templates/browser-test-automation/README.md +0 -136
- package/templates/browser-test-automation/chat.mjs +0 -36
- package/templates/browser-test-automation/graph.mjs +0 -80
- package/templates/browser-test-automation/nodes/cache-replay.mjs +0 -213
- package/templates/browser-test-automation/nodes/execute-live.mjs +0 -254
- package/templates/browser-test-automation/nodes/generate-script.mjs +0 -108
- package/templates/browser-test-automation/nodes/index.mjs +0 -4
- package/templates/browser-test-automation/nodes/preflight.mjs +0 -94
- package/templates/browser-test-automation/nodes/utils.mjs +0 -297
- package/templates/browser-test-automation/pipeline-ids.js +0 -12
- package/templates/browser-test-automation/result-handler.mjs +0 -327
- package/templates/browser-test-automation/run-index.mjs +0 -420
- package/templates/browser-test-automation/run_test.json +0 -358
- package/templates/browser-test-automation/state.js +0 -61
- package/templates/code-analysis/README.md +0 -60
- package/templates/code-analysis/graph.js +0 -72
- package/templates/code-analysis/graph.mjs +0 -33
- package/templates/code-analysis/index.js +0 -18
- package/templates/code-analysis/nodes/analyze-ticket-node.js +0 -204
- package/templates/code-analysis/nodes/create-pr-node.js +0 -175
- package/templates/code-analysis/nodes/finalize-node.js +0 -118
- package/templates/code-analysis/nodes/generate-code-node.js +0 -425
- package/templates/code-analysis/nodes/generate-test-cases-node.js +0 -376
- package/templates/code-analysis/nodes/services/prMetaService.js +0 -86
- package/templates/code-analysis/nodes/setup-node.js +0 -142
- package/templates/code-analysis/prompts/analyze-ticket.md +0 -181
- package/templates/code-analysis/prompts/generate-code.md +0 -33
- package/templates/code-analysis/prompts/generate-test-cases.md +0 -110
- package/templates/code-analysis/state.js +0 -48
- package/templates/generate-test-cases/README.md +0 -72
- package/templates/generate-test-cases/graph.mjs +0 -46
- package/templates/generate-test-cases/nodes/generate-test-cases-node.js +0 -381
- package/templates/generate-test-cases/nodes/setup-node.js +0 -142
- package/templates/generate-test-cases/state.js +0 -54
- package/templates/global-setup.js +0 -56
- package/templates/index.js +0 -147
- package/templates/register-nodes.js +0 -24
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { randomBytes } from 'crypto';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
import { adfToText } from '@zibby/core/utils/adf-converter.js';
|
|
6
|
-
|
|
7
|
-
const generateId = () => randomBytes(16).toString('hex');
|
|
8
|
-
|
|
9
|
-
const SuggestedChangeSchema = z.object({
|
|
10
|
-
field: z.enum(['summary', 'description', 'labels'])
|
|
11
|
-
.describe('Which ticket field this change applies to'),
|
|
12
|
-
|
|
13
|
-
original: z.string()
|
|
14
|
-
.describe('The original value of the field'),
|
|
15
|
-
|
|
16
|
-
suggested: z.string()
|
|
17
|
-
.describe('The suggested new value for the field'),
|
|
18
|
-
|
|
19
|
-
reasoning: z.string()
|
|
20
|
-
.describe('Explanation of why this change improves the ticket')
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// Shared validation schema (used by both AI agent output and node output)
|
|
24
|
-
const ValidationSchema = z.object({
|
|
25
|
-
canProceed: z.boolean()
|
|
26
|
-
.describe('Whether the ticket has enough information to proceed with implementation'),
|
|
27
|
-
|
|
28
|
-
status: z.enum(['valid', 'insufficient_context', 'unclear_requirements', 'invalid_ticket', 'needs_clarification'])
|
|
29
|
-
.describe('Status indicating why we can or cannot proceed'),
|
|
30
|
-
|
|
31
|
-
reasoning: z.string()
|
|
32
|
-
.describe('Explanation of the validation decision - why the ticket is valid or what is missing'),
|
|
33
|
-
|
|
34
|
-
blockers: z.array(z.string())
|
|
35
|
-
.nullable()
|
|
36
|
-
.describe('Specific blockers preventing implementation (if canProceed is false), null if none')
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const AnalysisOutputSchema = z.object({
|
|
40
|
-
validation: ValidationSchema
|
|
41
|
-
.describe('Validation of whether ticket is ready for implementation'),
|
|
42
|
-
|
|
43
|
-
suggestedChanges: z.array(SuggestedChangeSchema)
|
|
44
|
-
.describe('Array of suggested changes to ticket fields'),
|
|
45
|
-
|
|
46
|
-
technicalAnalysis: z.object({
|
|
47
|
-
requirements: z.array(z.string())
|
|
48
|
-
.describe('Key requirements extracted from the ticket'),
|
|
49
|
-
|
|
50
|
-
affectedFiles: z.array(z.string())
|
|
51
|
-
.nullable()
|
|
52
|
-
.describe('Files that will likely need changes (null if unknown). Each path MUST start with a top-level repo directory name (e.g. "my-api/src/...")'),
|
|
53
|
-
|
|
54
|
-
complexity: z.enum(['simple', 'medium', 'complex', 'unknown'])
|
|
55
|
-
.describe('Estimated complexity of the implementation'),
|
|
56
|
-
|
|
57
|
-
risks: z.array(z.string())
|
|
58
|
-
.nullable()
|
|
59
|
-
.describe('Potential risks or challenges, null if none')
|
|
60
|
-
}).describe('Technical analysis of the implementation'),
|
|
61
|
-
|
|
62
|
-
overallSummary: z.string()
|
|
63
|
-
.describe('Brief summary of the analysis findings'),
|
|
64
|
-
|
|
65
|
-
implementationPlan: z.string()
|
|
66
|
-
.describe('Markdown implementation plan for the code generation agent. Include: 1) A brief summary of what to build, 2) Which top-level repositories need changes โ MUST be the exact directory names from Repository Information, NEVER internal sub-modules or Maven modules, 3) An ordered TODO checklist where every file path starts with a top-level repo name (e.g. "In my-api/src/.../Foo.java" NOT "src/.../Foo.java"), 4) Key technical details like function signatures, patterns to follow, and gotchas. This will be passed directly to the coding agent as its instructions.')
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Node output schema (what this node returns to state)
|
|
70
|
-
const AnalyzeTicketNodeOutputSchema = z.object({
|
|
71
|
-
success: z.boolean(),
|
|
72
|
-
analysis: z.object({
|
|
73
|
-
raw: z.string(),
|
|
74
|
-
structured: z.object({
|
|
75
|
-
validation: ValidationSchema,
|
|
76
|
-
suggestedChanges: z.array(z.any()),
|
|
77
|
-
technicalAnalysis: z.any(),
|
|
78
|
-
overallSummary: z.string(),
|
|
79
|
-
implementationPlan: z.string()
|
|
80
|
-
}),
|
|
81
|
-
timestamp: z.string()
|
|
82
|
-
}),
|
|
83
|
-
validation: ValidationSchema // Exposed at root for easy access by conditional logic
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
export const analyzeTicketNode = {
|
|
87
|
-
name: 'analyze_ticket',
|
|
88
|
-
outputSchema: AnalyzeTicketNodeOutputSchema,
|
|
89
|
-
|
|
90
|
-
execute: async (context) => {
|
|
91
|
-
console.log('\n๐ Analyzing ticket with Cursor Agent...');
|
|
92
|
-
|
|
93
|
-
// Extract from context (new unified signature)
|
|
94
|
-
const { state, invokeAgent } = context;
|
|
95
|
-
const { workspace, ticketContext, repos, model } = state.getAll();
|
|
96
|
-
const aiModel = model || ticketContext.model || 'auto';
|
|
97
|
-
|
|
98
|
-
// Prepare description text
|
|
99
|
-
let descriptionText = ticketContext.description || 'No description provided';
|
|
100
|
-
if (typeof descriptionText === 'object') {
|
|
101
|
-
descriptionText = adfToText(descriptionText);
|
|
102
|
-
console.log('โ ๏ธ Description is in ADF format, converted to plain text');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Build prompt values for template rendering
|
|
106
|
-
const promptValues = {
|
|
107
|
-
ticketKey: ticketContext.ticketKey,
|
|
108
|
-
ticketSummary: ticketContext.summary,
|
|
109
|
-
ticketDescription: descriptionText,
|
|
110
|
-
ticketType: ticketContext.type || 'Task',
|
|
111
|
-
ticketPriority: ticketContext.priority || 'Medium',
|
|
112
|
-
ticketLabels: Array.isArray(ticketContext.labels) ? ticketContext.labels.join(', ') : (ticketContext.labels || 'None'),
|
|
113
|
-
ticketComponents: Array.isArray(ticketContext.components)
|
|
114
|
-
? ticketContext.components.map(c => c.name || c).join(', ') || 'None'
|
|
115
|
-
: (ticketContext.components || 'None'),
|
|
116
|
-
additionalContext: ticketContext.additionalContext || null,
|
|
117
|
-
repositories: Array.isArray(repos) ? repos.map(r => ({
|
|
118
|
-
name: r.name,
|
|
119
|
-
...detectProjectInfo(join(workspace, r.name))
|
|
120
|
-
})) : []
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const images = (ticketContext.imageAttachments || [])
|
|
124
|
-
.filter(att => att.base64)
|
|
125
|
-
.map(att => ({ mimeType: att.mimeType, base64: att.base64, filename: att.filename }));
|
|
126
|
-
|
|
127
|
-
if (images.length > 0) {
|
|
128
|
-
console.log(`๐ผ๏ธ Including ${images.length} image attachment(s) for vision analysis`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
console.log(`๐ Running AI Agent to analyze ticket with model: ${aiModel}...`);
|
|
132
|
-
|
|
133
|
-
// Use context.invokeAgent - template rendering handled by framework
|
|
134
|
-
const validatedOutput = await invokeAgent(promptValues, {
|
|
135
|
-
model: aiModel,
|
|
136
|
-
schema: AnalysisOutputSchema,
|
|
137
|
-
images
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Handle both structured response and raw response scenarios
|
|
141
|
-
const output = validatedOutput?.structured || validatedOutput;
|
|
142
|
-
|
|
143
|
-
const suggestedChanges = (output?.suggestedChanges || []).map(change => ({
|
|
144
|
-
id: generateId(),
|
|
145
|
-
...change,
|
|
146
|
-
status: 'pending'
|
|
147
|
-
}));
|
|
148
|
-
|
|
149
|
-
const analysis = {
|
|
150
|
-
raw: JSON.stringify(output),
|
|
151
|
-
structured: {
|
|
152
|
-
validation: output?.validation || { canProceed: false, status: 'invalid_ticket', reasoning: 'Failed to parse validation' },
|
|
153
|
-
suggestedChanges,
|
|
154
|
-
technicalAnalysis: output?.technicalAnalysis || { requirements: [], complexity: 'unknown' },
|
|
155
|
-
overallSummary: output?.overallSummary || 'Analysis failed',
|
|
156
|
-
implementationPlan: output?.implementationPlan || 'No plan generated'
|
|
157
|
-
},
|
|
158
|
-
timestamp: new Date().toISOString()
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
console.log(`โ
Parsed ${suggestedChanges.length} suggested changes`);
|
|
162
|
-
|
|
163
|
-
if (!output?.validation?.canProceed) {
|
|
164
|
-
console.log(`โ ๏ธ Ticket validation failed: ${output?.validation?.status || 'unknown'}`);
|
|
165
|
-
console.log(` Reasoning: ${output?.validation?.reasoning || 'No reasoning provided'}`);
|
|
166
|
-
if (output?.validation?.blockers) {
|
|
167
|
-
console.log(` Blockers:`);
|
|
168
|
-
output.validation.blockers.forEach(blocker => {
|
|
169
|
-
console.log(` - ${blocker}`);
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return {
|
|
175
|
-
success: true,
|
|
176
|
-
analysis,
|
|
177
|
-
validation: output?.validation || { canProceed: false, status: 'invalid_ticket', reasoning: 'No validation data' }
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
function detectProjectInfo(repoPath) {
|
|
183
|
-
const info = {
|
|
184
|
-
framework: 'Unknown',
|
|
185
|
-
language: 'Unknown',
|
|
186
|
-
packageManager: 'Unknown'
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
if (existsSync(join(repoPath, 'package.json'))) {
|
|
190
|
-
info.language = 'JavaScript/TypeScript';
|
|
191
|
-
const pkg = JSON.parse(readFileSync(join(repoPath, 'package.json'), 'utf-8'));
|
|
192
|
-
|
|
193
|
-
if (pkg.dependencies?.react) info.framework = 'React';
|
|
194
|
-
if (pkg.dependencies?.next) info.framework = 'Next.js';
|
|
195
|
-
if (pkg.dependencies?.vue) info.framework = 'Vue';
|
|
196
|
-
if (pkg.dependencies?.express) info.framework = 'Express';
|
|
197
|
-
|
|
198
|
-
if (existsSync(join(repoPath, 'yarn.lock'))) info.packageManager = 'yarn';
|
|
199
|
-
else if (existsSync(join(repoPath, 'pnpm-lock.yaml'))) info.packageManager = 'pnpm';
|
|
200
|
-
else info.packageManager = 'npm';
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return info;
|
|
204
|
-
}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { adfToText } from '@zibby/core/utils/adf-converter.js';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
|
|
5
|
-
const CreatePROutputSchema = z.object({
|
|
6
|
-
success: z.boolean(),
|
|
7
|
-
pullRequests: z.array(z.object({
|
|
8
|
-
number: z.number(),
|
|
9
|
-
url: z.string(),
|
|
10
|
-
title: z.string(),
|
|
11
|
-
repo: z.string(),
|
|
12
|
-
branch: z.string(),
|
|
13
|
-
timestamp: z.string()
|
|
14
|
-
})),
|
|
15
|
-
pr: z.object({
|
|
16
|
-
number: z.number(),
|
|
17
|
-
url: z.string(),
|
|
18
|
-
title: z.string(),
|
|
19
|
-
repo: z.string(),
|
|
20
|
-
branch: z.string(),
|
|
21
|
-
timestamp: z.string()
|
|
22
|
-
}).nullable()
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
export const createPRNode = {
|
|
26
|
-
name: 'create_pr',
|
|
27
|
-
outputSchema: CreatePROutputSchema,
|
|
28
|
-
execute: async (state) => {
|
|
29
|
-
console.log('\n๐ Creating Pull Request(s)...');
|
|
30
|
-
|
|
31
|
-
const { ticketContext, repos, githubToken } = state;
|
|
32
|
-
const codeImpl = state.implement_code_output?.codeImplementation;
|
|
33
|
-
const tests = state.generate_test_cases_output?.tests;
|
|
34
|
-
|
|
35
|
-
if (!codeImpl) {
|
|
36
|
-
throw new Error('No code implementation found');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (!githubToken) {
|
|
40
|
-
console.log('โ ๏ธ No GitHub token found, skipping PR creation');
|
|
41
|
-
return { success: true, pullRequests: [] };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const githubRepos = (repos || []).filter(r => {
|
|
45
|
-
if (r.provider && r.provider !== 'github') return false;
|
|
46
|
-
return r.url?.includes('github.com');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
if (githubRepos.length === 0) {
|
|
50
|
-
console.log('โ ๏ธ No GitHub repositories found, skipping PR creation');
|
|
51
|
-
return { success: true, pullRequests: [] };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const committedRepos = new Set(codeImpl.committedRepos || []);
|
|
55
|
-
const prBody = buildPRBody(ticketContext, codeImpl, tests);
|
|
56
|
-
const pullRequests = [];
|
|
57
|
-
const errors = [];
|
|
58
|
-
|
|
59
|
-
for (const repo of githubRepos) {
|
|
60
|
-
if (committedRepos.size > 0 && !committedRepos.has(repo.name)) {
|
|
61
|
-
console.log(`โญ๏ธ No changes committed in ${repo.name}, skipping PR`);
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const match = repo.url.match(/github\.com\/([^/]+)\/([^/]+)/);
|
|
66
|
-
if (!match) {
|
|
67
|
-
console.warn(`โ ๏ธ Invalid GitHub URL for ${repo.name}: ${repo.url}`);
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const [, owner, repoName] = match;
|
|
72
|
-
const cleanRepoName = repoName.replace(/\.git$/, '');
|
|
73
|
-
|
|
74
|
-
console.log(`๐ค Creating PR in ${owner}/${cleanRepoName}...`);
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
const response = await axios.post(
|
|
78
|
-
`https://api.github.com/repos/${owner}/${cleanRepoName}/pulls`,
|
|
79
|
-
{
|
|
80
|
-
title: `${ticketContext.ticketKey}: ${ticketContext.summary}`,
|
|
81
|
-
head: codeImpl.branchName,
|
|
82
|
-
base: repo.branch || 'main',
|
|
83
|
-
body: prBody,
|
|
84
|
-
draft: false
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
headers: {
|
|
88
|
-
'Authorization': `token ${githubToken}`,
|
|
89
|
-
'Accept': 'application/vnd.github.v3+json',
|
|
90
|
-
'Content-Type': 'application/json'
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const pr = response.data;
|
|
96
|
-
console.log(`โ
PR created: ${pr.html_url} (#${pr.number})`);
|
|
97
|
-
|
|
98
|
-
pullRequests.push({
|
|
99
|
-
number: pr.number,
|
|
100
|
-
url: pr.html_url,
|
|
101
|
-
title: pr.title,
|
|
102
|
-
repo: `${owner}/${cleanRepoName}`,
|
|
103
|
-
branch: codeImpl.branchName,
|
|
104
|
-
timestamp: new Date().toISOString()
|
|
105
|
-
});
|
|
106
|
-
} catch (error) {
|
|
107
|
-
const msg = error.response?.data?.message || error.message;
|
|
108
|
-
console.error(`โ Failed to create PR for ${owner}/${cleanRepoName}: ${msg}`);
|
|
109
|
-
errors.push({ repo: `${owner}/${cleanRepoName}`, error: msg });
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (pullRequests.length === 0 && errors.length > 0) {
|
|
114
|
-
throw new Error(`All PR creations failed: ${errors.map(e => `${e.repo}: ${e.error}`).join('; ')}`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
success: true,
|
|
119
|
-
pullRequests,
|
|
120
|
-
pr: pullRequests[0] || null
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
function buildPRBody(ticketContext, codeImpl, tests) {
|
|
126
|
-
const description = typeof ticketContext.description === 'object'
|
|
127
|
-
? adfToText(ticketContext.description)
|
|
128
|
-
: ticketContext.description;
|
|
129
|
-
let body = `## ๐ซ Ticket: ${ticketContext.ticketKey}
|
|
130
|
-
|
|
131
|
-
${description || ticketContext.summary}
|
|
132
|
-
|
|
133
|
-
## ๐ Changes
|
|
134
|
-
|
|
135
|
-
`;
|
|
136
|
-
|
|
137
|
-
if (codeImpl.metrics) {
|
|
138
|
-
body += `### Metrics
|
|
139
|
-
- **Files Changed**: ${codeImpl.metrics.filesChanged}
|
|
140
|
-
- **Lines Added**: +${codeImpl.metrics.additions}
|
|
141
|
-
- **Lines Deleted**: -${codeImpl.metrics.deletions}
|
|
142
|
-
- **Net Change**: ${codeImpl.metrics.netChange} lines
|
|
143
|
-
|
|
144
|
-
`;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
body += `### Affected Files
|
|
148
|
-
${codeImpl.changedFiles.map(f => `- \`${f}\``).join('\n')}
|
|
149
|
-
|
|
150
|
-
`;
|
|
151
|
-
|
|
152
|
-
if (tests && tests.cases && tests.cases.length > 0) {
|
|
153
|
-
body += `## ๐งช Test Cases
|
|
154
|
-
|
|
155
|
-
Generated ${tests.cases.length} test cases:
|
|
156
|
-
|
|
157
|
-
${tests.cases.map((tc, i) => `### ${i + 1}. ${tc.name}
|
|
158
|
-
|
|
159
|
-
${tc.description}
|
|
160
|
-
|
|
161
|
-
**Steps:**
|
|
162
|
-
${tc.steps.map((s, j) => `${j + 1}. ${s}`).join('\n')}
|
|
163
|
-
|
|
164
|
-
**Expected:** ${tc.expected}
|
|
165
|
-
|
|
166
|
-
`).join('\n')}
|
|
167
|
-
`;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
body += `---
|
|
171
|
-
๐ค *This PR was automatically generated by [Zibby Agent](https://zibby.dev)*
|
|
172
|
-
`;
|
|
173
|
-
|
|
174
|
-
return body;
|
|
175
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
const ReportSchema = z.object({
|
|
4
|
-
status: z.enum(['completed', 'blocked', 'insufficient_context', 'failed'])
|
|
5
|
-
.describe('Final execution status'),
|
|
6
|
-
|
|
7
|
-
summary: z.string()
|
|
8
|
-
.describe('1-2 sentence human-readable summary of what was analyzed/implemented'),
|
|
9
|
-
|
|
10
|
-
storyPoints: z.object({
|
|
11
|
-
points: z.number(),
|
|
12
|
-
confidence: z.enum(['high', 'medium', 'low'])
|
|
13
|
-
}).optional()
|
|
14
|
-
.describe('Story point estimate from analysis'),
|
|
15
|
-
|
|
16
|
-
complexity: z.enum(['simple', 'medium', 'complex', 'unknown']).optional()
|
|
17
|
-
.describe('Implementation complexity from analysis'),
|
|
18
|
-
|
|
19
|
-
codeMetrics: z.object({
|
|
20
|
-
filesChanged: z.number(),
|
|
21
|
-
additions: z.number(),
|
|
22
|
-
deletions: z.number(),
|
|
23
|
-
netChange: z.number()
|
|
24
|
-
}).optional()
|
|
25
|
-
.describe('Code change metrics (only present when code was generated)'),
|
|
26
|
-
|
|
27
|
-
testCount: z.number().optional()
|
|
28
|
-
.describe('Number of test cases generated'),
|
|
29
|
-
|
|
30
|
-
risks: z.array(z.string()).optional()
|
|
31
|
-
.describe('Potential risks or challenges identified during analysis'),
|
|
32
|
-
|
|
33
|
-
blockers: z.array(z.string()).optional()
|
|
34
|
-
.describe('Blockers preventing implementation (when status is blocked/insufficient_context)')
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const FinalizeOutputSchema = z.object({
|
|
38
|
-
success: z.boolean(),
|
|
39
|
-
report: ReportSchema
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
export const finalizeNode = {
|
|
43
|
-
name: 'finalize',
|
|
44
|
-
outputSchema: FinalizeOutputSchema,
|
|
45
|
-
|
|
46
|
-
execute: async (state) => {
|
|
47
|
-
console.log('\n๐ Finalizing...');
|
|
48
|
-
|
|
49
|
-
const { ticketContext } = state;
|
|
50
|
-
|
|
51
|
-
const analysis = state.analysis;
|
|
52
|
-
const codeImpl = state.codeImplementation;
|
|
53
|
-
const tests = state.tests;
|
|
54
|
-
|
|
55
|
-
const structured = analysis?.structured;
|
|
56
|
-
const validation = structured?.validation;
|
|
57
|
-
|
|
58
|
-
let status = 'completed';
|
|
59
|
-
let blockers;
|
|
60
|
-
if (validation && !validation.canProceed) {
|
|
61
|
-
status = validation.status === 'insufficient_context'
|
|
62
|
-
? 'insufficient_context'
|
|
63
|
-
: 'blocked';
|
|
64
|
-
blockers = validation.blockers;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const testCases = tests?.structured?.testCases || tests?.cases || [];
|
|
68
|
-
|
|
69
|
-
const report = {
|
|
70
|
-
status,
|
|
71
|
-
summary: structured?.overallSummary || ticketContext.summary || `Analysis for ${ticketContext.ticketKey}`,
|
|
72
|
-
|
|
73
|
-
...(structured?.storyPointEstimate && {
|
|
74
|
-
storyPoints: {
|
|
75
|
-
points: structured.storyPointEstimate.points,
|
|
76
|
-
confidence: structured.storyPointEstimate.confidence
|
|
77
|
-
}
|
|
78
|
-
}),
|
|
79
|
-
|
|
80
|
-
...(structured?.technicalAnalysis?.complexity && {
|
|
81
|
-
complexity: structured.technicalAnalysis.complexity
|
|
82
|
-
}),
|
|
83
|
-
|
|
84
|
-
...(codeImpl?.metrics && {
|
|
85
|
-
codeMetrics: {
|
|
86
|
-
filesChanged: codeImpl.metrics.filesChanged,
|
|
87
|
-
additions: codeImpl.metrics.additions,
|
|
88
|
-
deletions: codeImpl.metrics.deletions,
|
|
89
|
-
netChange: codeImpl.metrics.netChange
|
|
90
|
-
}
|
|
91
|
-
}),
|
|
92
|
-
|
|
93
|
-
...(testCases.length > 0 && { testCount: testCases.length }),
|
|
94
|
-
|
|
95
|
-
...(structured?.technicalAnalysis?.risks?.length > 0 && {
|
|
96
|
-
risks: structured.technicalAnalysis.risks
|
|
97
|
-
}),
|
|
98
|
-
|
|
99
|
-
...(blockers?.length > 0 && { blockers })
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
console.log(`\n${ '='.repeat(60)}`);
|
|
103
|
-
console.log('FINALIZE SUMMARY');
|
|
104
|
-
console.log('='.repeat(60));
|
|
105
|
-
console.log(JSON.stringify(report, null, 2));
|
|
106
|
-
console.log('='.repeat(60));
|
|
107
|
-
|
|
108
|
-
if (status !== 'completed') {
|
|
109
|
-
console.log(`\nโ ๏ธ Execution blocked: ${status}`);
|
|
110
|
-
if (validation?.reasoning) console.log(` Reason: ${validation.reasoning}`);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
success: true,
|
|
115
|
-
report
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
};
|