@ebowwa/terminal 0.2.1 → 0.3.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/src/exec.js DELETED
@@ -1,183 +0,0 @@
1
- "use strict";
2
- /**
3
- * SSH command execution functions
4
- */
5
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
- return new (P || (P = Promise))(function (resolve, reject) {
8
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
- step((generator = generator.apply(thisArg, _arguments || [])).next());
12
- });
13
- };
14
- var __generator = (this && this.__generator) || function (thisArg, body) {
15
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
16
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
17
- function verb(n) { return function (v) { return step([n, v]); }; }
18
- function step(op) {
19
- if (f) throw new TypeError("Generator is already executing.");
20
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
21
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
22
- if (y = 0, t) op = [op[0] & 2, t.value];
23
- switch (op[0]) {
24
- case 0: case 1: t = op; break;
25
- case 4: _.label++; return { value: op[1], done: false };
26
- case 5: _.label++; y = op[1]; op = [0]; continue;
27
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
28
- default:
29
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
30
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
31
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
32
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
33
- if (t[2]) _.ops.pop();
34
- _.trys.pop(); continue;
35
- }
36
- op = body.call(thisArg, _);
37
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
38
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
39
- }
40
- };
41
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
42
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
43
- if (ar || !(i in from)) {
44
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
45
- ar[i] = from[i];
46
- }
47
- }
48
- return to.concat(ar || Array.prototype.slice.call(from));
49
- };
50
- Object.defineProperty(exports, "__esModule", { value: true });
51
- exports.execSSHParallel = execSSHParallel;
52
- exports.testSSHConnection = testSSHConnection;
53
- var client_js_1 = require("./client.js");
54
- var pool_js_1 = require("./pool.js");
55
- /**
56
- * Execute multiple SSH commands in parallel using multiple connections
57
- *
58
- * DESIGN DECISION: Multiple Connections vs Single Connection
59
- * ===========================================================
60
- *
61
- * We use MULTIPLE SSH connections to avoid channel saturation issues.
62
- * SSH servers typically limit concurrent channels per connection (~10).
63
- * When executing 9+ commands in parallel, we can exceed this limit.
64
- *
65
- * Solution: Distribute commands across multiple pooled connections.
66
- * Each connection handles a subset of commands, staying within channel limits.
67
- *
68
- * DESIGN DECISION: Promise.allSettled() vs Promise.all()
69
- * ======================================================
70
- *
71
- * We use Promise.allSettled() instead of Promise.all() for a critical reason:
72
- * Resource monitoring should be RESILIENT. If one command fails (e.g., GPU
73
- * query on a CPU-only server), we still want results from all other commands.
74
- *
75
- * Example scenario:
76
- * - CPU, memory, disk commands: succeed
77
- * - GPU command: fails (no NVIDIA GPU)
78
- * - Network command: succeeds
79
- *
80
- * With Promise.all(): entire batch fails, no metrics collected
81
- * With Promise.allSettled(): we get 6/7 metrics, GPU returns "0" fallback
82
- *
83
- * ERROR HANDLING:
84
- * ==============
85
- * 1. Individual command failures are logged to console
86
- * 2. Failed commands return "0" as fallback (matches execSSH default)
87
- * 3. The function always completes successfully (never throws)
88
- * 4. Calling code can check for "0" values to detect failures
89
- */
90
- function execSSHParallel(commands, options) {
91
- return __awaiter(this, void 0, void 0, function () {
92
- var entries, pool, numCommands, numConnections, connections, connectionPromises, allSettledResults, results, _i, allSettledResults_1, connResults, _a, connResults_1, result;
93
- var _this = this;
94
- return __generator(this, function (_b) {
95
- switch (_b.label) {
96
- case 0:
97
- entries = Object.entries(commands);
98
- pool = (0, pool_js_1.getSSHPool)();
99
- numCommands = entries.length;
100
- numConnections = Math.min(numCommands, 4);
101
- return [4 /*yield*/, pool.getConnections(options, numConnections)];
102
- case 1:
103
- connections = _b.sent();
104
- connectionPromises = connections.map(function (ssh, connIndex) {
105
- // Assign commands to this connection
106
- var assignedCommands = entries.filter(function (_, i) { return i % numConnections === connIndex; });
107
- // Execute all assigned commands on this connection
108
- return Promise.allSettled(assignedCommands.map(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
109
- var result, error_1;
110
- var key = _b[0], cmd = _b[1];
111
- return __generator(this, function (_c) {
112
- switch (_c.label) {
113
- case 0:
114
- _c.trys.push([0, 2, , 3]);
115
- return [4 /*yield*/, ssh.execCommand(cmd, {
116
- execOptions: {
117
- timeout: (options.timeout || 5) * 1000,
118
- },
119
- })];
120
- case 1:
121
- result = _c.sent();
122
- // If we have stderr but no stdout, the command failed
123
- if (result.stderr && !result.stdout) {
124
- throw new Error(result.stderr);
125
- }
126
- return [2 /*return*/, [key, result.stdout.trim()]];
127
- case 2:
128
- error_1 = _c.sent();
129
- // Log the error with full details including cause
130
- console.error("[execSSHParallel] Command \"".concat(key, "\" failed:"), error_1 instanceof Error ? error_1.message : error_1);
131
- // Log the underlying cause if available
132
- if (error_1 instanceof Error && error_1.cause) {
133
- console.error("[execSSHParallel] Command \"".concat(key, "\" cause:"), error_1.cause);
134
- }
135
- return [2 /*return*/, [key, "0"]]; // Fallback value
136
- case 3: return [2 /*return*/];
137
- }
138
- });
139
- }); }));
140
- });
141
- return [4 /*yield*/, Promise.all(connectionPromises)];
142
- case 2:
143
- allSettledResults = _b.sent();
144
- results = [];
145
- for (_i = 0, allSettledResults_1 = allSettledResults; _i < allSettledResults_1.length; _i++) {
146
- connResults = allSettledResults_1[_i];
147
- for (_a = 0, connResults_1 = connResults; _a < connResults_1.length; _a++) {
148
- result = connResults_1[_a];
149
- if (result.status === "fulfilled") {
150
- results.push(__spreadArray([], result.value, true));
151
- }
152
- // Rejected promises are already logged and return "0" above
153
- }
154
- }
155
- return [2 /*return*/, Object.fromEntries(results)];
156
- }
157
- });
158
- });
159
- }
160
- /**
161
- * Test SSH connection to a remote server
162
- * @param options - SSH connection options
163
- * @returns True if connection successful
164
- */
165
- function testSSHConnection(options) {
166
- return __awaiter(this, void 0, void 0, function () {
167
- var _a;
168
- return __generator(this, function (_b) {
169
- switch (_b.label) {
170
- case 0:
171
- _b.trys.push([0, 2, , 3]);
172
- return [4 /*yield*/, (0, client_js_1.execSSH)('echo "connection_test"', options)];
173
- case 1:
174
- _b.sent();
175
- return [2 /*return*/, true];
176
- case 2:
177
- _a = _b.sent();
178
- return [2 /*return*/, false];
179
- case 3: return [2 /*return*/];
180
- }
181
- });
182
- });
183
- }