buildhive-agent 1.0.0-beta.1
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 +166 -0
- package/dist/__tests__/fakes/FakeDockerManager.d.ts +115 -0
- package/dist/__tests__/fakes/FakeDockerManager.d.ts.map +1 -0
- package/dist/__tests__/fakes/FakeDockerManager.js +203 -0
- package/dist/__tests__/fakes/FakeDockerManager.js.map +1 -0
- package/dist/acceptanceChecker.d.ts +26 -0
- package/dist/acceptanceChecker.d.ts.map +1 -0
- package/dist/acceptanceChecker.js +64 -0
- package/dist/acceptanceChecker.js.map +1 -0
- package/dist/advancedAgent.d.ts +161 -0
- package/dist/advancedAgent.d.ts.map +1 -0
- package/dist/advancedAgent.js +604 -0
- package/dist/advancedAgent.js.map +1 -0
- package/dist/agent.d.ts +101 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +490 -0
- package/dist/agent.js.map +1 -0
- package/dist/api/jobStatusApi.d.ts +88 -0
- package/dist/api/jobStatusApi.d.ts.map +1 -0
- package/dist/api/jobStatusApi.js +240 -0
- package/dist/api/jobStatusApi.js.map +1 -0
- package/dist/autoUpdater.d.ts +135 -0
- package/dist/autoUpdater.d.ts.map +1 -0
- package/dist/autoUpdater.js +494 -0
- package/dist/autoUpdater.js.map +1 -0
- package/dist/cacheManager.d.ts +108 -0
- package/dist/cacheManager.d.ts.map +1 -0
- package/dist/cacheManager.js +300 -0
- package/dist/cacheManager.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +749 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +30 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +35 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +45 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +269 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +193 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +90 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validation.d.ts +28 -0
- package/dist/config/validation.d.ts.map +1 -0
- package/dist/config/validation.js +397 -0
- package/dist/config/validation.js.map +1 -0
- package/dist/docker.d.ts +96 -0
- package/dist/docker.d.ts.map +1 -0
- package/dist/docker.js +411 -0
- package/dist/docker.js.map +1 -0
- package/dist/enhancedJobExecutor.d.ts +81 -0
- package/dist/enhancedJobExecutor.d.ts.map +1 -0
- package/dist/enhancedJobExecutor.js +223 -0
- package/dist/enhancedJobExecutor.js.map +1 -0
- package/dist/executors/executorFactory.d.ts +46 -0
- package/dist/executors/executorFactory.d.ts.map +1 -0
- package/dist/executors/executorFactory.js +80 -0
- package/dist/executors/executorFactory.js.map +1 -0
- package/dist/executors/index.d.ts +7 -0
- package/dist/executors/index.d.ts.map +1 -0
- package/dist/executors/index.js +6 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/executors/nativeExecutor.d.ts +60 -0
- package/dist/executors/nativeExecutor.d.ts.map +1 -0
- package/dist/executors/nativeExecutor.js +311 -0
- package/dist/executors/nativeExecutor.js.map +1 -0
- package/dist/executors/types.d.ts +38 -0
- package/dist/executors/types.d.ts.map +1 -0
- package/dist/executors/types.js +9 -0
- package/dist/executors/types.js.map +1 -0
- package/dist/healthMonitor.d.ts +213 -0
- package/dist/healthMonitor.d.ts.map +1 -0
- package/dist/healthMonitor.js +547 -0
- package/dist/healthMonitor.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/jobExecutor.d.ts +117 -0
- package/dist/jobExecutor.d.ts.map +1 -0
- package/dist/jobExecutor.js +458 -0
- package/dist/jobExecutor.js.map +1 -0
- package/dist/lifecycleExecutor.d.ts +54 -0
- package/dist/lifecycleExecutor.d.ts.map +1 -0
- package/dist/lifecycleExecutor.js +230 -0
- package/dist/lifecycleExecutor.js.map +1 -0
- package/dist/main.d.ts +15 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +77 -0
- package/dist/main.js.map +1 -0
- package/dist/metrics.d.ts +103 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +360 -0
- package/dist/metrics.js.map +1 -0
- package/dist/recipes/builtinRecipes.d.ts +11 -0
- package/dist/recipes/builtinRecipes.d.ts.map +1 -0
- package/dist/recipes/builtinRecipes.js +688 -0
- package/dist/recipes/builtinRecipes.js.map +1 -0
- package/dist/recipes/index.d.ts +18 -0
- package/dist/recipes/index.d.ts.map +1 -0
- package/dist/recipes/index.js +17 -0
- package/dist/recipes/index.js.map +1 -0
- package/dist/recipes/recipeRegistry.d.ts +49 -0
- package/dist/recipes/recipeRegistry.d.ts.map +1 -0
- package/dist/recipes/recipeRegistry.js +264 -0
- package/dist/recipes/recipeRegistry.js.map +1 -0
- package/dist/recipes/types.d.ts +116 -0
- package/dist/recipes/types.d.ts.map +1 -0
- package/dist/recipes/types.js +10 -0
- package/dist/recipes/types.js.map +1 -0
- package/dist/recovery.d.ts +133 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +299 -0
- package/dist/recovery.js.map +1 -0
- package/dist/registration/apiClient.d.ts +44 -0
- package/dist/registration/apiClient.d.ts.map +1 -0
- package/dist/registration/apiClient.js +149 -0
- package/dist/registration/apiClient.js.map +1 -0
- package/dist/registration/index.d.ts +41 -0
- package/dist/registration/index.d.ts.map +1 -0
- package/dist/registration/index.js +141 -0
- package/dist/registration/index.js.map +1 -0
- package/dist/registration/machineId.d.ts +30 -0
- package/dist/registration/machineId.d.ts.map +1 -0
- package/dist/registration/machineId.js +89 -0
- package/dist/registration/machineId.js.map +1 -0
- package/dist/registration/types.d.ts +32 -0
- package/dist/registration/types.d.ts.map +1 -0
- package/dist/registration/types.js +9 -0
- package/dist/registration/types.js.map +1 -0
- package/dist/resourceGovernor.d.ts +57 -0
- package/dist/resourceGovernor.d.ts.map +1 -0
- package/dist/resourceGovernor.js +125 -0
- package/dist/resourceGovernor.js.map +1 -0
- package/dist/security/secretManager.d.ts +107 -0
- package/dist/security/secretManager.d.ts.map +1 -0
- package/dist/security/secretManager.js +361 -0
- package/dist/security/secretManager.js.map +1 -0
- package/dist/security.d.ts +134 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +470 -0
- package/dist/security.js.map +1 -0
- package/dist/storage/artifactUploader.d.ts +155 -0
- package/dist/storage/artifactUploader.d.ts.map +1 -0
- package/dist/storage/artifactUploader.js +554 -0
- package/dist/storage/artifactUploader.js.map +1 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/capabilities.d.ts +23 -0
- package/dist/utils/capabilities.d.ts.map +1 -0
- package/dist/utils/capabilities.js +200 -0
- package/dist/utils/capabilities.js.map +1 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +188 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/sdkScanner.d.ts +105 -0
- package/dist/utils/sdkScanner.d.ts.map +1 -0
- package/dist/utils/sdkScanner.js +459 -0
- package/dist/utils/sdkScanner.js.map +1 -0
- package/dist/websocketClient.d.ts +154 -0
- package/dist/websocketClient.d.ts.map +1 -0
- package/dist/websocketClient.js +422 -0
- package/dist/websocketClient.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job Executor - Docker-based job execution
|
|
3
|
+
*
|
|
4
|
+
* Handles the execution of CI jobs in isolated Docker containers
|
|
5
|
+
* with security, resource limits, and progress reporting.
|
|
6
|
+
*
|
|
7
|
+
* Requirements: 1.1, 1.2, 4.1, 4.2, 4.3, 4.4, 4.5
|
|
8
|
+
*/
|
|
9
|
+
import { AgentConfig } from './config/types.js';
|
|
10
|
+
import { JobSubmissionRequest } from './types.js';
|
|
11
|
+
export interface JobExecutionResult {
|
|
12
|
+
success: boolean;
|
|
13
|
+
exitCode?: number;
|
|
14
|
+
logs?: string;
|
|
15
|
+
errorMessage?: string;
|
|
16
|
+
artifactUrls?: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface JobProgress {
|
|
19
|
+
percentage: number;
|
|
20
|
+
currentStep: string;
|
|
21
|
+
totalSteps?: number;
|
|
22
|
+
currentStepIndex?: number;
|
|
23
|
+
estimatedTimeRemaining?: number;
|
|
24
|
+
}
|
|
25
|
+
export type ProgressCallback = (progress: JobProgress) => void;
|
|
26
|
+
export type LogsCallback = (logs: string) => void;
|
|
27
|
+
export declare class JobExecutor {
|
|
28
|
+
private config;
|
|
29
|
+
private dockerManager;
|
|
30
|
+
private artifactUploader;
|
|
31
|
+
private activeJobs;
|
|
32
|
+
private workspaceRoot;
|
|
33
|
+
constructor(config: AgentConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Execute a job in a Docker container
|
|
36
|
+
*/
|
|
37
|
+
executeJob(job: JobSubmissionRequest, progressCallback: ProgressCallback, logsCallback: LogsCallback): Promise<JobExecutionResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Cancel a running job
|
|
40
|
+
*/
|
|
41
|
+
cancelJob(jobId: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Clean up resources
|
|
44
|
+
*/
|
|
45
|
+
cleanup(): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Clean up orphaned containers from previous agent crashes.
|
|
48
|
+
*/
|
|
49
|
+
cleanupOrphanedContainers(): Promise<number>;
|
|
50
|
+
/**
|
|
51
|
+
* Validate job requirements against agent capabilities
|
|
52
|
+
*/
|
|
53
|
+
private validateJobRequirements;
|
|
54
|
+
/**
|
|
55
|
+
* Create workspace directory for job
|
|
56
|
+
*/
|
|
57
|
+
private createWorkspace;
|
|
58
|
+
/**
|
|
59
|
+
* Prepare workspace with job context
|
|
60
|
+
*/
|
|
61
|
+
private prepareWorkspace;
|
|
62
|
+
/**
|
|
63
|
+
* Build an authenticated clone URL from a plain HTTPS repository URL.
|
|
64
|
+
*
|
|
65
|
+
* Converts https://github.com/user/repo (or https://github.com/user/repo.git)
|
|
66
|
+
* to https://x-access-token:{token}@github.com/user/repo using the
|
|
67
|
+
* x-access-token convention supported by GitHub App installation tokens,
|
|
68
|
+
* fine-grained PATs, and classic PATs.
|
|
69
|
+
*
|
|
70
|
+
* Only HTTPS URLs are rewritten. SSH URLs (git@github.com:...) are returned
|
|
71
|
+
* unchanged because they rely on key-based auth, not token-based.
|
|
72
|
+
*
|
|
73
|
+
* The token is never written to disk or emitted in log lines.
|
|
74
|
+
*/
|
|
75
|
+
private buildAuthenticatedCloneUrl;
|
|
76
|
+
/**
|
|
77
|
+
* Execute a git command in the given working directory.
|
|
78
|
+
*
|
|
79
|
+
* @param args - Arguments to pass to the git binary
|
|
80
|
+
* @param cwd - Working directory for the git process
|
|
81
|
+
* @param env - Additional environment variables merged on top of process.env.
|
|
82
|
+
* Use this to pass GIT_ASKPASS, GIT_TERMINAL_PROMPT=0, etc.
|
|
83
|
+
* @param timeoutMs - Maximum time to wait before killing the process (default 5 min)
|
|
84
|
+
*/
|
|
85
|
+
private executeGitCommand;
|
|
86
|
+
/**
|
|
87
|
+
* Collect build artifacts from container
|
|
88
|
+
*
|
|
89
|
+
* MVP.4.2.4: Artifacts are copied from container and uploaded to configured storage
|
|
90
|
+
*/
|
|
91
|
+
private collectArtifacts;
|
|
92
|
+
/**
|
|
93
|
+
* Clean up job resources
|
|
94
|
+
*/
|
|
95
|
+
private cleanupJob;
|
|
96
|
+
/**
|
|
97
|
+
* Clean up old artifacts based on retention policy (MVP.4.2.4)
|
|
98
|
+
*
|
|
99
|
+
* Should be called periodically by the agent to enforce retention policy.
|
|
100
|
+
*
|
|
101
|
+
* @returns Number of artifacts deleted
|
|
102
|
+
*/
|
|
103
|
+
cleanupOldArtifacts(): Promise<number>;
|
|
104
|
+
/**
|
|
105
|
+
* Get artifact storage statistics (MVP.4.2.4)
|
|
106
|
+
*
|
|
107
|
+
* @returns Storage statistics
|
|
108
|
+
*/
|
|
109
|
+
getArtifactStorageStats(): Promise<{
|
|
110
|
+
type: "local" | "s3";
|
|
111
|
+
totalFiles: number;
|
|
112
|
+
totalSizeBytes: number;
|
|
113
|
+
oldestFileDate?: Date;
|
|
114
|
+
newestFileDate?: Date;
|
|
115
|
+
}>;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=jobExecutor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobExecutor.d.ts","sourceRoot":"","sources":["../src/jobExecutor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAQlD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAC;AAC/D,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAElD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,UAAU,CAA+D;IACjF,OAAO,CAAC,aAAa,CAAS;gBAElB,MAAM,EAAE,WAAW;IAO/B;;OAEG;IACG,UAAU,CACd,GAAG,EAAE,oBAAoB,EACzB,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,kBAAkB,CAAC;IAwJ9B;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB7C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAa9B;;OAEG;IACG,yBAAyB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIlD;;OAEG;YACW,uBAAuB;IA0BrC;;OAEG;YACW,eAAe;IAa7B;;OAEG;YACW,gBAAgB;IAoF9B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IAyCzB;;;;OAIG;YACW,gBAAgB;IAmD9B;;OAEG;YACW,UAAU;IAwBxB;;;;;;OAMG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAa5C;;;;OAIG;IACG,uBAAuB;;;;;;;CAG9B"}
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job Executor - Docker-based job execution
|
|
3
|
+
*
|
|
4
|
+
* Handles the execution of CI jobs in isolated Docker containers
|
|
5
|
+
* with security, resource limits, and progress reporting.
|
|
6
|
+
*
|
|
7
|
+
* Requirements: 1.1, 1.2, 4.1, 4.2, 4.3, 4.4, 4.5
|
|
8
|
+
*/
|
|
9
|
+
import { DockerManager } from './docker.js';
|
|
10
|
+
import { ArtifactUploader } from './storage/artifactUploader.js';
|
|
11
|
+
import { createLogger } from './utils/logger.js';
|
|
12
|
+
import { promises as fs } from 'fs';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import { spawn } from 'child_process';
|
|
15
|
+
const logger = createLogger('jobExecutor');
|
|
16
|
+
export class JobExecutor {
|
|
17
|
+
config;
|
|
18
|
+
dockerManager;
|
|
19
|
+
artifactUploader;
|
|
20
|
+
activeJobs = new Map();
|
|
21
|
+
workspaceRoot;
|
|
22
|
+
constructor(config) {
|
|
23
|
+
this.config = config;
|
|
24
|
+
this.dockerManager = new DockerManager(config.dockerConfig, config.securityConfig);
|
|
25
|
+
this.artifactUploader = new ArtifactUploader(config.storageConfig);
|
|
26
|
+
this.workspaceRoot = join(process.cwd(), 'workspaces');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Execute a job in a Docker container
|
|
30
|
+
*/
|
|
31
|
+
async executeJob(job, progressCallback, logsCallback) {
|
|
32
|
+
const jobId = job.externalId;
|
|
33
|
+
const workDir = await this.createWorkspace(jobId);
|
|
34
|
+
logger.info(`Executing job ${jobId} in workspace: ${workDir}`);
|
|
35
|
+
try {
|
|
36
|
+
// Step 1: Validate job requirements
|
|
37
|
+
progressCallback({
|
|
38
|
+
percentage: 5,
|
|
39
|
+
currentStep: 'Validating job requirements',
|
|
40
|
+
totalSteps: 8,
|
|
41
|
+
currentStepIndex: 1
|
|
42
|
+
});
|
|
43
|
+
await this.validateJobRequirements(job);
|
|
44
|
+
logsCallback(`[INFO] Job requirements validated for ${jobId}`);
|
|
45
|
+
// Step 2: Prepare workspace
|
|
46
|
+
progressCallback({
|
|
47
|
+
percentage: 15,
|
|
48
|
+
currentStep: 'Preparing workspace',
|
|
49
|
+
totalSteps: 8,
|
|
50
|
+
currentStepIndex: 2
|
|
51
|
+
});
|
|
52
|
+
await this.prepareWorkspace(workDir, job);
|
|
53
|
+
logsCallback(`[INFO] Workspace prepared at ${workDir}`);
|
|
54
|
+
// Step 3: Pull Docker image
|
|
55
|
+
progressCallback({
|
|
56
|
+
percentage: 25,
|
|
57
|
+
currentStep: 'Pulling Docker image',
|
|
58
|
+
totalSteps: 8,
|
|
59
|
+
currentStepIndex: 3
|
|
60
|
+
});
|
|
61
|
+
await this.dockerManager.pullImage(job.dockerImage);
|
|
62
|
+
logsCallback(`[INFO] Docker image pulled: ${job.dockerImage}`);
|
|
63
|
+
// Step 4: Create container
|
|
64
|
+
progressCallback({
|
|
65
|
+
percentage: 35,
|
|
66
|
+
currentStep: 'Creating container',
|
|
67
|
+
totalSteps: 8,
|
|
68
|
+
currentStepIndex: 4
|
|
69
|
+
});
|
|
70
|
+
const containerId = await this.dockerManager.createContainer({
|
|
71
|
+
image: job.dockerImage,
|
|
72
|
+
workDir: '/workspace',
|
|
73
|
+
environment: job.environment || {},
|
|
74
|
+
volumeMounts: [
|
|
75
|
+
{
|
|
76
|
+
hostPath: workDir,
|
|
77
|
+
containerPath: '/workspace',
|
|
78
|
+
readOnly: false
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
});
|
|
82
|
+
this.activeJobs.set(jobId, { containerId, workDir });
|
|
83
|
+
logsCallback(`[INFO] Container created: ${containerId}`);
|
|
84
|
+
// Step 5: Start container
|
|
85
|
+
progressCallback({
|
|
86
|
+
percentage: 45,
|
|
87
|
+
currentStep: 'Starting container',
|
|
88
|
+
totalSteps: 8,
|
|
89
|
+
currentStepIndex: 5
|
|
90
|
+
});
|
|
91
|
+
await this.dockerManager.startContainer(containerId);
|
|
92
|
+
logsCallback(`[INFO] Container started: ${containerId}`);
|
|
93
|
+
// Step 6: Execute build command
|
|
94
|
+
progressCallback({
|
|
95
|
+
percentage: 55,
|
|
96
|
+
currentStep: 'Executing build command',
|
|
97
|
+
totalSteps: 8,
|
|
98
|
+
currentStepIndex: 6
|
|
99
|
+
});
|
|
100
|
+
logsCallback(`[INFO] Executing command: ${job.buildCommand}`);
|
|
101
|
+
const executionResult = await this.dockerManager.executeCommand(containerId, job.buildCommand, {
|
|
102
|
+
timeout: this.config.jobTimeoutMinutes * 60 * 1000,
|
|
103
|
+
onOutput: (output) => {
|
|
104
|
+
logsCallback(`[BUILD] ${output}`);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
// Step 7: Collect artifacts
|
|
108
|
+
progressCallback({
|
|
109
|
+
percentage: 85,
|
|
110
|
+
currentStep: 'Collecting artifacts',
|
|
111
|
+
totalSteps: 8,
|
|
112
|
+
currentStepIndex: 7
|
|
113
|
+
});
|
|
114
|
+
const artifactUrls = await this.collectArtifacts(containerId, workDir, job.artifacts || []);
|
|
115
|
+
if (artifactUrls.length > 0) {
|
|
116
|
+
logsCallback(`[INFO] Collected ${artifactUrls.length} artifacts`);
|
|
117
|
+
}
|
|
118
|
+
// Step 8: Cleanup
|
|
119
|
+
progressCallback({
|
|
120
|
+
percentage: 95,
|
|
121
|
+
currentStep: 'Cleaning up',
|
|
122
|
+
totalSteps: 8,
|
|
123
|
+
currentStepIndex: 8
|
|
124
|
+
});
|
|
125
|
+
await this.cleanupJob(jobId);
|
|
126
|
+
logsCallback(`[INFO] Job cleanup completed`);
|
|
127
|
+
// Final progress
|
|
128
|
+
progressCallback({
|
|
129
|
+
percentage: 100,
|
|
130
|
+
currentStep: 'Job completed',
|
|
131
|
+
totalSteps: 8,
|
|
132
|
+
currentStepIndex: 8
|
|
133
|
+
});
|
|
134
|
+
const success = executionResult.exitCode === 0;
|
|
135
|
+
logsCallback(`[INFO] Job ${jobId} ${success ? 'completed successfully' : 'failed'} (exit code: ${executionResult.exitCode})`);
|
|
136
|
+
return {
|
|
137
|
+
success,
|
|
138
|
+
exitCode: executionResult.exitCode,
|
|
139
|
+
logs: executionResult.output,
|
|
140
|
+
artifactUrls
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
logger.error(`Job execution failed for ${jobId}:`, error);
|
|
145
|
+
logsCallback(`[ERROR] Job execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
146
|
+
// Cleanup on error
|
|
147
|
+
await this.cleanupJob(jobId);
|
|
148
|
+
return {
|
|
149
|
+
success: false,
|
|
150
|
+
errorMessage: error instanceof Error ? error.message : 'Unknown error'
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Cancel a running job
|
|
156
|
+
*/
|
|
157
|
+
async cancelJob(jobId) {
|
|
158
|
+
const jobInfo = this.activeJobs.get(jobId);
|
|
159
|
+
if (!jobInfo) {
|
|
160
|
+
logger.warn(`Attempted to cancel non-existent job: ${jobId}`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
logger.info(`Cancelling job: ${jobId}`);
|
|
164
|
+
try {
|
|
165
|
+
// Stop the container
|
|
166
|
+
await this.dockerManager.stopContainer(jobInfo.containerId);
|
|
167
|
+
logger.info(`Container stopped for job: ${jobId}`);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
logger.error(`Error stopping container for job ${jobId}:`, error);
|
|
171
|
+
}
|
|
172
|
+
// Clean up
|
|
173
|
+
await this.cleanupJob(jobId);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Clean up resources
|
|
177
|
+
*/
|
|
178
|
+
async cleanup() {
|
|
179
|
+
logger.info('Cleaning up job executor...');
|
|
180
|
+
// Cancel all active jobs
|
|
181
|
+
const activeJobIds = Array.from(this.activeJobs.keys());
|
|
182
|
+
for (const jobId of activeJobIds) {
|
|
183
|
+
await this.cancelJob(jobId);
|
|
184
|
+
}
|
|
185
|
+
// Clean up Docker manager
|
|
186
|
+
await this.dockerManager.cleanup();
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Clean up orphaned containers from previous agent crashes.
|
|
190
|
+
*/
|
|
191
|
+
async cleanupOrphanedContainers() {
|
|
192
|
+
return this.dockerManager.cleanupOrphanedContainers();
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Validate job requirements against agent capabilities
|
|
196
|
+
*/
|
|
197
|
+
async validateJobRequirements(job) {
|
|
198
|
+
// Check repository whitelist/blacklist
|
|
199
|
+
if (this.config.allowedRepositories && this.config.allowedRepositories.length > 0) {
|
|
200
|
+
if (!this.config.allowedRepositories.includes(job.repository)) {
|
|
201
|
+
throw new Error(`Repository ${job.repository} is not in the allowed list`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (this.config.blockedRepositories && this.config.blockedRepositories.includes(job.repository)) {
|
|
205
|
+
throw new Error(`Repository ${job.repository} is blocked`);
|
|
206
|
+
}
|
|
207
|
+
// Default Docker image if not provided
|
|
208
|
+
if (!job.dockerImage || job.dockerImage.trim() === '') {
|
|
209
|
+
job.dockerImage = 'node:20';
|
|
210
|
+
logger.info(`No Docker image specified, defaulting to ${job.dockerImage}`);
|
|
211
|
+
}
|
|
212
|
+
// Validate build command
|
|
213
|
+
if (!job.buildCommand || job.buildCommand.trim() === '') {
|
|
214
|
+
throw new Error('Build command is required');
|
|
215
|
+
}
|
|
216
|
+
logger.info(`Job requirements validated for ${job.externalId}`);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Create workspace directory for job
|
|
220
|
+
*/
|
|
221
|
+
async createWorkspace(jobId) {
|
|
222
|
+
const workDir = join(this.workspaceRoot, jobId);
|
|
223
|
+
try {
|
|
224
|
+
await fs.mkdir(workDir, { recursive: true });
|
|
225
|
+
logger.info(`Created workspace: ${workDir}`);
|
|
226
|
+
return workDir;
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
logger.error(`Failed to create workspace ${workDir}:`, error);
|
|
230
|
+
throw new Error(`Failed to create workspace: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Prepare workspace with job context
|
|
235
|
+
*/
|
|
236
|
+
async prepareWorkspace(workDir, job) {
|
|
237
|
+
try {
|
|
238
|
+
// Build the clone URL, injecting credentials for private repositories.
|
|
239
|
+
// When a githubToken is present we rewrite the HTTPS URL to embed the
|
|
240
|
+
// x-access-token convention so no interactive credential prompt is needed.
|
|
241
|
+
// The token is intentionally kept out of log lines.
|
|
242
|
+
// Normalize repository to a full URL if it's just owner/repo format
|
|
243
|
+
const repoUrl = job.repository.startsWith('http')
|
|
244
|
+
? job.repository
|
|
245
|
+
: `https://github.com/${job.repository}.git`;
|
|
246
|
+
const cloneUrl = job.githubToken
|
|
247
|
+
? this.buildAuthenticatedCloneUrl(repoUrl, job.githubToken)
|
|
248
|
+
: repoUrl;
|
|
249
|
+
// Disable all interactive git prompts so the process fails fast instead
|
|
250
|
+
// of hanging indefinitely when credentials are missing or wrong.
|
|
251
|
+
const gitEnv = {
|
|
252
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
253
|
+
};
|
|
254
|
+
logger.info(`Cloning repository ${job.repository} (branch: ${job.branch}) into ${workDir}${job.githubToken ? ' [token auth]' : ''}`);
|
|
255
|
+
const cloneResult = await this.executeGitCommand([
|
|
256
|
+
'clone', cloneUrl,
|
|
257
|
+
'--branch', job.branch,
|
|
258
|
+
'--single-branch',
|
|
259
|
+
'--depth', '1',
|
|
260
|
+
'.'
|
|
261
|
+
], workDir, gitEnv);
|
|
262
|
+
if (cloneResult.exitCode !== 0) {
|
|
263
|
+
// Scrub any embedded token from the error message before surfacing it
|
|
264
|
+
const safeError = job.githubToken
|
|
265
|
+
? (cloneResult.error || cloneResult.output).replace(job.githubToken, '[REDACTED]')
|
|
266
|
+
: (cloneResult.error || cloneResult.output);
|
|
267
|
+
throw new Error(`Git clone failed: ${safeError}`);
|
|
268
|
+
}
|
|
269
|
+
// Checkout exact commit if specified and differs from branch HEAD
|
|
270
|
+
if (job.commitSha) {
|
|
271
|
+
const checkoutResult = await this.executeGitCommand(['checkout', job.commitSha], workDir, gitEnv);
|
|
272
|
+
if (checkoutResult.exitCode !== 0) {
|
|
273
|
+
logger.warn(`Could not checkout exact commit ${job.commitSha}, using branch HEAD`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
logger.info(`Repository cloned successfully for job ${job.externalId}`);
|
|
277
|
+
// Create job metadata file
|
|
278
|
+
const jobMetadata = {
|
|
279
|
+
jobId: job.externalId,
|
|
280
|
+
repository: job.repository,
|
|
281
|
+
branch: job.branch,
|
|
282
|
+
commitSha: job.commitSha,
|
|
283
|
+
jobType: job.jobType,
|
|
284
|
+
createdAt: new Date().toISOString()
|
|
285
|
+
};
|
|
286
|
+
await fs.writeFile(join(workDir, '.buildhive-job.json'), JSON.stringify(jobMetadata, null, 2));
|
|
287
|
+
// Create environment file if needed
|
|
288
|
+
if (job.environment && Object.keys(job.environment).length > 0) {
|
|
289
|
+
const envContent = Object.entries(job.environment)
|
|
290
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
291
|
+
.join('\n');
|
|
292
|
+
await fs.writeFile(join(workDir, '.env'), envContent);
|
|
293
|
+
}
|
|
294
|
+
logger.info(`Workspace prepared for job ${job.externalId}`);
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
logger.error(`Failed to prepare workspace for job ${job.externalId}:`, error);
|
|
298
|
+
throw new Error(`Failed to prepare workspace: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Build an authenticated clone URL from a plain HTTPS repository URL.
|
|
303
|
+
*
|
|
304
|
+
* Converts https://github.com/user/repo (or https://github.com/user/repo.git)
|
|
305
|
+
* to https://x-access-token:{token}@github.com/user/repo using the
|
|
306
|
+
* x-access-token convention supported by GitHub App installation tokens,
|
|
307
|
+
* fine-grained PATs, and classic PATs.
|
|
308
|
+
*
|
|
309
|
+
* Only HTTPS URLs are rewritten. SSH URLs (git@github.com:...) are returned
|
|
310
|
+
* unchanged because they rely on key-based auth, not token-based.
|
|
311
|
+
*
|
|
312
|
+
* The token is never written to disk or emitted in log lines.
|
|
313
|
+
*/
|
|
314
|
+
buildAuthenticatedCloneUrl(repositoryUrl, token) {
|
|
315
|
+
try {
|
|
316
|
+
const parsed = new URL(repositoryUrl);
|
|
317
|
+
// Only inject credentials into HTTPS URLs
|
|
318
|
+
if (parsed.protocol !== 'https:') {
|
|
319
|
+
return repositoryUrl;
|
|
320
|
+
}
|
|
321
|
+
parsed.username = 'x-access-token';
|
|
322
|
+
parsed.password = token;
|
|
323
|
+
return parsed.toString();
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// Malformed URL — return as-is and let git produce the error
|
|
327
|
+
return repositoryUrl;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Execute a git command in the given working directory.
|
|
332
|
+
*
|
|
333
|
+
* @param args - Arguments to pass to the git binary
|
|
334
|
+
* @param cwd - Working directory for the git process
|
|
335
|
+
* @param env - Additional environment variables merged on top of process.env.
|
|
336
|
+
* Use this to pass GIT_ASKPASS, GIT_TERMINAL_PROMPT=0, etc.
|
|
337
|
+
* @param timeoutMs - Maximum time to wait before killing the process (default 5 min)
|
|
338
|
+
*/
|
|
339
|
+
executeGitCommand(args, cwd, env, timeoutMs = 300000) {
|
|
340
|
+
return new Promise((resolve) => {
|
|
341
|
+
const mergedEnv = env
|
|
342
|
+
? { ...process.env, ...env }
|
|
343
|
+
: process.env;
|
|
344
|
+
const proc = spawn('git', args, { cwd, env: mergedEnv });
|
|
345
|
+
let output = '';
|
|
346
|
+
let error = '';
|
|
347
|
+
let killed = false;
|
|
348
|
+
const timer = setTimeout(() => {
|
|
349
|
+
killed = true;
|
|
350
|
+
proc.kill('SIGKILL');
|
|
351
|
+
resolve({ exitCode: 1, output, error: `Git command timed out after ${timeoutMs / 1000}s` });
|
|
352
|
+
}, timeoutMs);
|
|
353
|
+
proc.stdout.on('data', (data) => { output += data.toString(); });
|
|
354
|
+
proc.stderr.on('data', (data) => { error += data.toString(); });
|
|
355
|
+
proc.on('close', (code) => {
|
|
356
|
+
clearTimeout(timer);
|
|
357
|
+
if (!killed) {
|
|
358
|
+
resolve({ exitCode: code ?? 1, output, error });
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
proc.on('error', (err) => {
|
|
362
|
+
clearTimeout(timer);
|
|
363
|
+
if (!killed) {
|
|
364
|
+
resolve({ exitCode: 1, output: '', error: err.message });
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Collect build artifacts from container
|
|
371
|
+
*
|
|
372
|
+
* MVP.4.2.4: Artifacts are copied from container and uploaded to configured storage
|
|
373
|
+
*/
|
|
374
|
+
async collectArtifacts(containerId, workDir, artifactPaths) {
|
|
375
|
+
if (artifactPaths.length === 0) {
|
|
376
|
+
return [];
|
|
377
|
+
}
|
|
378
|
+
const artifactUrls = [];
|
|
379
|
+
try {
|
|
380
|
+
for (const artifactPath of artifactPaths) {
|
|
381
|
+
const localPath = join(workDir, 'artifacts', artifactPath);
|
|
382
|
+
// Step 1: Copy artifact from container to host
|
|
383
|
+
logger.debug(`Copying artifact from container: ${artifactPath}`);
|
|
384
|
+
await this.dockerManager.copyFromContainer(containerId, `/workspace/${artifactPath}`, localPath);
|
|
385
|
+
// Step 2: Upload artifact to configured storage (MVP.4.2.4)
|
|
386
|
+
logger.debug(`Uploading artifact to storage: ${artifactPath}`);
|
|
387
|
+
const result = await this.artifactUploader.uploadArtifact(localPath, artifactPath, {
|
|
388
|
+
deleteAfterUpload: this.config.storageConfig.cleanupAfterUpload
|
|
389
|
+
});
|
|
390
|
+
artifactUrls.push(result.url);
|
|
391
|
+
logger.debug(`Artifact uploaded successfully`, {
|
|
392
|
+
path: artifactPath,
|
|
393
|
+
url: result.url,
|
|
394
|
+
size: result.size
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
logger.info(`Collected and uploaded ${artifactUrls.length} artifacts`);
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
logger.error('Failed to collect artifacts:', error);
|
|
401
|
+
// Don't fail the job if artifact collection fails
|
|
402
|
+
}
|
|
403
|
+
return artifactUrls;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Clean up job resources
|
|
407
|
+
*/
|
|
408
|
+
async cleanupJob(jobId) {
|
|
409
|
+
const jobInfo = this.activeJobs.get(jobId);
|
|
410
|
+
if (!jobInfo) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
try {
|
|
414
|
+
// Remove and clean up container
|
|
415
|
+
await this.dockerManager.removeContainer(jobInfo.containerId);
|
|
416
|
+
// Clean up workspace unless explicitly told to keep it for debugging
|
|
417
|
+
const keepWorkspace = process.env.BUILDHIVE_KEEP_WORKSPACE === 'true';
|
|
418
|
+
if (!keepWorkspace) {
|
|
419
|
+
await fs.rm(jobInfo.workDir, { recursive: true, force: true });
|
|
420
|
+
logger.info(`Cleaned up workspace: ${jobInfo.workDir}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
logger.error(`Error during cleanup for job ${jobId}:`, error);
|
|
425
|
+
}
|
|
426
|
+
finally {
|
|
427
|
+
this.activeJobs.delete(jobId);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Clean up old artifacts based on retention policy (MVP.4.2.4)
|
|
432
|
+
*
|
|
433
|
+
* Should be called periodically by the agent to enforce retention policy.
|
|
434
|
+
*
|
|
435
|
+
* @returns Number of artifacts deleted
|
|
436
|
+
*/
|
|
437
|
+
async cleanupOldArtifacts() {
|
|
438
|
+
logger.info('Starting artifact retention cleanup');
|
|
439
|
+
try {
|
|
440
|
+
const deletedCount = await this.artifactUploader.cleanupOldArtifacts();
|
|
441
|
+
logger.info(`Artifact retention cleanup complete`, { deletedCount });
|
|
442
|
+
return deletedCount;
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
logger.error('Artifact retention cleanup failed:', error);
|
|
446
|
+
return 0;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Get artifact storage statistics (MVP.4.2.4)
|
|
451
|
+
*
|
|
452
|
+
* @returns Storage statistics
|
|
453
|
+
*/
|
|
454
|
+
async getArtifactStorageStats() {
|
|
455
|
+
return this.artifactUploader.getStorageStats();
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
//# sourceMappingURL=jobExecutor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobExecutor.js","sourceRoot":"","sources":["../src/jobExecutor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle Executor - Setup/Execute/Teardown job phases
|
|
3
|
+
*
|
|
4
|
+
* Manages the full lifecycle of a job execution:
|
|
5
|
+
* 1. Setup steps run sequentially
|
|
6
|
+
* 2. Main build command executes
|
|
7
|
+
* 3. Teardown steps ALWAYS run (even on failure)
|
|
8
|
+
*/
|
|
9
|
+
import { RecipeLifecycleStep } from './recipes/types.js';
|
|
10
|
+
export interface LifecyclePhaseResult {
|
|
11
|
+
phase: 'setup' | 'execute' | 'teardown';
|
|
12
|
+
stepName: string;
|
|
13
|
+
exitCode: number;
|
|
14
|
+
stdout: string;
|
|
15
|
+
stderr: string;
|
|
16
|
+
durationMs: number;
|
|
17
|
+
skipped: boolean;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface LifecycleResult {
|
|
21
|
+
setupResults: LifecyclePhaseResult[];
|
|
22
|
+
executeResult: LifecyclePhaseResult;
|
|
23
|
+
teardownResults: LifecyclePhaseResult[];
|
|
24
|
+
overallSuccess: boolean;
|
|
25
|
+
totalDurationMs: number;
|
|
26
|
+
}
|
|
27
|
+
export interface LifecycleOptions {
|
|
28
|
+
workDir: string;
|
|
29
|
+
environment?: Record<string, string>;
|
|
30
|
+
onProgress?: (phase: string, step: string, progress: number) => void;
|
|
31
|
+
onLog?: (phase: string, step: string, log: string) => void;
|
|
32
|
+
abortSignal?: AbortSignal;
|
|
33
|
+
}
|
|
34
|
+
export declare class LifecycleExecutor {
|
|
35
|
+
/**
|
|
36
|
+
* Execute full lifecycle: setup -> main command -> teardown
|
|
37
|
+
*
|
|
38
|
+
* CRITICAL BEHAVIORS:
|
|
39
|
+
* 1. Setup steps run sequentially. If a step fails and continueOnError=false,
|
|
40
|
+
* skip remaining setup + main command, but STILL run teardown.
|
|
41
|
+
* 2. Main command runs only if all required setup steps succeed.
|
|
42
|
+
* 3. Teardown ALWAYS runs, even if setup or main command failed.
|
|
43
|
+
* 4. Each step has its own timeout (default 300s).
|
|
44
|
+
* 5. If abortSignal fires, terminate current step and run teardown.
|
|
45
|
+
*/
|
|
46
|
+
execute(setupSteps: RecipeLifecycleStep[], mainCommand: string, teardownSteps: RecipeLifecycleStep[], options: LifecycleOptions): Promise<LifecycleResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Execute a single lifecycle step using child_process.spawn.
|
|
49
|
+
*/
|
|
50
|
+
private executeStep;
|
|
51
|
+
private skippedResult;
|
|
52
|
+
private isAborted;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=lifecycleExecutor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycleExecutor.d.ts","sourceRoot":"","sources":["../src/lifecycleExecutor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAMzD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,aAAa,EAAE,oBAAoB,CAAC;IACpC,eAAe,EAAE,oBAAoB,EAAE,CAAC;IACxC,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAaD,qBAAa,iBAAiB;IAC5B;;;;;;;;;;OAUG;IACG,OAAO,CACX,UAAU,EAAE,mBAAmB,EAAE,EACjC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,mBAAmB,EAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC;IAqF3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAiInB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,SAAS;CAGlB"}
|