@zibby/core 0.1.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/LICENSE +21 -0
- package/README.md +147 -0
- package/package.json +94 -0
- package/src/agents/base.js +361 -0
- package/src/constants.js +47 -0
- package/src/enrichment/base.js +49 -0
- package/src/enrichment/enrichers/accessibility-enricher.js +197 -0
- package/src/enrichment/enrichers/dom-enricher.js +171 -0
- package/src/enrichment/enrichers/page-state-enricher.js +129 -0
- package/src/enrichment/enrichers/position-enricher.js +67 -0
- package/src/enrichment/index.js +96 -0
- package/src/enrichment/mcp-integration.js +149 -0
- package/src/enrichment/mcp-ref-enricher.js +78 -0
- package/src/enrichment/pipeline.js +192 -0
- package/src/enrichment/trace-text-enricher.js +115 -0
- package/src/framework/AGENTS.md +98 -0
- package/src/framework/agents/base.js +72 -0
- package/src/framework/agents/claude-strategy.js +278 -0
- package/src/framework/agents/cursor-strategy.js +459 -0
- package/src/framework/agents/index.js +105 -0
- package/src/framework/agents/utils/cursor-output-formatter.js +67 -0
- package/src/framework/agents/utils/openai-proxy-formatter.js +249 -0
- package/src/framework/code-generator.js +301 -0
- package/src/framework/constants.js +33 -0
- package/src/framework/context-loader.js +101 -0
- package/src/framework/function-bridge.js +78 -0
- package/src/framework/function-skill-registry.js +20 -0
- package/src/framework/graph-compiler.js +342 -0
- package/src/framework/graph.js +610 -0
- package/src/framework/index.js +28 -0
- package/src/framework/node-registry.js +163 -0
- package/src/framework/node.js +259 -0
- package/src/framework/output-parser.js +71 -0
- package/src/framework/skill-registry.js +55 -0
- package/src/framework/state-utils.js +52 -0
- package/src/framework/state.js +67 -0
- package/src/framework/tool-resolver.js +65 -0
- package/src/index.js +342 -0
- package/src/runtime/generation/base.js +46 -0
- package/src/runtime/generation/index.js +70 -0
- package/src/runtime/generation/mcp-ref-strategy.js +197 -0
- package/src/runtime/generation/stable-id-strategy.js +170 -0
- package/src/runtime/stable-id-runtime.js +248 -0
- package/src/runtime/verification/base.js +44 -0
- package/src/runtime/verification/index.js +67 -0
- package/src/runtime/verification/playwright-json-strategy.js +119 -0
- package/src/runtime/zibby-runtime.js +299 -0
- package/src/sync/index.js +2 -0
- package/src/sync/uploader.js +29 -0
- package/src/tools/run-playwright-test.js +158 -0
- package/src/utils/adf-converter.js +68 -0
- package/src/utils/ast-utils.js +37 -0
- package/src/utils/ci-setup.js +124 -0
- package/src/utils/cursor-utils.js +71 -0
- package/src/utils/logger.js +144 -0
- package/src/utils/mcp-config-writer.js +115 -0
- package/src/utils/node-schema-parser.js +522 -0
- package/src/utils/post-process-events.js +55 -0
- package/src/utils/result-handler.js +102 -0
- package/src/utils/ripple-effect.js +84 -0
- package/src/utils/selector-generator.js +239 -0
- package/src/utils/streaming-parser.js +387 -0
- package/src/utils/test-post-processor.js +211 -0
- package/src/utils/timeline.js +217 -0
- package/src/utils/trace-parser.js +325 -0
- package/src/utils/video-organizer.js +91 -0
- package/templates/browser-test-automation/README.md +114 -0
- package/templates/browser-test-automation/graph.js +54 -0
- package/templates/browser-test-automation/nodes/execute-live.js +250 -0
- package/templates/browser-test-automation/nodes/generate-script.js +77 -0
- package/templates/browser-test-automation/nodes/index.js +3 -0
- package/templates/browser-test-automation/nodes/preflight.js +59 -0
- package/templates/browser-test-automation/nodes/utils.js +154 -0
- package/templates/browser-test-automation/result-handler.js +286 -0
- package/templates/code-analysis/graph.js +72 -0
- package/templates/code-analysis/index.js +18 -0
- package/templates/code-analysis/nodes/analyze-ticket-node.js +204 -0
- package/templates/code-analysis/nodes/create-pr-node.js +175 -0
- package/templates/code-analysis/nodes/finalize-node.js +118 -0
- package/templates/code-analysis/nodes/generate-code-node.js +425 -0
- package/templates/code-analysis/nodes/generate-test-cases-node.js +376 -0
- package/templates/code-analysis/nodes/services/prMetaService.js +86 -0
- package/templates/code-analysis/nodes/setup-node.js +142 -0
- package/templates/code-analysis/prompts/analyze-ticket.md +181 -0
- package/templates/code-analysis/prompts/generate-code.md +33 -0
- package/templates/code-analysis/prompts/generate-test-cases.md +110 -0
- package/templates/code-analysis/state.js +40 -0
- package/templates/code-implementation/graph.js +35 -0
- package/templates/code-implementation/index.js +7 -0
- package/templates/code-implementation/state.js +14 -0
- package/templates/global-setup.js +56 -0
- package/templates/index.js +94 -0
- package/templates/register-nodes.js +24 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { adfToText } from '../../../src/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.app)*
|
|
172
|
+
`;
|
|
173
|
+
|
|
174
|
+
return body;
|
|
175
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
};
|