greenbump 0.2.1 โ 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/CHANGELOG.md +82 -0
- package/README.md +2 -0
- package/action-dist/index.cjs +1054 -19
- package/competitive-analysis.md +304 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/engine/change-detector.js +152 -0
- package/dist/engine/change-detector.js.map +1 -0
- package/dist/engine/dep-graph.js +101 -0
- package/dist/engine/dep-graph.js.map +1 -0
- package/dist/engine/git.js +10 -0
- package/dist/engine/git.js.map +1 -1
- package/dist/engine/perf/metrics.js +171 -0
- package/dist/engine/perf/metrics.js.map +1 -0
- package/dist/engine/perf/regression.js +115 -0
- package/dist/engine/perf/regression.js.map +1 -0
- package/dist/engine/run.js +71 -2
- package/dist/engine/run.js.map +1 -1
- package/dist/engine/sandbox/docker-manager.js +215 -0
- package/dist/engine/sandbox/docker-manager.js.map +1 -0
- package/dist/engine/sandbox/orchestrator.js +107 -0
- package/dist/engine/sandbox/orchestrator.js.map +1 -0
- package/dist/engine/sandbox/service-detector.js +147 -0
- package/dist/engine/sandbox/service-detector.js.map +1 -0
- package/dist/engine/sandbox/template-generator.js +241 -0
- package/dist/engine/sandbox/template-generator.js.map +1 -0
- package/dist/engine/staged-fix.js +108 -0
- package/dist/engine/staged-fix.js.map +1 -0
- package/dist/engine/stages.js +125 -0
- package/dist/engine/stages.js.map +1 -0
- package/dist/engine/verify.js +121 -0
- package/dist/engine/verify.js.map +1 -0
- package/dist/format.js +20 -0
- package/dist/format.js.map +1 -1
- package/optimization-roadmap.md +772 -0
- package/package.json +4 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
4
|
+
import { exec } from "../git.js";
|
|
5
|
+
/**
|
|
6
|
+
* Check if project has build script
|
|
7
|
+
*/
|
|
8
|
+
async function hasBuildScript(cwd) {
|
|
9
|
+
const pkgPath = join(cwd, "package.json");
|
|
10
|
+
if (!existsSync(pkgPath))
|
|
11
|
+
return false;
|
|
12
|
+
try {
|
|
13
|
+
const content = await readFile(pkgPath, "utf-8");
|
|
14
|
+
const pkg = JSON.parse(content);
|
|
15
|
+
return pkg.scripts?.build !== undefined;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if project has test script
|
|
23
|
+
*/
|
|
24
|
+
async function hasTestScript(cwd) {
|
|
25
|
+
const pkgPath = join(cwd, "package.json");
|
|
26
|
+
if (!existsSync(pkgPath))
|
|
27
|
+
return false;
|
|
28
|
+
try {
|
|
29
|
+
const content = await readFile(pkgPath, "utf-8");
|
|
30
|
+
const pkg = JSON.parse(content);
|
|
31
|
+
return pkg.scripts?.test !== undefined;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get total size of directory in bytes
|
|
39
|
+
*/
|
|
40
|
+
async function getTotalSize(dirPath) {
|
|
41
|
+
if (!existsSync(dirPath))
|
|
42
|
+
return 0;
|
|
43
|
+
try {
|
|
44
|
+
const result = await exec("du", ["-sb", dirPath], { cwd: dirPath });
|
|
45
|
+
const match = result.stdout.match(/^(\d+)/);
|
|
46
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Capture performance baseline before upgrade
|
|
54
|
+
*/
|
|
55
|
+
export async function captureBaseline(cwd) {
|
|
56
|
+
console.log("๐ Capturing performance baseline...");
|
|
57
|
+
const metrics = {
|
|
58
|
+
timestamp: new Date(),
|
|
59
|
+
};
|
|
60
|
+
try {
|
|
61
|
+
// Measure install time
|
|
62
|
+
console.log(" Measuring install time...");
|
|
63
|
+
const installStart = Date.now();
|
|
64
|
+
await exec("npm", ["install"], { cwd });
|
|
65
|
+
metrics.installTime = (Date.now() - installStart) / 1000;
|
|
66
|
+
console.log(` โ Install: ${metrics.installTime.toFixed(1)}s`);
|
|
67
|
+
// Measure build time (if build script exists)
|
|
68
|
+
if (await hasBuildScript(cwd)) {
|
|
69
|
+
console.log(" Measuring build time...");
|
|
70
|
+
const buildStart = Date.now();
|
|
71
|
+
await exec("npm", ["run", "build"], { cwd });
|
|
72
|
+
metrics.buildTime = (Date.now() - buildStart) / 1000;
|
|
73
|
+
console.log(` โ Build: ${metrics.buildTime.toFixed(1)}s`);
|
|
74
|
+
// Measure bundle size
|
|
75
|
+
const distDir = join(cwd, "dist");
|
|
76
|
+
if (existsSync(distDir)) {
|
|
77
|
+
metrics.bundleSize = await getTotalSize(distDir);
|
|
78
|
+
console.log(` โ Bundle: ${(metrics.bundleSize / 1024).toFixed(0)} KB`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Measure test time
|
|
82
|
+
if (await hasTestScript(cwd)) {
|
|
83
|
+
console.log(" Measuring test time...");
|
|
84
|
+
const testStart = Date.now();
|
|
85
|
+
await exec("npm", ["test"], { cwd });
|
|
86
|
+
metrics.testTime = (Date.now() - testStart) / 1000;
|
|
87
|
+
console.log(` โ Test: ${metrics.testTime.toFixed(1)}s`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.warn("โ ๏ธ Warning: Failed to capture complete baseline:", error.message);
|
|
92
|
+
}
|
|
93
|
+
// Save baseline to .greenbump/perf-baseline.json
|
|
94
|
+
const greenbumpDir = join(cwd, ".greenbump");
|
|
95
|
+
if (!existsSync(greenbumpDir)) {
|
|
96
|
+
await mkdir(greenbumpDir, { recursive: true });
|
|
97
|
+
}
|
|
98
|
+
const baselinePath = join(greenbumpDir, "perf-baseline.json");
|
|
99
|
+
await writeFile(baselinePath, JSON.stringify(metrics, null, 2));
|
|
100
|
+
return metrics;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Load baseline from file
|
|
104
|
+
*/
|
|
105
|
+
export async function loadBaseline(cwd) {
|
|
106
|
+
const baselinePath = join(cwd, ".greenbump", "perf-baseline.json");
|
|
107
|
+
if (!existsSync(baselinePath)) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const content = await readFile(baselinePath, "utf-8");
|
|
112
|
+
const baseline = JSON.parse(content);
|
|
113
|
+
// Convert timestamp string back to Date
|
|
114
|
+
if (baseline.timestamp) {
|
|
115
|
+
baseline.timestamp = new Date(baseline.timestamp);
|
|
116
|
+
}
|
|
117
|
+
return baseline;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Collect current performance metrics
|
|
125
|
+
*/
|
|
126
|
+
export async function collectCurrentMetrics(cwd) {
|
|
127
|
+
console.log("๐ Collecting current performance metrics...");
|
|
128
|
+
const metrics = {
|
|
129
|
+
timestamp: new Date(),
|
|
130
|
+
};
|
|
131
|
+
try {
|
|
132
|
+
// Check bundle size if build output exists
|
|
133
|
+
const distDir = join(cwd, "dist");
|
|
134
|
+
if (existsSync(distDir)) {
|
|
135
|
+
metrics.bundleSize = await getTotalSize(distDir);
|
|
136
|
+
}
|
|
137
|
+
// We can't easily measure install/build/test time after the fact
|
|
138
|
+
// These would need to be captured during the actual operations
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.warn("โ ๏ธ Warning: Failed to collect metrics:", error.message);
|
|
142
|
+
}
|
|
143
|
+
return metrics;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Extract performance metrics from Docker container logs
|
|
147
|
+
*/
|
|
148
|
+
export async function extractMetricsFromLogs(logs) {
|
|
149
|
+
const metrics = {};
|
|
150
|
+
// Try to extract timing information from logs
|
|
151
|
+
// This is a simple heuristic-based approach
|
|
152
|
+
// Look for npm install time
|
|
153
|
+
const installMatch = logs.match(/added \d+ packages.*in ([\d.]+)s/);
|
|
154
|
+
if (installMatch) {
|
|
155
|
+
metrics.installTime = parseFloat(installMatch[1]);
|
|
156
|
+
}
|
|
157
|
+
// Look for build time (webpack/vite output)
|
|
158
|
+
const buildMatch = logs.match(/built in ([\d.]+)s/i) ||
|
|
159
|
+
logs.match(/Done in ([\d.]+)s/);
|
|
160
|
+
if (buildMatch) {
|
|
161
|
+
metrics.buildTime = parseFloat(buildMatch[1]);
|
|
162
|
+
}
|
|
163
|
+
// Look for test time
|
|
164
|
+
const testMatch = logs.match(/Tests:\s+\d+ passed.*\(([\d.]+)s\)/) ||
|
|
165
|
+
logs.match(/Ran \d+ tests? in ([\d.]+)s/);
|
|
166
|
+
if (testMatch) {
|
|
167
|
+
metrics.testTime = parseFloat(testMatch[1]);
|
|
168
|
+
}
|
|
169
|
+
return metrics;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/engine/perf/metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const DEFAULT_THRESHOLDS = {
|
|
2
|
+
installTime: 0.30, // 30% slower
|
|
3
|
+
buildTime: 0.20, // 20% slower
|
|
4
|
+
testTime: 0.30, // 30% slower
|
|
5
|
+
bundleSize: 0.15, // 15% larger
|
|
6
|
+
memoryPeak: 0.40, // 40% more memory
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Compare performance metrics and detect regressions
|
|
10
|
+
*/
|
|
11
|
+
export function comparePerformance(baseline, current, thresholds = {}) {
|
|
12
|
+
const mergedThresholds = { ...DEFAULT_THRESHOLDS, ...thresholds };
|
|
13
|
+
const comparisons = [];
|
|
14
|
+
// Compare each metric
|
|
15
|
+
for (const [metric, threshold] of Object.entries(mergedThresholds)) {
|
|
16
|
+
const before = baseline[metric];
|
|
17
|
+
const after = current[metric];
|
|
18
|
+
if (before === undefined || after === undefined)
|
|
19
|
+
continue;
|
|
20
|
+
if (before === 0)
|
|
21
|
+
continue; // Avoid division by zero
|
|
22
|
+
const delta = after - before;
|
|
23
|
+
const percentChange = (delta / before) * 100;
|
|
24
|
+
const isRegression = percentChange > threshold * 100;
|
|
25
|
+
comparisons.push({
|
|
26
|
+
metric,
|
|
27
|
+
before,
|
|
28
|
+
after,
|
|
29
|
+
delta,
|
|
30
|
+
percentChange,
|
|
31
|
+
isRegression,
|
|
32
|
+
severity: isRegression
|
|
33
|
+
? percentChange > threshold * 200
|
|
34
|
+
? "critical"
|
|
35
|
+
: "warning"
|
|
36
|
+
: "ok",
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return comparisons;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if any regressions were detected
|
|
43
|
+
*/
|
|
44
|
+
export function hasRegressions(comparisons) {
|
|
45
|
+
return comparisons.some(c => c.isRegression);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get human-readable metric name
|
|
49
|
+
*/
|
|
50
|
+
export function getMetricDisplayName(metric) {
|
|
51
|
+
const names = {
|
|
52
|
+
installTime: "Install time",
|
|
53
|
+
buildTime: "Build time",
|
|
54
|
+
testTime: "Test time",
|
|
55
|
+
bundleSize: "Bundle size",
|
|
56
|
+
memoryPeak: "Memory usage",
|
|
57
|
+
};
|
|
58
|
+
return names[metric] || metric;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Format metric value for display
|
|
62
|
+
*/
|
|
63
|
+
export function formatMetricValue(metric, value) {
|
|
64
|
+
if (metric === "bundleSize") {
|
|
65
|
+
// Format as KB or MB
|
|
66
|
+
if (value < 1024 * 1024) {
|
|
67
|
+
return `${(value / 1024).toFixed(0)} KB`;
|
|
68
|
+
}
|
|
69
|
+
return `${(value / (1024 * 1024)).toFixed(1)} MB`;
|
|
70
|
+
}
|
|
71
|
+
if (metric === "memoryPeak") {
|
|
72
|
+
return `${value.toFixed(0)} MB`;
|
|
73
|
+
}
|
|
74
|
+
// Time metrics - format as seconds
|
|
75
|
+
return `${value.toFixed(1)}s`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Format percent change for display
|
|
79
|
+
*/
|
|
80
|
+
export function formatPercentChange(percentChange) {
|
|
81
|
+
const sign = percentChange > 0 ? "+" : "";
|
|
82
|
+
return `${sign}${percentChange.toFixed(1)}%`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Display performance comparison results
|
|
86
|
+
*/
|
|
87
|
+
export function displayPerformanceComparison(comparisons) {
|
|
88
|
+
if (comparisons.length === 0) {
|
|
89
|
+
console.log("๐ No performance metrics to compare");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.log("\n๐ Performance Comparison:");
|
|
93
|
+
for (const comparison of comparisons) {
|
|
94
|
+
const name = getMetricDisplayName(comparison.metric);
|
|
95
|
+
const before = formatMetricValue(comparison.metric, comparison.before);
|
|
96
|
+
const after = formatMetricValue(comparison.metric, comparison.after);
|
|
97
|
+
const change = formatPercentChange(comparison.percentChange);
|
|
98
|
+
if (comparison.isRegression) {
|
|
99
|
+
const icon = comparison.severity === "critical" ? "๐ด" : "โ ๏ธ";
|
|
100
|
+
console.log(` ${icon} ${name}: ${before} โ ${after} (${change}) - REGRESSION`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.log(` โ ${name}: ${before} โ ${after} (${change})`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const regressionCount = comparisons.filter(c => c.isRegression).length;
|
|
107
|
+
if (regressionCount > 0) {
|
|
108
|
+
console.log(`\nโ ๏ธ ${regressionCount} performance regression(s) detected!`);
|
|
109
|
+
console.log(" Review changes before committing.\n");
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
console.log("\nโ
No performance regressions detected\n");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=regression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regression.js","sourceRoot":"","sources":["../../../src/engine/perf/regression.ts"],"names":[],"mappings":"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"}
|
package/dist/engine/run.js
CHANGED
|
@@ -6,6 +6,11 @@ import { fetchChangelog } from "./changelog.js";
|
|
|
6
6
|
import { isGitRepo, isTreeClean, currentBranch, createBranch, commitAll, diffStat, fullDiff, } from "./git.js";
|
|
7
7
|
import { runFixLoop } from "../agent/fixer.js";
|
|
8
8
|
import { createProvider } from "../agent/factory.js";
|
|
9
|
+
import { runStaticAnalysis } from "./verify.js";
|
|
10
|
+
import { detectSuspiciousChanges } from "./change-detector.js";
|
|
11
|
+
import { runInSandbox } from "./sandbox/orchestrator.js";
|
|
12
|
+
import { captureBaseline, loadBaseline } from "./perf/metrics.js";
|
|
13
|
+
import { comparePerformance, displayPerformanceComparison, hasRegressions } from "./perf/regression.js";
|
|
9
14
|
export class RunError extends Error {
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
@@ -60,7 +65,13 @@ export async function run(opts) {
|
|
|
60
65
|
await createBranch(cwd, branch);
|
|
61
66
|
log(`created branch ${branch}`);
|
|
62
67
|
}
|
|
63
|
-
// 4. baseline
|
|
68
|
+
// 4. Performance baseline (if regression detection enabled)
|
|
69
|
+
let perfBaseline;
|
|
70
|
+
if (opts.detectRegressions) {
|
|
71
|
+
log("capturing performance baselineโฆ");
|
|
72
|
+
perfBaseline = await captureBaseline(cwd);
|
|
73
|
+
}
|
|
74
|
+
// 4a. baseline โ refuse to run if it's already broken, so we never chase
|
|
64
75
|
// failures that predate the upgrade.
|
|
65
76
|
log("running baseline build + testsโฆ");
|
|
66
77
|
const baseline = await runChecks(pm, cwd, checkOverrides);
|
|
@@ -141,13 +152,71 @@ export async function run(opts) {
|
|
|
141
152
|
summary.usage = fix.usage;
|
|
142
153
|
summary.editedFiles = fix.editedFiles;
|
|
143
154
|
summary.testFilesTouched = fix.editedFiles.filter((f) => /(^|\/)(test|tests|__tests__|spec)(\/|\.)|\.(test|spec)\./i.test(f));
|
|
155
|
+
// Run static analysis (TypeScript + ESLint)
|
|
156
|
+
log("running static analysisโฆ");
|
|
157
|
+
const staticResults = await runStaticAnalysis(cwd, { strictLint: false });
|
|
158
|
+
const typesFailed = staticResults.some(r => r.stage === "types" && !r.passed);
|
|
159
|
+
if (typesFailed) {
|
|
160
|
+
log("โ ๏ธ TypeScript type check failed after fix");
|
|
161
|
+
summary.needsReview = true;
|
|
162
|
+
summary.staticAnalysisWarnings = staticResults
|
|
163
|
+
.filter(r => !r.passed)
|
|
164
|
+
.flatMap(r => r.warnings || []);
|
|
165
|
+
}
|
|
166
|
+
// Detect suspicious changes
|
|
167
|
+
const suspiciousChanges = await detectSuspiciousChanges(cwd);
|
|
168
|
+
const criticalChanges = suspiciousChanges.filter(c => c.severity === "critical");
|
|
169
|
+
if (criticalChanges.length > 0) {
|
|
170
|
+
log("โ ๏ธ Suspicious changes detected (test modifications, large deletions)");
|
|
171
|
+
summary.needsReview = true;
|
|
172
|
+
summary.suspiciousChanges = suspiciousChanges.map(c => `${c.type}: ${c.file} - ${c.description}`);
|
|
173
|
+
}
|
|
174
|
+
// Sandbox verification (if enabled)
|
|
175
|
+
if (opts.sandbox) {
|
|
176
|
+
log("running sandbox verificationโฆ");
|
|
177
|
+
const sandboxResult = await runInSandbox(cwd, {
|
|
178
|
+
enabled: true,
|
|
179
|
+
services: opts.services,
|
|
180
|
+
keepContainer: opts.keepContainer,
|
|
181
|
+
timeout: 600,
|
|
182
|
+
});
|
|
183
|
+
if (!sandboxResult.skipped) {
|
|
184
|
+
summary.sandboxResult = {
|
|
185
|
+
passed: sandboxResult.passed,
|
|
186
|
+
services: sandboxResult.services.map(s => s.displayName),
|
|
187
|
+
};
|
|
188
|
+
if (!sandboxResult.passed) {
|
|
189
|
+
log("โ ๏ธ Sandbox verification failed");
|
|
190
|
+
summary.needsReview = true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Performance regression detection (if enabled)
|
|
195
|
+
if (opts.detectRegressions && perfBaseline) {
|
|
196
|
+
log("checking for performance regressionsโฆ");
|
|
197
|
+
const currentMetrics = await loadBaseline(cwd); // Load the metrics captured during the fix
|
|
198
|
+
if (currentMetrics) {
|
|
199
|
+
const comparisons = comparePerformance(perfBaseline, currentMetrics);
|
|
200
|
+
displayPerformanceComparison(comparisons);
|
|
201
|
+
if (hasRegressions(comparisons)) {
|
|
202
|
+
log("โ ๏ธ Performance regressions detected");
|
|
203
|
+
summary.needsReview = true;
|
|
204
|
+
summary.performanceRegression = {
|
|
205
|
+
detected: true,
|
|
206
|
+
details: comparisons
|
|
207
|
+
.filter(c => c.isRegression)
|
|
208
|
+
.map(c => `${c.metric}: ${c.percentChange.toFixed(1)}% slower/larger`),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
144
213
|
summary.needsReview = computeNeedsReview({
|
|
145
214
|
unverifiable: false,
|
|
146
215
|
neededFix: true,
|
|
147
216
|
fixed: fix.fixed,
|
|
148
217
|
testFilesTouched: summary.testFilesTouched,
|
|
149
218
|
budgetExceeded: fix.budgetExceeded,
|
|
150
|
-
});
|
|
219
|
+
}) || summary.needsReview; // Preserve needsReview if already set by static analysis or suspicious changes
|
|
151
220
|
await maybeCommit(cwd, summary, fix.fixed);
|
|
152
221
|
summary.durationMs = Date.now() - startedAt;
|
|
153
222
|
return summary;
|
package/dist/engine/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/engine/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAuB,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAuB,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EACL,SAAS,EACT,WAAW,EACX,aAAa,EACb,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,QAAQ,GACT,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/engine/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { exec } from "../git.js";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { rm } from "fs/promises";
|
|
5
|
+
/**
|
|
6
|
+
* Check if Docker is available and running
|
|
7
|
+
*/
|
|
8
|
+
export async function checkDockerAvailable() {
|
|
9
|
+
const info = {
|
|
10
|
+
available: false,
|
|
11
|
+
composeAvailable: false,
|
|
12
|
+
};
|
|
13
|
+
try {
|
|
14
|
+
const versionResult = await exec("docker", ["--version"], { cwd: process.cwd() });
|
|
15
|
+
info.version = versionResult.stdout.trim();
|
|
16
|
+
// Check if Docker daemon is running
|
|
17
|
+
await exec("docker", ["ps"], { cwd: process.cwd() });
|
|
18
|
+
info.available = true;
|
|
19
|
+
// Check docker-compose availability
|
|
20
|
+
try {
|
|
21
|
+
await exec("docker-compose", ["--version"], { cwd: process.cwd() });
|
|
22
|
+
info.composeAvailable = true;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// docker-compose not available, but that's okay
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Docker not available
|
|
30
|
+
}
|
|
31
|
+
return info;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build Docker image from Dockerfile
|
|
35
|
+
*/
|
|
36
|
+
export async function buildDockerImage(cwd, imageName, dockerfilePath) {
|
|
37
|
+
console.log(`๐ณ Building Docker image: ${imageName}...`);
|
|
38
|
+
await exec("docker", [
|
|
39
|
+
"build",
|
|
40
|
+
"-t", imageName,
|
|
41
|
+
"-f", dockerfilePath,
|
|
42
|
+
".",
|
|
43
|
+
], { cwd });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Run verification in Docker container
|
|
47
|
+
*/
|
|
48
|
+
export async function runVerificationInContainer(cwd, options) {
|
|
49
|
+
const args = [
|
|
50
|
+
"run",
|
|
51
|
+
"--rm",
|
|
52
|
+
"-v", `${cwd}:/workspace`,
|
|
53
|
+
"-w", "/workspace",
|
|
54
|
+
];
|
|
55
|
+
// Add network mode
|
|
56
|
+
if (options.networkMode) {
|
|
57
|
+
args.push("--network", options.networkMode);
|
|
58
|
+
}
|
|
59
|
+
// Add environment variables
|
|
60
|
+
if (options.env) {
|
|
61
|
+
for (const [key, value] of Object.entries(options.env)) {
|
|
62
|
+
args.push("-e", `${key}=${value}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
args.push(options.image);
|
|
66
|
+
// Run the container with test command
|
|
67
|
+
args.push("sh", "-c", "npm install && npm run build 2>&1 && npm test 2>&1");
|
|
68
|
+
let exitCode = 0;
|
|
69
|
+
let stdout = "";
|
|
70
|
+
let stderr = "";
|
|
71
|
+
let buildSuccess = false;
|
|
72
|
+
let testsPassed = false;
|
|
73
|
+
try {
|
|
74
|
+
const result = await exec("docker", args, {
|
|
75
|
+
cwd,
|
|
76
|
+
timeout: options.timeout || 600000, // 10 minutes default
|
|
77
|
+
});
|
|
78
|
+
stdout = result.stdout;
|
|
79
|
+
stderr = result.stderr;
|
|
80
|
+
exitCode = 0;
|
|
81
|
+
buildSuccess = true;
|
|
82
|
+
testsPassed = true;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
exitCode = error.exitCode || 1;
|
|
86
|
+
stdout = error.stdout || "";
|
|
87
|
+
stderr = error.stderr || "";
|
|
88
|
+
// Determine what failed
|
|
89
|
+
buildSuccess = !stderr.includes("npm run build") && !stdout.includes("build failed");
|
|
90
|
+
testsPassed = false;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
exitCode,
|
|
94
|
+
stdout,
|
|
95
|
+
stderr,
|
|
96
|
+
buildSuccess,
|
|
97
|
+
testsPassed,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Start docker-compose services
|
|
102
|
+
*/
|
|
103
|
+
export async function startComposeServices(cwd, composeFile) {
|
|
104
|
+
console.log("๐ Starting docker-compose services...");
|
|
105
|
+
const projectName = `greenbump-${Date.now()}`;
|
|
106
|
+
await exec("docker-compose", [
|
|
107
|
+
"-f", composeFile,
|
|
108
|
+
"-p", projectName,
|
|
109
|
+
"up", "-d",
|
|
110
|
+
], { cwd });
|
|
111
|
+
return projectName;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if a service is healthy
|
|
115
|
+
*/
|
|
116
|
+
export async function checkServiceHealth(projectName, serviceName) {
|
|
117
|
+
try {
|
|
118
|
+
const result = await exec("docker-compose", ["-p", projectName, "ps", "--filter", `name=${serviceName}`, "--format", "json"], { cwd: process.cwd() });
|
|
119
|
+
const output = result.stdout.trim();
|
|
120
|
+
if (!output)
|
|
121
|
+
return false;
|
|
122
|
+
// Check if service is running
|
|
123
|
+
return output.includes('"State":"running"') || output.includes('healthy');
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Wait for services to become healthy
|
|
131
|
+
*/
|
|
132
|
+
export async function waitForServices(projectName, services, timeout = 60) {
|
|
133
|
+
console.log("โณ Waiting for services to become healthy...");
|
|
134
|
+
const deadline = Date.now() + timeout * 1000;
|
|
135
|
+
const healthyServices = new Set();
|
|
136
|
+
while (Date.now() < deadline && healthyServices.size < services.length) {
|
|
137
|
+
for (const service of services) {
|
|
138
|
+
if (healthyServices.has(service))
|
|
139
|
+
continue;
|
|
140
|
+
const healthy = await checkServiceHealth(projectName, service);
|
|
141
|
+
if (healthy) {
|
|
142
|
+
console.log(`โ ${service} is healthy`);
|
|
143
|
+
healthyServices.add(service);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (healthyServices.size < services.length) {
|
|
147
|
+
await sleep(2000); // Wait 2 seconds before checking again
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (healthyServices.size < services.length) {
|
|
151
|
+
const unhealthy = services.filter(s => !healthyServices.has(s));
|
|
152
|
+
throw new Error(`Timeout waiting for services to become healthy: ${unhealthy.join(", ")}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Stop and remove docker-compose services
|
|
157
|
+
*/
|
|
158
|
+
export async function stopComposeServices(cwd, composeFile, projectName) {
|
|
159
|
+
console.log("๐ Stopping docker-compose services...");
|
|
160
|
+
try {
|
|
161
|
+
await exec("docker-compose", [
|
|
162
|
+
"-f", composeFile,
|
|
163
|
+
"-p", projectName,
|
|
164
|
+
"down", "-v",
|
|
165
|
+
], { cwd });
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
console.warn("Warning: Failed to stop compose services:", error);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Remove Docker image
|
|
173
|
+
*/
|
|
174
|
+
export async function removeDockerImage(imageName) {
|
|
175
|
+
try {
|
|
176
|
+
await exec("docker", ["rmi", imageName], { cwd: process.cwd() });
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Ignore errors when removing image
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Cleanup Docker resources
|
|
184
|
+
*/
|
|
185
|
+
export async function cleanupDocker(cwd, imageName, composeFile, projectName) {
|
|
186
|
+
console.log("๐งน Cleaning up Docker resources...");
|
|
187
|
+
// Stop compose services
|
|
188
|
+
if (composeFile && projectName) {
|
|
189
|
+
await stopComposeServices(cwd, composeFile, projectName);
|
|
190
|
+
}
|
|
191
|
+
// Remove image
|
|
192
|
+
await removeDockerImage(imageName);
|
|
193
|
+
// Remove temporary files
|
|
194
|
+
const tempFiles = [
|
|
195
|
+
join(cwd, ".greenbump-Dockerfile"),
|
|
196
|
+
join(cwd, ".greenbump-compose.yml"),
|
|
197
|
+
];
|
|
198
|
+
for (const file of tempFiles) {
|
|
199
|
+
try {
|
|
200
|
+
if (existsSync(file)) {
|
|
201
|
+
await rm(file);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// Ignore cleanup errors
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Utility: sleep
|
|
211
|
+
*/
|
|
212
|
+
function sleep(ms) {
|
|
213
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=docker-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-manager.js","sourceRoot":"","sources":["../../../src/engine/sandbox/docker-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAuB,EAAE,EAAE,MAAM,aAAa,CAAC;AAwBtD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,IAAI,GAAe;QACvB,SAAS,EAAE,KAAK;QAChB,gBAAgB,EAAE,KAAK;KACxB,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAE3C,oCAAoC;QACpC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAEtB,oCAAoC;QACpC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAW,EACX,SAAiB,EACjB,cAAsB;IAEtB,OAAO,CAAC,GAAG,CAAC,6BAA6B,SAAS,KAAK,CAAC,CAAC;IAEzD,MAAM,IAAI,CACR,QAAQ,EACR;QACE,OAAO;QACP,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,cAAc;QACpB,GAAG;KACJ,EACD,EAAE,GAAG,EAAE,CACR,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,GAAW,EACX,OAA4B;IAE5B,MAAM,IAAI,GAAG;QACX,KAAK;QACL,MAAM;QACN,IAAI,EAAE,GAAG,GAAG,aAAa;QACzB,IAAI,EAAE,YAAY;KACnB,CAAC;IAEF,mBAAmB;IACnB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9C,CAAC;IAED,4BAA4B;IAC5B,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAEzB,sCAAsC;IACtC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,oDAAoD,CAAC,CAAC;IAE5E,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,WAAW,GAAG,KAAK,CAAC;IAExB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE;YACxC,GAAG;YACH,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,MAAM,EAAE,qBAAqB;SAC1D,CAAC,CAAC;QACH,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QACvB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QACvB,QAAQ,GAAG,CAAC,CAAC;QACb,YAAY,GAAG,IAAI,CAAC;QACpB,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;QAC/B,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;QAC5B,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;QAE5B,wBAAwB;QACxB,YAAY,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QACrF,WAAW,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,OAAO;QACL,QAAQ;QACR,MAAM;QACN,MAAM;QACN,YAAY;QACZ,WAAW;KACZ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,GAAW,EACX,WAAmB;IAEnB,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IAEtD,MAAM,WAAW,GAAG,aAAa,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAE9C,MAAM,IAAI,CACR,gBAAgB,EAChB;QACE,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,IAAI;KACX,EACD,EAAE,GAAG,EAAE,CACR,CAAC;IAEF,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,WAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CACvB,gBAAgB,EAChB,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,WAAW,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAChF,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CACvB,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAE1B,8BAA8B;QAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAmB,EACnB,QAAkB,EAClB,UAAkB,EAAE;IAEpB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAE3D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC;IAC7C,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,IAAI,eAAe,CAAC,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QACvE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS;YAE3C,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAC/D,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,aAAa,CAAC,CAAC;gBACvC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,IAAI,eAAe,CAAC,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3C,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,uCAAuC;QAC5D,CAAC;IACH,CAAC;IAED,IAAI,eAAe,CAAC,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,mDAAmD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7F,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAW,EACX,WAAmB,EACnB,WAAmB;IAEnB,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IAEtD,IAAI,CAAC;QACH,MAAM,IAAI,CACR,gBAAgB,EAChB;YACE,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,IAAI;SACb,EACD,EAAE,GAAG,EAAE,CACR,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,SAAiB,EACjB,WAAoB,EACpB,WAAoB;IAEpB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAElD,wBAAwB;IACxB,IAAI,WAAW,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAC3D,CAAC;IAED,eAAe;IACf,MAAM,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAEnC,yBAAyB;IACzB,MAAM,SAAS,GAAG;QAChB,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC;QAClC,IAAI,CAAC,GAAG,EAAE,wBAAwB,CAAC;KACpC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrB,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC"}
|