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,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Registration Module
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the agent registration process including machine ID generation,
|
|
5
|
+
* capability detection, API registration, and configuration persistence.
|
|
6
|
+
*
|
|
7
|
+
* Requirements: MVP.4.1.2
|
|
8
|
+
*/
|
|
9
|
+
import { AgentConfig } from '../config/types.js';
|
|
10
|
+
export interface RegistrationOptions {
|
|
11
|
+
platformUrl: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
tags?: string[];
|
|
14
|
+
maxConcurrentJobs?: number;
|
|
15
|
+
configPath?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class AgentRegistration {
|
|
18
|
+
private machineIdManager;
|
|
19
|
+
private apiClient;
|
|
20
|
+
constructor(platformUrl: string);
|
|
21
|
+
/**
|
|
22
|
+
* Register agent with the BuildHive platform
|
|
23
|
+
*/
|
|
24
|
+
registerAgent(options: RegistrationOptions): Promise<AgentConfig>;
|
|
25
|
+
/**
|
|
26
|
+
* Check if agent is already registered
|
|
27
|
+
*/
|
|
28
|
+
isRegistered(): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Re-register agent (clears existing registration)
|
|
31
|
+
*/
|
|
32
|
+
reRegister(options: RegistrationOptions): Promise<AgentConfig>;
|
|
33
|
+
/**
|
|
34
|
+
* Get machine ID without registering
|
|
35
|
+
*/
|
|
36
|
+
getMachineId(): Promise<string>;
|
|
37
|
+
}
|
|
38
|
+
export { MachineIdManager } from './machineId.js';
|
|
39
|
+
export { BuildHiveApiClient } from './apiClient.js';
|
|
40
|
+
export * from './types.js';
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registration/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,oBAAoB,CAAC;AAsCjE,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,SAAS,CAAqB;gBAE1B,WAAW,EAAE,MAAM;IAK/B;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC;IA6EvE;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAItC;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC;IAMpE;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;CAGtC;AAGD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Registration Module
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the agent registration process including machine ID generation,
|
|
5
|
+
* capability detection, API registration, and configuration persistence.
|
|
6
|
+
*
|
|
7
|
+
* Requirements: MVP.4.1.2
|
|
8
|
+
*/
|
|
9
|
+
import { DEFAULT_CONFIG } from '../config/types.js';
|
|
10
|
+
import { MachineIdManager } from './machineId.js';
|
|
11
|
+
import { BuildHiveApiClient } from './apiClient.js';
|
|
12
|
+
import { detectCapabilities } from '../utils/capabilities.js';
|
|
13
|
+
import { scanInstalledSDKs, generateTagsFromSDKs } from '../utils/sdkScanner.js';
|
|
14
|
+
import { saveConfig } from '../config/index.js';
|
|
15
|
+
import { createLogger } from '../utils/logger.js';
|
|
16
|
+
import { join } from 'path';
|
|
17
|
+
import os from 'os';
|
|
18
|
+
import { execSync } from 'child_process';
|
|
19
|
+
const logger = createLogger('registration');
|
|
20
|
+
/**
|
|
21
|
+
* Get a friendly device name from the OS.
|
|
22
|
+
* macOS: uses `scutil --get ComputerName` (e.g. "Shahar's MacBook Pro")
|
|
23
|
+
* Linux: uses hostname
|
|
24
|
+
* Windows: uses COMPUTERNAME env var
|
|
25
|
+
*/
|
|
26
|
+
async function getDeviceFriendlyName() {
|
|
27
|
+
try {
|
|
28
|
+
if (process.platform === 'darwin') {
|
|
29
|
+
return execSync('scutil --get ComputerName', { encoding: 'utf8' }).trim();
|
|
30
|
+
}
|
|
31
|
+
if (process.platform === 'win32') {
|
|
32
|
+
return process.env.COMPUTERNAME || null;
|
|
33
|
+
}
|
|
34
|
+
// Linux: try hostnamectl pretty hostname, fallback to hostname
|
|
35
|
+
try {
|
|
36
|
+
const pretty = execSync('hostnamectl --pretty', { encoding: 'utf8' }).trim();
|
|
37
|
+
if (pretty)
|
|
38
|
+
return pretty;
|
|
39
|
+
}
|
|
40
|
+
catch { /* ignore */ }
|
|
41
|
+
return os.hostname();
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class AgentRegistration {
|
|
48
|
+
machineIdManager;
|
|
49
|
+
apiClient;
|
|
50
|
+
constructor(platformUrl) {
|
|
51
|
+
this.machineIdManager = new MachineIdManager();
|
|
52
|
+
this.apiClient = new BuildHiveApiClient(platformUrl);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Register agent with the BuildHive platform
|
|
56
|
+
*/
|
|
57
|
+
async registerAgent(options) {
|
|
58
|
+
logger.info('Starting agent registration process');
|
|
59
|
+
// Test connection to platform
|
|
60
|
+
logger.info(`Testing connection to ${options.platformUrl}`);
|
|
61
|
+
const connected = await this.apiClient.testConnection();
|
|
62
|
+
if (!connected) {
|
|
63
|
+
throw new Error(`Cannot connect to BuildHive platform at ${options.platformUrl}. Please check the URL and your network connection.`);
|
|
64
|
+
}
|
|
65
|
+
// Get or generate machine ID
|
|
66
|
+
const machineId = await this.machineIdManager.getMachineId();
|
|
67
|
+
logger.info(`Machine ID: ${machineId}`);
|
|
68
|
+
// Detect system capabilities
|
|
69
|
+
logger.info('Detecting system capabilities...');
|
|
70
|
+
const capabilities = await detectCapabilities();
|
|
71
|
+
logger.info('Detected system capabilities:', capabilities);
|
|
72
|
+
// Scan installed SDKs and generate capability tags
|
|
73
|
+
logger.info('Scanning installed SDKs...');
|
|
74
|
+
const sdkCapabilities = await scanInstalledSDKs();
|
|
75
|
+
const sdkTags = generateTagsFromSDKs(sdkCapabilities);
|
|
76
|
+
logger.info(`SDK scan generated ${sdkTags.length} tags: ${sdkTags.join(', ')}`);
|
|
77
|
+
// Merge user-provided tags with SDK-detected tags (user tags take precedence)
|
|
78
|
+
const userTags = options.tags || [];
|
|
79
|
+
const mergedTags = [...new Set([...userTags, ...sdkTags])];
|
|
80
|
+
logger.info(`Merged tags (${mergedTags.length}): ${mergedTags.join(', ')}`);
|
|
81
|
+
// Generate agent name from device info if not provided
|
|
82
|
+
const agentName = options.name ||
|
|
83
|
+
await getDeviceFriendlyName() ||
|
|
84
|
+
`buildhive-agent-${os.hostname()}-${machineId.substring(0, 8)}`;
|
|
85
|
+
// Register with platform
|
|
86
|
+
logger.info(`Registering agent "${agentName}" with platform...`);
|
|
87
|
+
const response = await this.apiClient.register({
|
|
88
|
+
name: agentName,
|
|
89
|
+
machineId,
|
|
90
|
+
version: '1.0.0', // Agent version
|
|
91
|
+
capabilities,
|
|
92
|
+
tags: mergedTags,
|
|
93
|
+
maxConcurrentJobs: options.maxConcurrentJobs || 1,
|
|
94
|
+
sdkCapabilities,
|
|
95
|
+
});
|
|
96
|
+
logger.info(`Agent registered successfully with ID: ${response.agentId}`);
|
|
97
|
+
// Create full config with registration data and defaults
|
|
98
|
+
const fullConfig = {
|
|
99
|
+
...DEFAULT_CONFIG,
|
|
100
|
+
platformUrl: options.platformUrl,
|
|
101
|
+
agentId: response.agentId,
|
|
102
|
+
apiKey: response.apiKey,
|
|
103
|
+
name: agentName,
|
|
104
|
+
tags: mergedTags,
|
|
105
|
+
maxConcurrentJobs: options.maxConcurrentJobs || 1,
|
|
106
|
+
};
|
|
107
|
+
// Determine config file path
|
|
108
|
+
const configPath = options.configPath ||
|
|
109
|
+
join(os.homedir(), '.buildhive', 'buildhive-agent.json');
|
|
110
|
+
// Save config to file
|
|
111
|
+
await saveConfig(fullConfig, configPath);
|
|
112
|
+
logger.info(`Configuration saved to ${configPath}`);
|
|
113
|
+
logger.info('Agent registration completed successfully');
|
|
114
|
+
return fullConfig;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if agent is already registered
|
|
118
|
+
*/
|
|
119
|
+
async isRegistered() {
|
|
120
|
+
return await this.machineIdManager.exists();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Re-register agent (clears existing registration)
|
|
124
|
+
*/
|
|
125
|
+
async reRegister(options) {
|
|
126
|
+
logger.warn('Re-registering agent - clearing existing machine ID');
|
|
127
|
+
await this.machineIdManager.clear();
|
|
128
|
+
return await this.registerAgent(options);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get machine ID without registering
|
|
132
|
+
*/
|
|
133
|
+
async getMachineId() {
|
|
134
|
+
return await this.machineIdManager.getMachineId();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Export convenience functions
|
|
138
|
+
export { MachineIdManager } from './machineId.js';
|
|
139
|
+
export { BuildHiveApiClient } from './apiClient.js';
|
|
140
|
+
export * from './types.js';
|
|
141
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/registration/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine ID Manager
|
|
3
|
+
*
|
|
4
|
+
* Generates and persists a unique machine identifier for agent registration.
|
|
5
|
+
* Uses hardware-based ID generation with file-based persistence for consistency.
|
|
6
|
+
*
|
|
7
|
+
* Requirements: MVP.4.1.2
|
|
8
|
+
*/
|
|
9
|
+
export declare class MachineIdManager {
|
|
10
|
+
private configDir;
|
|
11
|
+
private idFile;
|
|
12
|
+
constructor(configDir?: string);
|
|
13
|
+
/**
|
|
14
|
+
* Get machine ID - loads from file or generates new one
|
|
15
|
+
*/
|
|
16
|
+
getMachineId(): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Store machine ID to file for persistence
|
|
19
|
+
*/
|
|
20
|
+
private storeMachineId;
|
|
21
|
+
/**
|
|
22
|
+
* Check if machine ID exists
|
|
23
|
+
*/
|
|
24
|
+
exists(): Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Clear stored machine ID (for testing or reset)
|
|
27
|
+
*/
|
|
28
|
+
clear(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=machineId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machineId.d.ts","sourceRoot":"","sources":["../../src/registration/machineId.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAS;gBAEX,SAAS,GAAE,MAAyC;IAKhE;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAuBrC;;OAEG;YACW,cAAc;IAc5B;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAShC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAW7B"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine ID Manager
|
|
3
|
+
*
|
|
4
|
+
* Generates and persists a unique machine identifier for agent registration.
|
|
5
|
+
* Uses hardware-based ID generation with file-based persistence for consistency.
|
|
6
|
+
*
|
|
7
|
+
* Requirements: MVP.4.1.2
|
|
8
|
+
*/
|
|
9
|
+
import machineIdPkg from 'node-machine-id';
|
|
10
|
+
const { machineIdSync } = machineIdPkg;
|
|
11
|
+
import { promises as fs } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import os from 'os';
|
|
14
|
+
import { createLogger } from '../utils/logger.js';
|
|
15
|
+
const logger = createLogger('machineId');
|
|
16
|
+
export class MachineIdManager {
|
|
17
|
+
configDir;
|
|
18
|
+
idFile;
|
|
19
|
+
constructor(configDir = join(os.homedir(), '.buildhive')) {
|
|
20
|
+
this.configDir = configDir;
|
|
21
|
+
this.idFile = join(configDir, 'machine-id');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get machine ID - loads from file or generates new one
|
|
25
|
+
*/
|
|
26
|
+
async getMachineId() {
|
|
27
|
+
// Try to load from file first
|
|
28
|
+
try {
|
|
29
|
+
const storedId = await fs.readFile(this.idFile, 'utf8');
|
|
30
|
+
if (storedId && storedId.trim()) {
|
|
31
|
+
logger.info('Loaded machine ID from file');
|
|
32
|
+
return storedId.trim();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
// File doesn't exist, will generate new
|
|
37
|
+
logger.debug('No stored machine ID found, generating new one');
|
|
38
|
+
}
|
|
39
|
+
// Generate new machine ID based on hardware
|
|
40
|
+
const machineId = machineIdSync(true);
|
|
41
|
+
logger.info('Generated new machine ID');
|
|
42
|
+
// Store for future use
|
|
43
|
+
await this.storeMachineId(machineId);
|
|
44
|
+
return machineId;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Store machine ID to file for persistence
|
|
48
|
+
*/
|
|
49
|
+
async storeMachineId(machineId) {
|
|
50
|
+
try {
|
|
51
|
+
await fs.mkdir(this.configDir, { recursive: true });
|
|
52
|
+
await fs.writeFile(this.idFile, machineId, 'utf8');
|
|
53
|
+
await fs.chmod(this.idFile, 0o600); // Read/write for owner only
|
|
54
|
+
logger.info(`Stored machine ID to ${this.idFile}`);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
logger.error('Failed to store machine ID:', error);
|
|
58
|
+
throw new Error(`Failed to store machine ID: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if machine ID exists
|
|
63
|
+
*/
|
|
64
|
+
async exists() {
|
|
65
|
+
try {
|
|
66
|
+
await fs.access(this.idFile);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Clear stored machine ID (for testing or reset)
|
|
75
|
+
*/
|
|
76
|
+
async clear() {
|
|
77
|
+
try {
|
|
78
|
+
await fs.unlink(this.idFile);
|
|
79
|
+
logger.info('Cleared stored machine ID');
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
// Ignore if file doesn't exist
|
|
83
|
+
if (error.code !== 'ENOENT') {
|
|
84
|
+
logger.error('Failed to clear machine ID:', error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=machineId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machineId.js","sourceRoot":"","sources":["../../src/registration/machineId.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registration Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for agent registration with the BuildHive platform
|
|
5
|
+
*
|
|
6
|
+
* Requirements: MVP.4.1.2
|
|
7
|
+
*/
|
|
8
|
+
import { AgentCapabilities } from '../types.js';
|
|
9
|
+
import { SDKScanResult } from '../utils/sdkScanner.js';
|
|
10
|
+
export interface RegistrationRequest {
|
|
11
|
+
name: string;
|
|
12
|
+
machineId: string;
|
|
13
|
+
version: string;
|
|
14
|
+
capabilities: AgentCapabilities;
|
|
15
|
+
tags: string[];
|
|
16
|
+
maxConcurrentJobs: number;
|
|
17
|
+
sdkCapabilities?: SDKScanResult;
|
|
18
|
+
}
|
|
19
|
+
export interface RegistrationResponse {
|
|
20
|
+
agentId: string;
|
|
21
|
+
apiKey: string;
|
|
22
|
+
expiresAt: string;
|
|
23
|
+
}
|
|
24
|
+
export interface AuthenticationRequest {
|
|
25
|
+
agentId: string;
|
|
26
|
+
apiKey: string;
|
|
27
|
+
}
|
|
28
|
+
export interface AuthenticationResponse {
|
|
29
|
+
token: string;
|
|
30
|
+
expiresAt: string;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/registration/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,iBAAiB,CAAC;IAChC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,aAAa,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/registration/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Governor
|
|
3
|
+
*
|
|
4
|
+
* Enforces resource limits and quiet hours policies for the agent.
|
|
5
|
+
* Determines whether the agent should accept new jobs based on
|
|
6
|
+
* current resource usage and configured governance rules.
|
|
7
|
+
*/
|
|
8
|
+
import { ResourceGovernance } from './config/types.js';
|
|
9
|
+
export interface ResourceSnapshot {
|
|
10
|
+
cpuPercent: number;
|
|
11
|
+
memoryPercent: number;
|
|
12
|
+
diskFreeGB: number;
|
|
13
|
+
activeJobs: number;
|
|
14
|
+
}
|
|
15
|
+
export interface JobRequirements {
|
|
16
|
+
cpuCores?: number;
|
|
17
|
+
memoryGB?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface AcceptanceDecision {
|
|
20
|
+
allowed: boolean;
|
|
21
|
+
reason?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface EffectiveLimits {
|
|
24
|
+
maxCpu: number;
|
|
25
|
+
maxMemory: number;
|
|
26
|
+
maxJobs: number;
|
|
27
|
+
}
|
|
28
|
+
export declare class ResourceGovernor {
|
|
29
|
+
private config;
|
|
30
|
+
private maxConcurrentJobs;
|
|
31
|
+
private nowFn;
|
|
32
|
+
constructor(config: ResourceGovernance, maxConcurrentJobs?: number, nowFn?: () => Date);
|
|
33
|
+
/**
|
|
34
|
+
* Check if the agent should accept a new job based on current resources.
|
|
35
|
+
* @param snapshot Current resource usage snapshot
|
|
36
|
+
*/
|
|
37
|
+
canAcceptJob(snapshot: ResourceSnapshot): AcceptanceDecision;
|
|
38
|
+
/**
|
|
39
|
+
* Check if the agent is currently in quiet hours.
|
|
40
|
+
*/
|
|
41
|
+
isQuietHours(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Get effective resource limits, considering quiet hours.
|
|
44
|
+
*/
|
|
45
|
+
getEffectiveLimits(): EffectiveLimits;
|
|
46
|
+
/**
|
|
47
|
+
* Check if accepting a job with given requirements would exceed limits.
|
|
48
|
+
* @param jobRequirements CPU and memory requirements for the job
|
|
49
|
+
* @param currentSnapshot Current resource usage
|
|
50
|
+
*/
|
|
51
|
+
wouldExceedLimits(jobRequirements: JobRequirements, currentSnapshot?: ResourceSnapshot): boolean;
|
|
52
|
+
/** Parse "HH:MM" to total minutes */
|
|
53
|
+
private parseTimeToMinutes;
|
|
54
|
+
/** Get current time in the configured timezone */
|
|
55
|
+
private getCurrentTimeInTimezone;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=resourceGovernor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceGovernor.d.ts","sourceRoot":"","sources":["../src/resourceGovernor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,KAAK;gBAFL,MAAM,EAAE,kBAAkB,EAC1B,iBAAiB,GAAE,MAAU,EAC7B,KAAK,GAAE,MAAM,IAAuB;IAG9C;;;OAGG;IACH,YAAY,CAAC,QAAQ,EAAE,gBAAgB,GAAG,kBAAkB;IAsB5D;;OAEG;IACH,YAAY,IAAI,OAAO;IAmBvB;;OAEG;IACH,kBAAkB,IAAI,eAAe;IAgBrC;;;;OAIG;IACH,iBAAiB,CAAC,eAAe,EAAE,eAAe,EAAE,eAAe,CAAC,EAAE,gBAAgB,GAAG,OAAO;IAuBhG,qCAAqC;IACrC,OAAO,CAAC,kBAAkB;IAK1B,kDAAkD;IAClD,OAAO,CAAC,wBAAwB;CAoBjC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Governor
|
|
3
|
+
*
|
|
4
|
+
* Enforces resource limits and quiet hours policies for the agent.
|
|
5
|
+
* Determines whether the agent should accept new jobs based on
|
|
6
|
+
* current resource usage and configured governance rules.
|
|
7
|
+
*/
|
|
8
|
+
export class ResourceGovernor {
|
|
9
|
+
config;
|
|
10
|
+
maxConcurrentJobs;
|
|
11
|
+
nowFn;
|
|
12
|
+
constructor(config, maxConcurrentJobs = 1, nowFn = () => new Date()) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.maxConcurrentJobs = maxConcurrentJobs;
|
|
15
|
+
this.nowFn = nowFn;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if the agent should accept a new job based on current resources.
|
|
19
|
+
* @param snapshot Current resource usage snapshot
|
|
20
|
+
*/
|
|
21
|
+
canAcceptJob(snapshot) {
|
|
22
|
+
const limits = this.getEffectiveLimits();
|
|
23
|
+
if (snapshot.activeJobs >= limits.maxJobs) {
|
|
24
|
+
return { allowed: false, reason: `Active jobs (${snapshot.activeJobs}) at or above limit (${limits.maxJobs})` };
|
|
25
|
+
}
|
|
26
|
+
if (snapshot.cpuPercent >= limits.maxCpu) {
|
|
27
|
+
return { allowed: false, reason: `CPU usage (${snapshot.cpuPercent}%) exceeds limit (${limits.maxCpu}%)` };
|
|
28
|
+
}
|
|
29
|
+
if (snapshot.memoryPercent >= limits.maxMemory) {
|
|
30
|
+
return { allowed: false, reason: `Memory usage (${snapshot.memoryPercent}%) exceeds limit (${limits.maxMemory}%)` };
|
|
31
|
+
}
|
|
32
|
+
if (snapshot.diskFreeGB < this.config.reservedDiskGB) {
|
|
33
|
+
return { allowed: false, reason: `Free disk (${snapshot.diskFreeGB}GB) below reserve (${this.config.reservedDiskGB}GB)` };
|
|
34
|
+
}
|
|
35
|
+
return { allowed: true };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if the agent is currently in quiet hours.
|
|
39
|
+
*/
|
|
40
|
+
isQuietHours() {
|
|
41
|
+
const qh = this.config.quietHours;
|
|
42
|
+
if (!qh || !qh.schedule)
|
|
43
|
+
return false;
|
|
44
|
+
const now = this.getCurrentTimeInTimezone(qh);
|
|
45
|
+
const [startStr, endStr] = qh.schedule.split('-');
|
|
46
|
+
const startMinutes = this.parseTimeToMinutes(startStr);
|
|
47
|
+
const endMinutes = this.parseTimeToMinutes(endStr);
|
|
48
|
+
const nowMinutes = now.hours * 60 + now.minutes;
|
|
49
|
+
if (startMinutes <= endMinutes) {
|
|
50
|
+
// Same-day range (e.g., 22:00-23:00 or 09:00-17:00)
|
|
51
|
+
return nowMinutes >= startMinutes && nowMinutes < endMinutes;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// Overnight range (e.g., 22:00-06:00)
|
|
55
|
+
return nowMinutes >= startMinutes || nowMinutes < endMinutes;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get effective resource limits, considering quiet hours.
|
|
60
|
+
*/
|
|
61
|
+
getEffectiveLimits() {
|
|
62
|
+
if (this.isQuietHours() && this.config.quietHours) {
|
|
63
|
+
return {
|
|
64
|
+
maxCpu: this.config.quietHours.maxCpuPercent,
|
|
65
|
+
maxMemory: Math.min(this.config.maxMemoryPercent, this.config.quietHours.maxCpuPercent),
|
|
66
|
+
maxJobs: this.config.quietHours.maxConcurrentJobs
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
maxCpu: this.config.maxCpuPercent,
|
|
71
|
+
maxMemory: this.config.maxMemoryPercent,
|
|
72
|
+
maxJobs: this.maxConcurrentJobs
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Check if accepting a job with given requirements would exceed limits.
|
|
77
|
+
* @param jobRequirements CPU and memory requirements for the job
|
|
78
|
+
* @param currentSnapshot Current resource usage
|
|
79
|
+
*/
|
|
80
|
+
wouldExceedLimits(jobRequirements, currentSnapshot) {
|
|
81
|
+
const limits = this.getEffectiveLimits();
|
|
82
|
+
if (jobRequirements.cpuCores !== undefined) {
|
|
83
|
+
const currentCpu = currentSnapshot?.cpuPercent ?? 0;
|
|
84
|
+
// Rough estimate: each core ~= some percent of total
|
|
85
|
+
// We just check if adding estimated usage would exceed limit
|
|
86
|
+
if (currentCpu + (jobRequirements.cpuCores * 10) > limits.maxCpu) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (jobRequirements.memoryGB !== undefined) {
|
|
91
|
+
const currentMem = currentSnapshot?.memoryPercent ?? 0;
|
|
92
|
+
// Rough estimate: each GB ~= some percent
|
|
93
|
+
if (currentMem + (jobRequirements.memoryGB * 5) > limits.maxMemory) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
/** Parse "HH:MM" to total minutes */
|
|
100
|
+
parseTimeToMinutes(time) {
|
|
101
|
+
const [hours, minutes] = time.split(':').map(Number);
|
|
102
|
+
return hours * 60 + minutes;
|
|
103
|
+
}
|
|
104
|
+
/** Get current time in the configured timezone */
|
|
105
|
+
getCurrentTimeInTimezone(qh) {
|
|
106
|
+
const now = this.nowFn();
|
|
107
|
+
if (qh.timezone) {
|
|
108
|
+
try {
|
|
109
|
+
const formatted = now.toLocaleTimeString('en-US', {
|
|
110
|
+
timeZone: qh.timezone,
|
|
111
|
+
hour12: false,
|
|
112
|
+
hour: '2-digit',
|
|
113
|
+
minute: '2-digit'
|
|
114
|
+
});
|
|
115
|
+
const [hours, minutes] = formatted.split(':').map(Number);
|
|
116
|
+
return { hours, minutes };
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Fall back to local time if timezone is invalid
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { hours: now.getHours(), minutes: now.getMinutes() };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=resourceGovernor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceGovernor.js","sourceRoot":"","sources":["../src/resourceGovernor.ts"],"names":[],"mappings":"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"}
|