synapse-mcp 1.0.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/README.md +607 -0
- package/dist/constants.d.ts +23 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +58 -0
- package/dist/constants.js.map +1 -0
- package/dist/formatters/index.d.ts +275 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +461 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +178 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/common.d.ts +48 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +69 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/discriminator.d.ts +20 -0
- package/dist/schemas/discriminator.d.ts.map +1 -0
- package/dist/schemas/discriminator.js +25 -0
- package/dist/schemas/discriminator.js.map +1 -0
- package/dist/schemas/flux/compose.d.ts +93 -0
- package/dist/schemas/flux/compose.d.ts.map +1 -0
- package/dist/schemas/flux/compose.js +112 -0
- package/dist/schemas/flux/compose.js.map +1 -0
- package/dist/schemas/flux/container.d.ts +144 -0
- package/dist/schemas/flux/container.d.ts.map +1 -0
- package/dist/schemas/flux/container.js +163 -0
- package/dist/schemas/flux/container.js.map +1 -0
- package/dist/schemas/flux/docker.d.ts +91 -0
- package/dist/schemas/flux/docker.d.ts.map +1 -0
- package/dist/schemas/flux/docker.js +101 -0
- package/dist/schemas/flux/docker.js.map +1 -0
- package/dist/schemas/flux/host.d.ts +61 -0
- package/dist/schemas/flux/host.d.ts.map +1 -0
- package/dist/schemas/flux/host.js +72 -0
- package/dist/schemas/flux/host.js.map +1 -0
- package/dist/schemas/flux/index.d.ts +20 -0
- package/dist/schemas/flux/index.d.ts.map +1 -0
- package/dist/schemas/flux/index.js +88 -0
- package/dist/schemas/flux/index.js.map +1 -0
- package/dist/schemas/index.d.ts +11 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +11 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/scout/index.d.ts +151 -0
- package/dist/schemas/scout/index.d.ts.map +1 -0
- package/dist/schemas/scout/index.js +41 -0
- package/dist/schemas/scout/index.js.map +1 -0
- package/dist/schemas/scout/logs.d.ts +48 -0
- package/dist/schemas/scout/logs.d.ts.map +1 -0
- package/dist/schemas/scout/logs.js +47 -0
- package/dist/schemas/scout/logs.js.map +1 -0
- package/dist/schemas/scout/simple.d.ts +68 -0
- package/dist/schemas/scout/simple.d.ts.map +1 -0
- package/dist/schemas/scout/simple.js +75 -0
- package/dist/schemas/scout/simple.js.map +1 -0
- package/dist/schemas/scout/zfs.d.ts +37 -0
- package/dist/schemas/scout/zfs.d.ts.map +1 -0
- package/dist/schemas/scout/zfs.js +36 -0
- package/dist/schemas/scout/zfs.js.map +1 -0
- package/dist/schemas/unified.d.ts +674 -0
- package/dist/schemas/unified.d.ts.map +1 -0
- package/dist/schemas/unified.js +453 -0
- package/dist/schemas/unified.js.map +1 -0
- package/dist/services/compose.d.ts +107 -0
- package/dist/services/compose.d.ts.map +1 -0
- package/dist/services/compose.js +308 -0
- package/dist/services/compose.js.map +1 -0
- package/dist/services/container.d.ts +69 -0
- package/dist/services/container.d.ts.map +1 -0
- package/dist/services/container.js +111 -0
- package/dist/services/container.js.map +1 -0
- package/dist/services/docker.d.ts +243 -0
- package/dist/services/docker.d.ts.map +1 -0
- package/dist/services/docker.js +812 -0
- package/dist/services/docker.js.map +1 -0
- package/dist/services/file-service.d.ts +79 -0
- package/dist/services/file-service.d.ts.map +1 -0
- package/dist/services/file-service.js +226 -0
- package/dist/services/file-service.js.map +1 -0
- package/dist/services/interfaces.d.ts +537 -0
- package/dist/services/interfaces.d.ts.map +1 -0
- package/dist/services/interfaces.js +2 -0
- package/dist/services/interfaces.js.map +1 -0
- package/dist/services/ssh-pool-exec.d.ts +10 -0
- package/dist/services/ssh-pool-exec.d.ts.map +1 -0
- package/dist/services/ssh-pool-exec.js +10 -0
- package/dist/services/ssh-pool-exec.js.map +1 -0
- package/dist/services/ssh-pool.d.ts +66 -0
- package/dist/services/ssh-pool.d.ts.map +1 -0
- package/dist/services/ssh-pool.js +253 -0
- package/dist/services/ssh-pool.js.map +1 -0
- package/dist/services/ssh-service.d.ts +39 -0
- package/dist/services/ssh-service.d.ts.map +1 -0
- package/dist/services/ssh-service.js +143 -0
- package/dist/services/ssh-service.js.map +1 -0
- package/dist/services/ssh.d.ts +37 -0
- package/dist/services/ssh.d.ts.map +1 -0
- package/dist/services/ssh.js +50 -0
- package/dist/services/ssh.js.map +1 -0
- package/dist/tools/flux.d.ts +14 -0
- package/dist/tools/flux.d.ts.map +1 -0
- package/dist/tools/flux.js +86 -0
- package/dist/tools/flux.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +43 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/scout.d.ts +14 -0
- package/dist/tools/scout.d.ts.map +1 -0
- package/dist/tools/scout.js +96 -0
- package/dist/tools/scout.js.map +1 -0
- package/dist/tools/unified.d.ts +7 -0
- package/dist/tools/unified.d.ts.map +1 -0
- package/dist/tools/unified.js +827 -0
- package/dist/tools/unified.js.map +1 -0
- package/dist/types.d.ts +93 -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/errors.d.ts +60 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +131 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/help.d.ts +69 -0
- package/dist/utils/help.d.ts.map +1 -0
- package/dist/utils/help.js +259 -0
- package/dist/utils/help.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/path-security.d.ts +64 -0
- package/dist/utils/path-security.d.ts.map +1 -0
- package/dist/utils/path-security.js +138 -0
- package/dist/utils/path-security.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { NodeSSH } from "node-ssh";
|
|
2
|
+
import { HostOperationError, logError } from "../utils/errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Default pool configuration
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_POOL_CONFIG = {
|
|
7
|
+
maxConnections: 5,
|
|
8
|
+
idleTimeoutMs: 60000,
|
|
9
|
+
connectionTimeoutMs: 5000,
|
|
10
|
+
enableHealthChecks: true,
|
|
11
|
+
healthCheckIntervalMs: 30000
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Generate unique pool key for host
|
|
15
|
+
* Format: ${host.name}:${port}
|
|
16
|
+
*/
|
|
17
|
+
export function generatePoolKey(host) {
|
|
18
|
+
const port = host.port || 22;
|
|
19
|
+
return `${host.name}:${port}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* SSH Connection Pool Implementation
|
|
23
|
+
*/
|
|
24
|
+
export class SSHConnectionPoolImpl {
|
|
25
|
+
config;
|
|
26
|
+
pool;
|
|
27
|
+
stats;
|
|
28
|
+
healthCheckTimer;
|
|
29
|
+
constructor(config = {}) {
|
|
30
|
+
this.config = { ...DEFAULT_POOL_CONFIG, ...config };
|
|
31
|
+
this.pool = new Map();
|
|
32
|
+
this.stats = {
|
|
33
|
+
poolHits: 0,
|
|
34
|
+
poolMisses: 0,
|
|
35
|
+
activeConnections: 0,
|
|
36
|
+
idleConnections: 0,
|
|
37
|
+
totalConnections: 0,
|
|
38
|
+
healthChecksPassed: 0,
|
|
39
|
+
healthCheckFailures: 0
|
|
40
|
+
};
|
|
41
|
+
if (this.config.enableHealthChecks) {
|
|
42
|
+
this.startHealthChecks();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
getStats() {
|
|
46
|
+
return { ...this.stats };
|
|
47
|
+
}
|
|
48
|
+
startHealthChecks() {
|
|
49
|
+
this.healthCheckTimer = setInterval(() => {
|
|
50
|
+
void this.performHealthChecks();
|
|
51
|
+
}, this.config.healthCheckIntervalMs);
|
|
52
|
+
}
|
|
53
|
+
async performHealthChecks() {
|
|
54
|
+
const healthCheckPromises = [];
|
|
55
|
+
for (const [poolKey, connections] of this.pool.entries()) {
|
|
56
|
+
for (const metadata of connections) {
|
|
57
|
+
// Only check idle connections
|
|
58
|
+
if (!metadata.isActive) {
|
|
59
|
+
healthCheckPromises.push(this.checkConnectionHealth(poolKey, metadata));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
await Promise.allSettled(healthCheckPromises);
|
|
64
|
+
}
|
|
65
|
+
async checkConnectionHealth(poolKey, metadata) {
|
|
66
|
+
try {
|
|
67
|
+
// Verify connection using echo command
|
|
68
|
+
const result = await metadata.connection.execCommand("echo ok");
|
|
69
|
+
if (result.code === 0) {
|
|
70
|
+
// Health check passed (exit code 0 indicates success)
|
|
71
|
+
metadata.healthChecksPassed++;
|
|
72
|
+
this.stats.healthChecksPassed++;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Command failed
|
|
76
|
+
throw new Error("Health check command failed");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
logError(new HostOperationError("Health check failed", metadata.host.name, "healthCheck", error), {
|
|
81
|
+
metadata: {
|
|
82
|
+
poolKey,
|
|
83
|
+
failureCount: metadata.healthChecksFailed + 1,
|
|
84
|
+
lastUsed: new Date(metadata.lastUsed).toISOString()
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
metadata.healthChecksFailed++;
|
|
88
|
+
this.stats.healthCheckFailures++;
|
|
89
|
+
await this.removeConnection(poolKey, metadata);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async getConnection(host) {
|
|
93
|
+
const poolKey = generatePoolKey(host);
|
|
94
|
+
const connections = this.pool.get(poolKey) || [];
|
|
95
|
+
// Try to find idle connection
|
|
96
|
+
const idleConnection = connections.find((c) => !c.isActive);
|
|
97
|
+
if (idleConnection) {
|
|
98
|
+
// Reuse existing connection (pool hit)
|
|
99
|
+
idleConnection.isActive = true;
|
|
100
|
+
idleConnection.lastUsed = Date.now();
|
|
101
|
+
this.stats.poolHits++;
|
|
102
|
+
this.updateConnectionStats();
|
|
103
|
+
return idleConnection.connection;
|
|
104
|
+
}
|
|
105
|
+
// Check if we can create new connection
|
|
106
|
+
if (connections.length >= this.config.maxConnections) {
|
|
107
|
+
throw new Error(`Connection pool exhausted for ${poolKey} (max: ${this.config.maxConnections})`);
|
|
108
|
+
}
|
|
109
|
+
// Create new connection (pool miss)
|
|
110
|
+
const connection = await this.createConnection(host);
|
|
111
|
+
const metadata = {
|
|
112
|
+
connection,
|
|
113
|
+
host,
|
|
114
|
+
lastUsed: Date.now(),
|
|
115
|
+
created: Date.now(),
|
|
116
|
+
healthChecksPassed: 0,
|
|
117
|
+
healthChecksFailed: 0,
|
|
118
|
+
isActive: true
|
|
119
|
+
};
|
|
120
|
+
connections.push(metadata);
|
|
121
|
+
this.pool.set(poolKey, connections);
|
|
122
|
+
this.stats.poolMisses++;
|
|
123
|
+
this.updateConnectionStats();
|
|
124
|
+
return connection;
|
|
125
|
+
}
|
|
126
|
+
async createConnection(host) {
|
|
127
|
+
const ssh = new NodeSSH();
|
|
128
|
+
const connectionConfig = {
|
|
129
|
+
host: host.host,
|
|
130
|
+
port: host.port || 22,
|
|
131
|
+
username: host.sshUser || process.env.USER || "root",
|
|
132
|
+
privateKeyPath: host.sshKeyPath,
|
|
133
|
+
readyTimeout: this.config.connectionTimeoutMs
|
|
134
|
+
};
|
|
135
|
+
console.error(`[SSH Pool] Attempting connection to ${host.name} (${connectionConfig.host}:${connectionConfig.port})`);
|
|
136
|
+
console.error(`[SSH Pool] - Username: ${connectionConfig.username}`);
|
|
137
|
+
console.error(`[SSH Pool] - Private key: ${connectionConfig.privateKeyPath}`);
|
|
138
|
+
console.error(`[SSH Pool] - Ready timeout: ${connectionConfig.readyTimeout}ms`);
|
|
139
|
+
try {
|
|
140
|
+
await ssh.connect(connectionConfig);
|
|
141
|
+
console.error(`[SSH Pool] Successfully connected to ${host.name}`);
|
|
142
|
+
return ssh;
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
console.error(`[SSH Pool] Connection failed to ${host.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
updateConnectionStats() {
|
|
150
|
+
let active = 0;
|
|
151
|
+
let idle = 0;
|
|
152
|
+
let total = 0;
|
|
153
|
+
for (const connections of this.pool.values()) {
|
|
154
|
+
for (const conn of connections) {
|
|
155
|
+
total++;
|
|
156
|
+
if (conn.isActive) {
|
|
157
|
+
active++;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
idle++;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
this.stats.activeConnections = active;
|
|
165
|
+
this.stats.idleConnections = idle;
|
|
166
|
+
this.stats.totalConnections = total;
|
|
167
|
+
}
|
|
168
|
+
async releaseConnection(host, connection) {
|
|
169
|
+
const poolKey = generatePoolKey(host);
|
|
170
|
+
const connections = this.pool.get(poolKey);
|
|
171
|
+
if (!connections) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const metadata = connections.find((c) => c.connection === connection);
|
|
175
|
+
if (metadata) {
|
|
176
|
+
metadata.isActive = false;
|
|
177
|
+
metadata.lastUsed = Date.now();
|
|
178
|
+
this.updateConnectionStats();
|
|
179
|
+
// Start idle timeout timer
|
|
180
|
+
this.scheduleIdleCleanup(poolKey, metadata);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
scheduleIdleCleanup(poolKey, metadata) {
|
|
184
|
+
setTimeout(async () => {
|
|
185
|
+
const now = Date.now();
|
|
186
|
+
const idleTime = now - metadata.lastUsed;
|
|
187
|
+
// Only close if still idle and exceeded timeout
|
|
188
|
+
if (!metadata.isActive && idleTime >= this.config.idleTimeoutMs) {
|
|
189
|
+
await this.removeConnection(poolKey, metadata);
|
|
190
|
+
}
|
|
191
|
+
}, this.config.idleTimeoutMs);
|
|
192
|
+
}
|
|
193
|
+
async removeConnection(poolKey, metadata) {
|
|
194
|
+
const connections = this.pool.get(poolKey);
|
|
195
|
+
if (!connections)
|
|
196
|
+
return;
|
|
197
|
+
const index = connections.indexOf(metadata);
|
|
198
|
+
if (index !== -1) {
|
|
199
|
+
try {
|
|
200
|
+
await metadata.connection.dispose();
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
logError(new HostOperationError("Failed to dispose SSH connection", metadata.host.name, "dispose", error), { metadata: { poolKey } });
|
|
204
|
+
}
|
|
205
|
+
connections.splice(index, 1);
|
|
206
|
+
if (connections.length === 0) {
|
|
207
|
+
this.pool.delete(poolKey);
|
|
208
|
+
}
|
|
209
|
+
this.updateConnectionStats();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async closeConnection(host) {
|
|
213
|
+
const poolKey = generatePoolKey(host);
|
|
214
|
+
const connections = this.pool.get(poolKey);
|
|
215
|
+
if (!connections) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const closePromises = connections.map(async (metadata) => {
|
|
219
|
+
try {
|
|
220
|
+
await metadata.connection.dispose();
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
logError(new HostOperationError("Failed to dispose SSH connection during closeConnection", metadata.host.name, "closeConnection", error), { metadata: { poolKey } });
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
await Promise.allSettled(closePromises);
|
|
227
|
+
this.pool.delete(poolKey);
|
|
228
|
+
this.updateConnectionStats();
|
|
229
|
+
}
|
|
230
|
+
async closeAll() {
|
|
231
|
+
if (this.healthCheckTimer) {
|
|
232
|
+
clearInterval(this.healthCheckTimer);
|
|
233
|
+
this.healthCheckTimer = undefined;
|
|
234
|
+
}
|
|
235
|
+
const closePromises = [];
|
|
236
|
+
for (const connections of this.pool.values()) {
|
|
237
|
+
for (const metadata of connections) {
|
|
238
|
+
closePromises.push((async () => {
|
|
239
|
+
try {
|
|
240
|
+
await metadata.connection.dispose();
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
logError(new HostOperationError("Failed to dispose SSH connection during closeAll", metadata.host.name, "closeAll", error), { operation: "closeAll" });
|
|
244
|
+
}
|
|
245
|
+
})());
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
await Promise.allSettled(closePromises);
|
|
249
|
+
this.pool.clear();
|
|
250
|
+
this.updateConnectionStats();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=ssh-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-pool.js","sourceRoot":"","sources":["../../src/services/ssh-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { HostConfig } from "../types.js";
|
|
2
|
+
import type { ISSHConnectionPool, ISSHService } from "./interfaces.js";
|
|
3
|
+
import type { HostResources } from "./ssh.js";
|
|
4
|
+
/**
|
|
5
|
+
* Options for SSH command execution
|
|
6
|
+
*/
|
|
7
|
+
export interface SSHCommandOptions {
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* SSH service implementation using connection pool for command execution.
|
|
12
|
+
* Provides secure command execution and resource monitoring via SSH connections.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SSHService implements ISSHService {
|
|
15
|
+
private readonly pool;
|
|
16
|
+
constructor(pool: ISSHConnectionPool);
|
|
17
|
+
/**
|
|
18
|
+
* Execute SSH command using connection pool
|
|
19
|
+
*
|
|
20
|
+
* Automatically acquires connection from pool, executes command, and releases.
|
|
21
|
+
* Connections are reused across calls for better performance.
|
|
22
|
+
*
|
|
23
|
+
* @param host - Host configuration
|
|
24
|
+
* @param command - Command to execute
|
|
25
|
+
* @param args - Command arguments (optional)
|
|
26
|
+
* @param options - Execution options (timeout, etc.)
|
|
27
|
+
* @returns Command stdout (trimmed)
|
|
28
|
+
* @throws SSHCommandError if command fails or times out
|
|
29
|
+
*/
|
|
30
|
+
executeSSHCommand(host: HostConfig, command: string, args?: string[], options?: SSHCommandOptions): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Get host resource usage via SSH using connection pool
|
|
33
|
+
*
|
|
34
|
+
* @param host - Host configuration to query
|
|
35
|
+
* @returns Resource information including CPU, memory, disk, and uptime
|
|
36
|
+
*/
|
|
37
|
+
getHostResources(host: HostConfig): Promise<HostResources>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=ssh-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-service.d.ts","sourceRoot":"","sources":["../../src/services/ssh-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,UAAW,YAAW,WAAW;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,kBAAkB;IAErD;;;;;;;;;;;;OAYG;IACG,iBAAiB,CACrB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,MAAM,EAAO,EACnB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC;IAiElB;;;;;OAKG;IACG,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;CAoFjE"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { SSHCommandError } from "../utils/errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* SSH service implementation using connection pool for command execution.
|
|
4
|
+
* Provides secure command execution and resource monitoring via SSH connections.
|
|
5
|
+
*/
|
|
6
|
+
export class SSHService {
|
|
7
|
+
pool;
|
|
8
|
+
constructor(pool) {
|
|
9
|
+
this.pool = pool;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Execute SSH command using connection pool
|
|
13
|
+
*
|
|
14
|
+
* Automatically acquires connection from pool, executes command, and releases.
|
|
15
|
+
* Connections are reused across calls for better performance.
|
|
16
|
+
*
|
|
17
|
+
* @param host - Host configuration
|
|
18
|
+
* @param command - Command to execute
|
|
19
|
+
* @param args - Command arguments (optional)
|
|
20
|
+
* @param options - Execution options (timeout, etc.)
|
|
21
|
+
* @returns Command stdout (trimmed)
|
|
22
|
+
* @throws SSHCommandError if command fails or times out
|
|
23
|
+
*/
|
|
24
|
+
async executeSSHCommand(host, command, args = [], options = {}) {
|
|
25
|
+
const timeoutMs = options.timeoutMs || 30000;
|
|
26
|
+
// Get connection from pool
|
|
27
|
+
const connection = await this.pool.getConnection(host);
|
|
28
|
+
// Build full command
|
|
29
|
+
const fullCommand = args.length > 0 ? `${command} ${args.join(" ")}` : command;
|
|
30
|
+
try {
|
|
31
|
+
// Execute with timeout
|
|
32
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
reject(new Error(`SSH command timeout after ${timeoutMs}ms: ${command}`));
|
|
35
|
+
}, timeoutMs);
|
|
36
|
+
});
|
|
37
|
+
const execPromise = connection.execCommand(fullCommand);
|
|
38
|
+
const result = await Promise.race([execPromise, timeoutPromise]);
|
|
39
|
+
// Check exit code
|
|
40
|
+
if (result.code !== 0) {
|
|
41
|
+
throw new SSHCommandError("SSH command failed with non-zero exit code", host.name, fullCommand, result.code ?? undefined, result.stderr, result.stdout);
|
|
42
|
+
}
|
|
43
|
+
return result.stdout.trim();
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof Error) {
|
|
47
|
+
if (error instanceof SSHCommandError) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
const baseMessage = error.message || "SSH command execution failed";
|
|
51
|
+
throw new SSHCommandError(baseMessage, host.name, fullCommand, undefined, undefined, undefined, error);
|
|
52
|
+
}
|
|
53
|
+
throw new SSHCommandError("SSH command execution failed", host.name, fullCommand, undefined, undefined, undefined, error);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
// Always release connection back to pool
|
|
57
|
+
await this.pool.releaseConnection(host, connection);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get host resource usage via SSH using connection pool
|
|
62
|
+
*
|
|
63
|
+
* @param host - Host configuration to query
|
|
64
|
+
* @returns Resource information including CPU, memory, disk, and uptime
|
|
65
|
+
*/
|
|
66
|
+
async getHostResources(host) {
|
|
67
|
+
// Run all commands in one SSH session for efficiency
|
|
68
|
+
const script = `
|
|
69
|
+
hostname
|
|
70
|
+
echo "---"
|
|
71
|
+
uptime -p 2>/dev/null || uptime | sed 's/.*up/up/'
|
|
72
|
+
echo "---"
|
|
73
|
+
cat /proc/loadavg | awk '{print $1,$2,$3}'
|
|
74
|
+
echo "---"
|
|
75
|
+
nproc
|
|
76
|
+
echo "---"
|
|
77
|
+
top -bn1 | grep "Cpu(s)" | awk '{print 100-$8}' 2>/dev/null || echo "0"
|
|
78
|
+
echo "---"
|
|
79
|
+
free -m | awk '/^Mem:/ {print $2,$3,$4}'
|
|
80
|
+
echo "---"
|
|
81
|
+
df -BG --output=source,target,size,used,avail,pcent 2>/dev/null | grep -E '^/dev' || df -h | grep -E '^/dev'
|
|
82
|
+
`
|
|
83
|
+
.trim()
|
|
84
|
+
.replace(/\n/g, "; ");
|
|
85
|
+
const output = await this.executeSSHCommand(host, script);
|
|
86
|
+
const sections = output.split("---").map((s) => s.trim());
|
|
87
|
+
// Parse hostname
|
|
88
|
+
const hostname = sections[0] || host.name;
|
|
89
|
+
// Parse uptime
|
|
90
|
+
const uptime = sections[1] || "unknown";
|
|
91
|
+
// Parse load average
|
|
92
|
+
const loadParts = (sections[2] || "0 0 0").split(" ").map(Number);
|
|
93
|
+
const loadAverage = [
|
|
94
|
+
loadParts[0] || 0,
|
|
95
|
+
loadParts[1] || 0,
|
|
96
|
+
loadParts[2] || 0
|
|
97
|
+
];
|
|
98
|
+
// Parse CPU
|
|
99
|
+
const cores = parseInt(sections[3] || "1", 10);
|
|
100
|
+
const cpuUsage = parseFloat(sections[4] || "0");
|
|
101
|
+
// Parse memory
|
|
102
|
+
const memParts = (sections[5] || "0 0 0").split(" ").map(Number);
|
|
103
|
+
const totalMB = memParts[0] || 0;
|
|
104
|
+
const usedMB = memParts[1] || 0;
|
|
105
|
+
const freeMB = memParts[2] || 0;
|
|
106
|
+
const memUsagePercent = totalMB > 0 ? (usedMB / totalMB) * 100 : 0;
|
|
107
|
+
// Parse disk
|
|
108
|
+
const diskLines = (sections[6] || "").split("\n").filter((l) => l.trim());
|
|
109
|
+
const disk = diskLines
|
|
110
|
+
.map((line) => {
|
|
111
|
+
const parts = line.trim().split(/\s+/);
|
|
112
|
+
if (parts.length >= 6) {
|
|
113
|
+
return {
|
|
114
|
+
filesystem: parts[0],
|
|
115
|
+
mount: parts[1],
|
|
116
|
+
totalGB: parseFloat(parts[2].replace("G", "")) || 0,
|
|
117
|
+
usedGB: parseFloat(parts[3].replace("G", "")) || 0,
|
|
118
|
+
availGB: parseFloat(parts[4].replace("G", "")) || 0,
|
|
119
|
+
usagePercent: parseFloat(parts[5].replace("%", "")) || 0
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
})
|
|
124
|
+
.filter((d) => d !== null);
|
|
125
|
+
return {
|
|
126
|
+
hostname,
|
|
127
|
+
uptime,
|
|
128
|
+
loadAverage,
|
|
129
|
+
cpu: {
|
|
130
|
+
cores,
|
|
131
|
+
usagePercent: Math.round(cpuUsage * 10) / 10
|
|
132
|
+
},
|
|
133
|
+
memory: {
|
|
134
|
+
totalMB,
|
|
135
|
+
usedMB,
|
|
136
|
+
freeMB,
|
|
137
|
+
usagePercent: Math.round(memUsagePercent * 10) / 10
|
|
138
|
+
},
|
|
139
|
+
disk
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=ssh-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-service.js","sourceRoot":"","sources":["../../src/services/ssh-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { HostConfig } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sanitize string for safe shell usage
|
|
4
|
+
* Rejects any potentially dangerous characters
|
|
5
|
+
*/
|
|
6
|
+
export declare function sanitizeForShell(input: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Validate host configuration for SSH
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateHostForSsh(host: HostConfig): void;
|
|
11
|
+
/**
|
|
12
|
+
* Host resource stats from SSH
|
|
13
|
+
*/
|
|
14
|
+
export interface HostResources {
|
|
15
|
+
hostname: string;
|
|
16
|
+
uptime: string;
|
|
17
|
+
loadAverage: [number, number, number];
|
|
18
|
+
cpu: {
|
|
19
|
+
cores: number;
|
|
20
|
+
usagePercent: number;
|
|
21
|
+
};
|
|
22
|
+
memory: {
|
|
23
|
+
totalMB: number;
|
|
24
|
+
usedMB: number;
|
|
25
|
+
freeMB: number;
|
|
26
|
+
usagePercent: number;
|
|
27
|
+
};
|
|
28
|
+
disk: Array<{
|
|
29
|
+
filesystem: string;
|
|
30
|
+
mount: string;
|
|
31
|
+
totalGB: number;
|
|
32
|
+
usedGB: number;
|
|
33
|
+
availGB: number;
|
|
34
|
+
usagePercent: number;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=ssh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh.d.ts","sourceRoot":"","sources":["../../src/services/ssh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA4BzC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMtD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAezD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,GAAG,EAAE;QACH,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,IAAI,EAAE,KAAK,CAAC;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SSHService } from "./ssh-service.js";
|
|
2
|
+
import { SSHConnectionPoolImpl } from "./ssh-pool.js";
|
|
3
|
+
/**
|
|
4
|
+
* Temporary global SSH service for backward compatibility
|
|
5
|
+
* @deprecated Use ServiceContainer.getSSHService() instead
|
|
6
|
+
*/
|
|
7
|
+
let globalSSHService = null;
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
9
|
+
function getGlobalSSHService() {
|
|
10
|
+
if (!globalSSHService) {
|
|
11
|
+
const pool = new SSHConnectionPoolImpl({
|
|
12
|
+
maxConnections: parseInt(process.env.HOMELAB_SSH_MAX_CONNECTIONS || "5", 10),
|
|
13
|
+
idleTimeoutMs: parseInt(process.env.HOMELAB_SSH_IDLE_TIMEOUT_MS || "60000", 10),
|
|
14
|
+
connectionTimeoutMs: parseInt(process.env.HOMELAB_SSH_CONNECTION_TIMEOUT_MS || "5000", 10),
|
|
15
|
+
enableHealthChecks: process.env.HOMELAB_SSH_ENABLE_HEALTH_CHECKS !== "false",
|
|
16
|
+
healthCheckIntervalMs: parseInt(process.env.HOMELAB_SSH_HEALTH_CHECK_INTERVAL_MS || "30000", 10)
|
|
17
|
+
});
|
|
18
|
+
globalSSHService = new SSHService(pool);
|
|
19
|
+
}
|
|
20
|
+
return globalSSHService;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Sanitize string for safe shell usage
|
|
24
|
+
* Rejects any potentially dangerous characters
|
|
25
|
+
*/
|
|
26
|
+
export function sanitizeForShell(input) {
|
|
27
|
+
// Only allow alphanumeric, dots, hyphens, underscores, and forward slashes (for paths)
|
|
28
|
+
if (!/^[a-zA-Z0-9._\-/]+$/.test(input)) {
|
|
29
|
+
throw new Error(`Invalid characters in input: ${input}`);
|
|
30
|
+
}
|
|
31
|
+
return input;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate host configuration for SSH
|
|
35
|
+
*/
|
|
36
|
+
export function validateHostForSsh(host) {
|
|
37
|
+
// Validate hostname/IP - allow alphanumeric, dots, hyphens, colons (IPv6), and brackets
|
|
38
|
+
if (host.host && !/^[a-zA-Z0-9.\-:[\]/]+$/.test(host.host)) {
|
|
39
|
+
throw new Error(`Invalid host format: ${host.host}`);
|
|
40
|
+
}
|
|
41
|
+
// Validate SSH user if provided
|
|
42
|
+
if (host.sshUser && !/^[a-zA-Z0-9_-]+$/.test(host.sshUser)) {
|
|
43
|
+
throw new Error(`Invalid SSH user: ${host.sshUser}`);
|
|
44
|
+
}
|
|
45
|
+
// Validate key path if provided
|
|
46
|
+
if (host.sshKeyPath && !/^[a-zA-Z0-9._\-/~]+$/.test(host.sshKeyPath)) {
|
|
47
|
+
throw new Error(`Invalid SSH key path: ${host.sshKeyPath}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=ssh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../src/services/ssh.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;GAGG;AACH,IAAI,gBAAgB,GAAsB,IAAI,CAAC;AAE/C,6DAA6D;AAC7D,SAAS,mBAAmB;IAC1B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,IAAI,qBAAqB,CAAC;YACrC,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,GAAG,EAAE,EAAE,CAAC;YAC5E,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,OAAO,EAAE,EAAE,CAAC;YAC/E,mBAAmB,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,MAAM,EAAE,EAAE,CAAC;YAC1F,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,gCAAgC,KAAK,OAAO;YAC5E,qBAAqB,EAAE,QAAQ,CAC7B,OAAO,CAAC,GAAG,CAAC,oCAAoC,IAAI,OAAO,EAC3D,EAAE,CACH;SACF,CAAC,CAAC;QACH,gBAAgB,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,uFAAuF;IACvF,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAgB;IACjD,wFAAwF;IACxF,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,gCAAgC;IAChC,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,gCAAgC;IAChC,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ServiceContainer } from '../services/container.js';
|
|
2
|
+
/**
|
|
3
|
+
* Flux tool handler - Docker infrastructure management
|
|
4
|
+
*
|
|
5
|
+
* Handles 4 action categories with 39 total subactions:
|
|
6
|
+
* - container: 14 subactions (list, start, stop, restart, pause, resume, logs, stats, inspect, search, pull, recreate, exec, top)
|
|
7
|
+
* - compose: 9 subactions (list, status, up, down, restart, logs, build, pull, recreate)
|
|
8
|
+
* - docker: 9 subactions (info, df, prune, images, pull, build, rmi, networks, volumes)
|
|
9
|
+
* - host: 7 subactions (status, resources, info, uptime, services, network, mounts)
|
|
10
|
+
*
|
|
11
|
+
* Plus 'help' pseudo-action for auto-generated documentation.
|
|
12
|
+
*/
|
|
13
|
+
export declare function handleFluxTool(input: unknown, container: ServiceContainer): Promise<string>;
|
|
14
|
+
//# sourceMappingURL=flux.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flux.d.ts","sourceRoot":"","sources":["../../src/tools/flux.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAQjE;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,gBAAgB,GAC1B,OAAO,CAAC,MAAM,CAAC,CA6BjB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// src/tools/flux.ts
|
|
2
|
+
import { FluxSchema } from '../schemas/flux/index.js';
|
|
3
|
+
import { generateHelp, formatHelpMarkdown, formatHelpJson } from '../utils/help.js';
|
|
4
|
+
/**
|
|
5
|
+
* Flux tool handler - Docker infrastructure management
|
|
6
|
+
*
|
|
7
|
+
* Handles 4 action categories with 39 total subactions:
|
|
8
|
+
* - container: 14 subactions (list, start, stop, restart, pause, resume, logs, stats, inspect, search, pull, recreate, exec, top)
|
|
9
|
+
* - compose: 9 subactions (list, status, up, down, restart, logs, build, pull, recreate)
|
|
10
|
+
* - docker: 9 subactions (info, df, prune, images, pull, build, rmi, networks, volumes)
|
|
11
|
+
* - host: 7 subactions (status, resources, info, uptime, services, network, mounts)
|
|
12
|
+
*
|
|
13
|
+
* Plus 'help' pseudo-action for auto-generated documentation.
|
|
14
|
+
*/
|
|
15
|
+
export async function handleFluxTool(input, container) {
|
|
16
|
+
// Handle help action before schema validation
|
|
17
|
+
if (typeof input === 'object' && input !== null && 'action' in input && input.action === 'help') {
|
|
18
|
+
const helpInput = input;
|
|
19
|
+
const entries = generateHelp(FluxSchema, helpInput.topic);
|
|
20
|
+
if (helpInput.format === 'json') {
|
|
21
|
+
return formatHelpJson(entries);
|
|
22
|
+
}
|
|
23
|
+
return formatHelpMarkdown(entries);
|
|
24
|
+
}
|
|
25
|
+
// Validate input against Flux schema
|
|
26
|
+
const validated = FluxSchema.parse(input);
|
|
27
|
+
// Route to appropriate handler based on action
|
|
28
|
+
switch (validated.action) {
|
|
29
|
+
case 'container':
|
|
30
|
+
return handleContainerAction(validated, container);
|
|
31
|
+
case 'compose':
|
|
32
|
+
return handleComposeAction(validated, container);
|
|
33
|
+
case 'docker':
|
|
34
|
+
return handleDockerAction(validated, container);
|
|
35
|
+
case 'host':
|
|
36
|
+
return handleHostAction(validated, container);
|
|
37
|
+
default:
|
|
38
|
+
// Zod validation should prevent reaching here
|
|
39
|
+
throw new Error(`Unknown action: ${validated.action}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Placeholder handler for container actions
|
|
44
|
+
* Will be implemented in Task 16
|
|
45
|
+
*/
|
|
46
|
+
function handleContainerAction(input, _container) {
|
|
47
|
+
// Type guard to ensure we have container action
|
|
48
|
+
if (input.action !== 'container') {
|
|
49
|
+
throw new Error(`Invalid action for container handler: ${input.action}`);
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Handler not implemented: container:${input.subaction}`);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Placeholder handler for compose actions
|
|
55
|
+
* Will be implemented in Task 17
|
|
56
|
+
*/
|
|
57
|
+
function handleComposeAction(input, _container) {
|
|
58
|
+
// Type guard to ensure we have compose action
|
|
59
|
+
if (input.action !== 'compose') {
|
|
60
|
+
throw new Error(`Invalid action for compose handler: ${input.action}`);
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`Handler not implemented: compose:${input.subaction}`);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Placeholder handler for docker actions
|
|
66
|
+
* Will be implemented in Task 18
|
|
67
|
+
*/
|
|
68
|
+
function handleDockerAction(input, _container) {
|
|
69
|
+
// Type guard to ensure we have docker action
|
|
70
|
+
if (input.action !== 'docker') {
|
|
71
|
+
throw new Error(`Invalid action for docker handler: ${input.action}`);
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`Handler not implemented: docker:${input.subaction}`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Placeholder handler for host actions
|
|
77
|
+
* Will be implemented in Task 19
|
|
78
|
+
*/
|
|
79
|
+
function handleHostAction(input, _container) {
|
|
80
|
+
// Type guard to ensure we have host action
|
|
81
|
+
if (input.action !== 'host') {
|
|
82
|
+
throw new Error(`Invalid action for host handler: ${input.action}`);
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`Handler not implemented: host:${input.subaction}`);
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=flux.js.map
|