@elizaos/cli 1.4.3 → 1.4.5
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/dist/BrowserWebSocketTransport-5YQPVDV7.js +7 -0
- package/dist/EnhancedEvaluationEngine-APOQ6INN.js +473 -0
- package/dist/EvaluationEngine-Y7ZQJBRC.js +9 -0
- package/dist/LocalEnvironmentProvider-JWFGG4IN.js +15 -0
- package/dist/NodeWebSocketTransport-PUO724EY.js +8 -0
- package/dist/ScreenRecorder-YK246DNJ.js +10 -0
- package/dist/agent-start-6QJQAMKA.js +13 -0
- package/dist/bidi-2SVNH6F7.js +15309 -0
- package/dist/{bun-exec-ULMPAIQC.js → bun-exec-NH4UCUY4.js} +1 -1
- package/dist/chunk-2ESYSVXG.js +48 -0
- package/dist/chunk-3AEYIKBZ.js +432 -0
- package/dist/chunk-5IWKEMEF.js +239 -0
- package/dist/chunk-5WZO2HMM.js +2644 -0
- package/dist/chunk-ABGBVB74.js +3501 -0
- package/dist/{chunk-NSNXXD3I.js → chunk-BCO32GR6.js} +2 -2
- package/dist/chunk-CGXTFHQP.js +25 -0
- package/dist/chunk-EXUFDTUD.js +3948 -0
- package/dist/chunk-FGGNHEXZ.js +211860 -0
- package/dist/chunk-FWYHSCLF.js +243 -0
- package/dist/chunk-I57T3WPO.js +165 -0
- package/dist/chunk-LBZLMFFF.js +221 -0
- package/dist/chunk-LG7YDBMV.js +401 -0
- package/dist/chunk-NHKLUXNE.js +166 -0
- package/dist/chunk-PUZHCSGF.js +828 -0
- package/dist/chunk-PWDR7CPA.js +7828 -0
- package/dist/{chunk-N5G5XSGP.js → chunk-Q6M2K53X.js} +3 -3
- package/dist/chunk-SVHCNBHM.js +289 -0
- package/dist/{chunk-HOC6B3QV.js → chunk-VFFOOPYS.js} +4 -238
- package/dist/chunk-WX37MM4G.js +292 -0
- package/dist/chunk-XFJIHUT3.js +6 -0
- package/dist/chunk-XPPESCCM.js +787 -0
- package/dist/chunk-YBDC5OZO.js +40 -0
- package/dist/commands/agent/actions/index.js +2 -2
- package/dist/commands/agent/index.js +2 -2
- package/dist/commands/create/actions/index.js +4 -3
- package/dist/commands/create/index.js +5 -4
- package/dist/commands/shared/index.js +1 -1
- package/dist/index.js +66820 -5009
- package/dist/js-yaml-KADNMPWR.js +35 -0
- package/dist/matrix-orchestrator-3WLRK7GG.js +1070 -0
- package/dist/matrix-runner-KDPETCKQ.js +160 -0
- package/dist/matrix-schema-PCO2KGJY.js +102 -0
- package/dist/parameter-override-ALOPPXCE.js +487 -0
- package/dist/{plugin-creator-TCUFII32.js → plugin-creator-J7GNPMPG.js} +1 -1
- package/dist/process-manager-IU2A3BTQ.js +9 -0
- package/dist/{registry-ELONUC44.js → registry-65KMEA7N.js} +2 -2
- package/dist/resource-monitor-EHZSH2P6.js +15 -0
- package/dist/run-isolation-PGLZ37Y7.js +29 -0
- package/dist/runtime-factory-Q4U5YBNV.js +22 -0
- package/dist/schema-C25LVPEK.js +17 -0
- package/dist/src/commands/report/src/assets/report_template.html +1704 -0
- package/dist/src-EJG4ILDC.js +5 -0
- package/dist/templates/plugin-quick-starter/package.json +2 -2
- package/dist/templates/plugin-quick-starter/src/__tests__/test-utils.ts +1 -0
- package/dist/templates/plugin-starter/package.json +2 -2
- package/dist/templates/plugin-starter/src/__tests__/test-utils.ts +1 -0
- package/dist/templates/project-starter/package.json +4 -4
- package/dist/templates/project-tee-starter/package.json +4 -4
- package/dist/templates/project-tee-starter/src/index.ts +1 -2
- package/dist/typescript-ZF3IK2DJ.js +5 -0
- package/dist/{utils-X6UXPLKD.js → utils-QFD2PW4X.js} +2 -2
- package/package.json +14 -8
- package/templates/plugin-quick-starter/package.json +2 -2
- package/templates/plugin-quick-starter/src/__tests__/test-utils.ts +1 -0
- package/templates/plugin-starter/package.json +2 -2
- package/templates/plugin-starter/src/__tests__/test-utils.ts +1 -0
- package/templates/project-starter/package.json +4 -4
- package/templates/project-tee-starter/package.json +4 -4
- package/templates/project-tee-starter/src/index.ts +1 -2
- package/dist/chunk-3RG5ZIWI.js +0 -10
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import {
|
|
2
|
+
require_src
|
|
3
|
+
} from "./chunk-XPPESCCM.js";
|
|
4
|
+
import {
|
|
5
|
+
CDPSessionEvent,
|
|
6
|
+
asyncDisposeSymbol,
|
|
7
|
+
bufferCount,
|
|
8
|
+
concatMap,
|
|
9
|
+
debugError,
|
|
10
|
+
filter,
|
|
11
|
+
from,
|
|
12
|
+
fromEmitterEvent,
|
|
13
|
+
fromEvent,
|
|
14
|
+
guarded,
|
|
15
|
+
lastValueFrom,
|
|
16
|
+
map,
|
|
17
|
+
takeUntil,
|
|
18
|
+
tap
|
|
19
|
+
} from "./chunk-ABGBVB74.js";
|
|
20
|
+
import {
|
|
21
|
+
__toESM
|
|
22
|
+
} from "./chunk-2ESYSVXG.js";
|
|
23
|
+
|
|
24
|
+
// ../../node_modules/puppeteer-core/lib/esm/puppeteer/node/ScreenRecorder.js
|
|
25
|
+
var import_debug = __toESM(require_src(), 1);
|
|
26
|
+
import { spawn, spawnSync } from "child_process";
|
|
27
|
+
import { PassThrough } from "stream";
|
|
28
|
+
var __runInitializers = function(thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
36
|
+
function accept(f) {
|
|
37
|
+
if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected");
|
|
38
|
+
return f;
|
|
39
|
+
}
|
|
40
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
41
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
42
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
43
|
+
var _, done = false;
|
|
44
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
45
|
+
var context = {};
|
|
46
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
47
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
48
|
+
context.addInitializer = function(f) {
|
|
49
|
+
if (done) throw new TypeError("Cannot add initializers after decoration has completed");
|
|
50
|
+
extraInitializers.push(accept(f || null));
|
|
51
|
+
};
|
|
52
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
53
|
+
if (kind === "accessor") {
|
|
54
|
+
if (result === void 0) continue;
|
|
55
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
56
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
57
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
58
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
59
|
+
} else if (_ = accept(result)) {
|
|
60
|
+
if (kind === "field") initializers.unshift(_);
|
|
61
|
+
else descriptor[key] = _;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
65
|
+
done = true;
|
|
66
|
+
};
|
|
67
|
+
var __setFunctionName = function(f, name, prefix) {
|
|
68
|
+
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
69
|
+
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
70
|
+
};
|
|
71
|
+
var CRF_VALUE = 30;
|
|
72
|
+
var DEFAULT_FPS = 30;
|
|
73
|
+
var debugFfmpeg = (0, import_debug.default)("puppeteer:ffmpeg");
|
|
74
|
+
var ScreenRecorder = (() => {
|
|
75
|
+
let _classSuper = PassThrough;
|
|
76
|
+
let _instanceExtraInitializers = [];
|
|
77
|
+
let _private_writeFrame_decorators;
|
|
78
|
+
let _private_writeFrame_descriptor;
|
|
79
|
+
let _stop_decorators;
|
|
80
|
+
return class ScreenRecorder extends _classSuper {
|
|
81
|
+
static {
|
|
82
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
83
|
+
__esDecorate(this, _private_writeFrame_descriptor = { value: __setFunctionName(async function(buffer) {
|
|
84
|
+
const error = await new Promise((resolve) => {
|
|
85
|
+
this.#process.stdin.write(buffer, resolve);
|
|
86
|
+
});
|
|
87
|
+
if (error) {
|
|
88
|
+
console.log(`ffmpeg failed to write: ${error.message}.`);
|
|
89
|
+
}
|
|
90
|
+
}, "#writeFrame") }, _private_writeFrame_decorators, { kind: "method", name: "#writeFrame", static: false, private: true, access: { has: (obj) => #writeFrame in obj, get: (obj) => obj.#writeFrame }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
91
|
+
__esDecorate(this, null, _stop_decorators, { kind: "method", name: "stop", static: false, private: false, access: { has: (obj) => "stop" in obj, get: (obj) => obj.stop }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
92
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
93
|
+
}
|
|
94
|
+
#page = __runInitializers(this, _instanceExtraInitializers);
|
|
95
|
+
#process;
|
|
96
|
+
#controller = new AbortController();
|
|
97
|
+
#lastFrame;
|
|
98
|
+
/**
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
constructor(page, width, height, { speed, scale, crop, format, path } = {}) {
|
|
102
|
+
super({ allowHalfOpen: false });
|
|
103
|
+
path ??= "ffmpeg";
|
|
104
|
+
const { error } = spawnSync(path);
|
|
105
|
+
if (error) {
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
this.#process = spawn(
|
|
109
|
+
path,
|
|
110
|
+
// See https://trac.ffmpeg.org/wiki/Encode/VP9 for more information on flags.
|
|
111
|
+
[
|
|
112
|
+
["-loglevel", "error"],
|
|
113
|
+
// Reduces general buffering.
|
|
114
|
+
["-avioflags", "direct"],
|
|
115
|
+
// Reduces initial buffering while analyzing input fps and other stats.
|
|
116
|
+
[
|
|
117
|
+
"-fpsprobesize",
|
|
118
|
+
"0",
|
|
119
|
+
"-probesize",
|
|
120
|
+
"32",
|
|
121
|
+
"-analyzeduration",
|
|
122
|
+
"0",
|
|
123
|
+
"-fflags",
|
|
124
|
+
"nobuffer"
|
|
125
|
+
],
|
|
126
|
+
// Forces input to be read from standard input, and forces png input
|
|
127
|
+
// image format.
|
|
128
|
+
["-f", "image2pipe", "-c:v", "png", "-i", "pipe:0"],
|
|
129
|
+
// Overwrite output and no audio.
|
|
130
|
+
["-y", "-an"],
|
|
131
|
+
// This drastically reduces stalling when cpu is overbooked. By default
|
|
132
|
+
// VP9 tries to use all available threads?
|
|
133
|
+
["-threads", "1"],
|
|
134
|
+
// Specifies the frame rate we are giving ffmpeg.
|
|
135
|
+
["-framerate", `${DEFAULT_FPS}`],
|
|
136
|
+
// Specifies the encoding and format we are using.
|
|
137
|
+
this.#getFormatArgs(format ?? "webm"),
|
|
138
|
+
// Disable bitrate.
|
|
139
|
+
["-b:v", "0"],
|
|
140
|
+
// Filters to ensure the images are piped correctly.
|
|
141
|
+
[
|
|
142
|
+
"-vf",
|
|
143
|
+
`${speed ? `setpts=${1 / speed}*PTS,` : ""}crop='min(${width},iw):min(${height},ih):0:0',pad=${width}:${height}:0:0${crop ? `,crop=${crop.width}:${crop.height}:${crop.x}:${crop.y}` : ""}${scale ? `,scale=iw*${scale}:-1` : ""}`
|
|
144
|
+
],
|
|
145
|
+
"pipe:1"
|
|
146
|
+
].flat(),
|
|
147
|
+
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
148
|
+
);
|
|
149
|
+
this.#process.stdout.pipe(this);
|
|
150
|
+
this.#process.stderr.on("data", (data) => {
|
|
151
|
+
debugFfmpeg(data.toString("utf8"));
|
|
152
|
+
});
|
|
153
|
+
this.#page = page;
|
|
154
|
+
const { client } = this.#page.mainFrame();
|
|
155
|
+
client.once(CDPSessionEvent.Disconnected, () => {
|
|
156
|
+
void this.stop().catch(debugError);
|
|
157
|
+
});
|
|
158
|
+
this.#lastFrame = lastValueFrom(fromEmitterEvent(client, "Page.screencastFrame").pipe(tap((event) => {
|
|
159
|
+
void client.send("Page.screencastFrameAck", {
|
|
160
|
+
sessionId: event.sessionId
|
|
161
|
+
});
|
|
162
|
+
}), filter((event) => {
|
|
163
|
+
return event.metadata.timestamp !== void 0;
|
|
164
|
+
}), map((event) => {
|
|
165
|
+
return {
|
|
166
|
+
buffer: Buffer.from(event.data, "base64"),
|
|
167
|
+
timestamp: event.metadata.timestamp
|
|
168
|
+
};
|
|
169
|
+
}), bufferCount(2, 1), concatMap(([{ timestamp: previousTimestamp, buffer }, { timestamp }]) => {
|
|
170
|
+
return from(Array(Math.round(DEFAULT_FPS * Math.max(timestamp - previousTimestamp, 0))).fill(buffer));
|
|
171
|
+
}), map((buffer) => {
|
|
172
|
+
void this.#writeFrame(buffer);
|
|
173
|
+
return [buffer, performance.now()];
|
|
174
|
+
}), takeUntil(fromEvent(this.#controller.signal, "abort"))), { defaultValue: [Buffer.from([]), performance.now()] });
|
|
175
|
+
}
|
|
176
|
+
#getFormatArgs(format) {
|
|
177
|
+
switch (format) {
|
|
178
|
+
case "webm":
|
|
179
|
+
return [
|
|
180
|
+
// Sets the codec to use.
|
|
181
|
+
["-c:v", "vp9"],
|
|
182
|
+
// Sets the format
|
|
183
|
+
["-f", "webm"],
|
|
184
|
+
// Sets the quality. Lower the better.
|
|
185
|
+
["-crf", `${CRF_VALUE}`],
|
|
186
|
+
// Sets the quality and how efficient the compression will be.
|
|
187
|
+
["-deadline", "realtime", "-cpu-used", "8"]
|
|
188
|
+
].flat();
|
|
189
|
+
case "gif":
|
|
190
|
+
return [
|
|
191
|
+
// Sets the frame rate and uses a custom palette generated from the
|
|
192
|
+
// input.
|
|
193
|
+
[
|
|
194
|
+
"-vf",
|
|
195
|
+
"fps=5,split[s0][s1];[s0]palettegen=stats_mode=diff[p];[s1][p]paletteuse"
|
|
196
|
+
],
|
|
197
|
+
// Sets the format
|
|
198
|
+
["-f", "gif"]
|
|
199
|
+
].flat();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
get #writeFrame() {
|
|
203
|
+
return _private_writeFrame_descriptor.value;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Stops the recorder.
|
|
207
|
+
*
|
|
208
|
+
* @public
|
|
209
|
+
*/
|
|
210
|
+
async stop() {
|
|
211
|
+
if (this.#controller.signal.aborted) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
await this.#page._stopScreencast().catch(debugError);
|
|
215
|
+
this.#controller.abort();
|
|
216
|
+
const [buffer, timestamp] = await this.#lastFrame;
|
|
217
|
+
await Promise.all(Array(Math.max(1, Math.round(DEFAULT_FPS * (performance.now() - timestamp) / 1e3))).fill(buffer).map(this.#writeFrame.bind(this)));
|
|
218
|
+
this.#process.stdin.end();
|
|
219
|
+
await new Promise((resolve) => {
|
|
220
|
+
this.#process.once("close", resolve);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* @internal
|
|
225
|
+
*/
|
|
226
|
+
async [(_private_writeFrame_decorators = [guarded()], _stop_decorators = [guarded()], asyncDisposeSymbol)]() {
|
|
227
|
+
await this.stop();
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
})();
|
|
231
|
+
|
|
232
|
+
export {
|
|
233
|
+
ScreenRecorder
|
|
234
|
+
};
|
|
235
|
+
/*! Bundled license information:
|
|
236
|
+
|
|
237
|
+
puppeteer-core/lib/esm/puppeteer/node/ScreenRecorder.js:
|
|
238
|
+
(**
|
|
239
|
+
* @license
|
|
240
|
+
* Copyright 2023 Google Inc.
|
|
241
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
242
|
+
*)
|
|
243
|
+
*/
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// src/commands/scenario/src/process-manager.ts
|
|
2
|
+
var ProcessManager = class {
|
|
3
|
+
processes = /* @__PURE__ */ new Map();
|
|
4
|
+
signalHandlersRegistered = false;
|
|
5
|
+
/**
|
|
6
|
+
* Register a process for tracking
|
|
7
|
+
*/
|
|
8
|
+
registerProcess(runId, pid, type, port) {
|
|
9
|
+
console.log(
|
|
10
|
+
`\u{1F527} [ProcessManager] Registering process ${pid} for runId: ${runId} (type: ${type})`
|
|
11
|
+
);
|
|
12
|
+
this.processes.set(runId, {
|
|
13
|
+
pid,
|
|
14
|
+
runId,
|
|
15
|
+
type,
|
|
16
|
+
startTime: /* @__PURE__ */ new Date(),
|
|
17
|
+
port
|
|
18
|
+
});
|
|
19
|
+
if (!this.signalHandlersRegistered) {
|
|
20
|
+
this.registerSignalHandlers();
|
|
21
|
+
this.signalHandlersRegistered = true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Unregister a process when it completes normally
|
|
26
|
+
*/
|
|
27
|
+
unregisterProcess(runId) {
|
|
28
|
+
const processInfo = this.processes.get(runId);
|
|
29
|
+
if (processInfo) {
|
|
30
|
+
console.log(
|
|
31
|
+
`\u{1F527} [ProcessManager] Unregistering process ${processInfo.pid} for runId: ${runId}`
|
|
32
|
+
);
|
|
33
|
+
this.processes.delete(runId);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get all registered processes
|
|
38
|
+
*/
|
|
39
|
+
getProcesses() {
|
|
40
|
+
return new Map(this.processes);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a process is still running
|
|
44
|
+
*/
|
|
45
|
+
isProcessRunning(pid) {
|
|
46
|
+
try {
|
|
47
|
+
process.kill(pid, 0);
|
|
48
|
+
return true;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Gracefully terminate a specific process
|
|
55
|
+
*/
|
|
56
|
+
async terminateProcess(runId, timeout = 5e3) {
|
|
57
|
+
const processInfo = this.processes.get(runId);
|
|
58
|
+
if (!processInfo) {
|
|
59
|
+
console.log(`\u{1F527} [ProcessManager] No process found for runId: ${runId}`);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
const { pid } = processInfo;
|
|
63
|
+
console.log(`\u{1F527} [ProcessManager] Terminating process ${pid} for runId: ${runId}`);
|
|
64
|
+
if (!this.isProcessRunning(pid)) {
|
|
65
|
+
console.log(`\u{1F527} [ProcessManager] Process ${pid} already terminated`);
|
|
66
|
+
this.unregisterProcess(runId);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
process.kill(pid, "SIGTERM");
|
|
71
|
+
const startTime = Date.now();
|
|
72
|
+
while (Date.now() - startTime < timeout) {
|
|
73
|
+
if (!this.isProcessRunning(pid)) {
|
|
74
|
+
console.log(`\u{1F527} [ProcessManager] Process ${pid} terminated gracefully`);
|
|
75
|
+
this.unregisterProcess(runId);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
79
|
+
}
|
|
80
|
+
console.log(`\u{1F527} [ProcessManager] Force killing process ${pid} after timeout`);
|
|
81
|
+
process.kill(pid, "SIGKILL");
|
|
82
|
+
this.unregisterProcess(runId);
|
|
83
|
+
return true;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.log(`\u{1F527} [ProcessManager] Failed to terminate process ${pid}:`, error);
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Terminate all registered processes
|
|
91
|
+
*/
|
|
92
|
+
async terminateAllProcesses(timeout = 1e4) {
|
|
93
|
+
const processes = Array.from(this.processes.keys());
|
|
94
|
+
console.log(`\u{1F527} [ProcessManager] Terminating ${processes.length} processes`);
|
|
95
|
+
if (processes.length === 0) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const terminationPromises = processes.map(
|
|
99
|
+
(runId) => this.terminateProcess(runId, timeout / processes.length)
|
|
100
|
+
);
|
|
101
|
+
await Promise.allSettled(terminationPromises);
|
|
102
|
+
for (const [runId, processInfo] of this.processes.entries()) {
|
|
103
|
+
if (this.isProcessRunning(processInfo.pid)) {
|
|
104
|
+
console.log(`\u{1F527} [ProcessManager] Force killing remaining process ${processInfo.pid}`);
|
|
105
|
+
try {
|
|
106
|
+
process.kill(processInfo.pid, "SIGKILL");
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.log(`\u{1F527} [ProcessManager] Failed to force kill ${processInfo.pid}:`, error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
this.processes.clear();
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Register signal handlers to cleanup on exit
|
|
116
|
+
*/
|
|
117
|
+
registerSignalHandlers() {
|
|
118
|
+
console.log(`\u{1F527} [ProcessManager] Registering signal handlers`);
|
|
119
|
+
const handleExit = async (signal) => {
|
|
120
|
+
console.log(`\u{1F527} [ProcessManager] Received ${signal}, cleaning up processes...`);
|
|
121
|
+
await this.terminateAllProcesses();
|
|
122
|
+
console.log(`\u{1F527} [ProcessManager] Process cleanup completed`);
|
|
123
|
+
process.exit(0);
|
|
124
|
+
};
|
|
125
|
+
process.on("SIGINT", () => handleExit("SIGINT"));
|
|
126
|
+
process.on("SIGTERM", () => handleExit("SIGTERM"));
|
|
127
|
+
process.on("SIGUSR1", () => handleExit("SIGUSR1"));
|
|
128
|
+
process.on("SIGUSR2", () => handleExit("SIGUSR2"));
|
|
129
|
+
process.on("uncaughtException", async (error) => {
|
|
130
|
+
console.error(`\u{1F527} [ProcessManager] Uncaught exception:`, error);
|
|
131
|
+
await this.terminateAllProcesses();
|
|
132
|
+
process.exit(1);
|
|
133
|
+
});
|
|
134
|
+
process.on("unhandledRejection", async (reason, promise) => {
|
|
135
|
+
console.error(`\u{1F527} [ProcessManager] Unhandled rejection at:`, promise, "reason:", reason);
|
|
136
|
+
await this.terminateAllProcesses();
|
|
137
|
+
process.exit(1);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get summary of managed processes
|
|
142
|
+
*/
|
|
143
|
+
getSummary() {
|
|
144
|
+
const processes = Array.from(this.processes.values());
|
|
145
|
+
const byType = {};
|
|
146
|
+
let oldestProcess;
|
|
147
|
+
for (const proc of processes) {
|
|
148
|
+
byType[proc.type] = (byType[proc.type] || 0) + 1;
|
|
149
|
+
if (!oldestProcess || proc.startTime < oldestProcess.startTime) {
|
|
150
|
+
oldestProcess = proc;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
total: processes.length,
|
|
155
|
+
byType,
|
|
156
|
+
oldestProcess
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
var processManager = new ProcessManager();
|
|
161
|
+
|
|
162
|
+
export {
|
|
163
|
+
ProcessManager,
|
|
164
|
+
processManager
|
|
165
|
+
};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// src/commands/scenario/src/run-isolation.ts
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
var runSequence = 0;
|
|
6
|
+
function resetRunSequence() {
|
|
7
|
+
runSequence = 0;
|
|
8
|
+
}
|
|
9
|
+
function generateRunId() {
|
|
10
|
+
const sequence = String(runSequence++).padStart(3, "0");
|
|
11
|
+
const hash = Math.random().toString(16).substring(2, 10);
|
|
12
|
+
return `run-${sequence}-${hash}`;
|
|
13
|
+
}
|
|
14
|
+
async function createIsolatedEnvironment(runId, outputDir) {
|
|
15
|
+
const tempDir = join(outputDir, "temp", runId);
|
|
16
|
+
await fs.mkdir(tempDir, { recursive: true });
|
|
17
|
+
const dbPath = join(tempDir, "database");
|
|
18
|
+
const logsDir = join(tempDir, "logs");
|
|
19
|
+
const logPath = join(logsDir, "run.log");
|
|
20
|
+
const scenarioPath = join(tempDir, "scenario.yaml");
|
|
21
|
+
await fs.mkdir(dirname(logPath), { recursive: true });
|
|
22
|
+
await fs.mkdir(dbPath, { recursive: true });
|
|
23
|
+
const cleanup = async () => {
|
|
24
|
+
await cleanupIsolatedEnvironment({
|
|
25
|
+
runId,
|
|
26
|
+
tempDir,
|
|
27
|
+
dbPath,
|
|
28
|
+
logPath,
|
|
29
|
+
scenarioPath,
|
|
30
|
+
cleanup: () => Promise.resolve()
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
runId,
|
|
35
|
+
tempDir,
|
|
36
|
+
dbPath,
|
|
37
|
+
logPath,
|
|
38
|
+
scenarioPath,
|
|
39
|
+
cleanup
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function cleanupIsolatedEnvironment(context) {
|
|
43
|
+
try {
|
|
44
|
+
await fs.rm(context.tempDir, { recursive: true, force: true });
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.warn(`Warning: Failed to cleanup isolated environment ${context.runId}:`, error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function ensureIsolatedDatabase(dbPath) {
|
|
50
|
+
try {
|
|
51
|
+
await fs.mkdir(dbPath, { recursive: true });
|
|
52
|
+
const dbConfig = {
|
|
53
|
+
type: "pglite",
|
|
54
|
+
path: dbPath,
|
|
55
|
+
isolated: true,
|
|
56
|
+
temporary: true
|
|
57
|
+
};
|
|
58
|
+
const configPath = join(dbPath, "config.json");
|
|
59
|
+
await fs.writeFile(configPath, JSON.stringify(dbConfig, null, 2));
|
|
60
|
+
} catch (error) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Failed to setup isolated database: ${error instanceof Error ? error.message : String(error)}`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function writeTemporaryScenario(scenarioPath, baseScenario, parameters) {
|
|
67
|
+
try {
|
|
68
|
+
const modifiedScenario = JSON.parse(JSON.stringify(baseScenario));
|
|
69
|
+
for (const [path, value] of Object.entries(parameters)) {
|
|
70
|
+
setNestedProperty(modifiedScenario, path, value);
|
|
71
|
+
}
|
|
72
|
+
await fs.writeFile(scenarioPath, JSON.stringify(modifiedScenario, null, 2));
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Failed to write temporary scenario: ${error instanceof Error ? error.message : String(error)}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function setNestedProperty(obj, path, value) {
|
|
80
|
+
const keys = path.split(".");
|
|
81
|
+
let current = obj;
|
|
82
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
83
|
+
const key = keys[i];
|
|
84
|
+
const arrayMatch2 = key.match(/^(.+)\[(\d+)\]$/);
|
|
85
|
+
if (arrayMatch2) {
|
|
86
|
+
const [, arrayKey, indexStr] = arrayMatch2;
|
|
87
|
+
const index = parseInt(indexStr, 10);
|
|
88
|
+
if (!current[arrayKey]) {
|
|
89
|
+
current[arrayKey] = [];
|
|
90
|
+
}
|
|
91
|
+
if (!current[arrayKey][index]) {
|
|
92
|
+
current[arrayKey][index] = {};
|
|
93
|
+
}
|
|
94
|
+
current = current[arrayKey][index];
|
|
95
|
+
} else {
|
|
96
|
+
if (!current[key]) {
|
|
97
|
+
current[key] = {};
|
|
98
|
+
}
|
|
99
|
+
current = current[key];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const finalKey = keys[keys.length - 1];
|
|
103
|
+
const arrayMatch = finalKey.match(/^(.+)\[(\d+)\]$/);
|
|
104
|
+
if (arrayMatch) {
|
|
105
|
+
const [, arrayKey, indexStr] = arrayMatch;
|
|
106
|
+
const index = parseInt(indexStr, 10);
|
|
107
|
+
if (!current[arrayKey]) {
|
|
108
|
+
current[arrayKey] = [];
|
|
109
|
+
}
|
|
110
|
+
current[arrayKey][index] = value;
|
|
111
|
+
} else {
|
|
112
|
+
current[finalKey] = value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function validateIsolationContext(context) {
|
|
116
|
+
try {
|
|
117
|
+
const tempDirExists = await fs.access(context.tempDir).then(() => true).catch(() => false);
|
|
118
|
+
const dbDirExists = await fs.access(context.dbPath).then(() => true).catch(() => false);
|
|
119
|
+
const logDirExists = await fs.access(dirname(context.logPath)).then(() => true).catch(() => false);
|
|
120
|
+
return tempDirExists && dbDirExists && logDirExists;
|
|
121
|
+
} catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function createIsolatedEnvironmentVariables(context) {
|
|
126
|
+
const baseEnv = { ...process.env };
|
|
127
|
+
const isolatedEnv = {
|
|
128
|
+
...baseEnv,
|
|
129
|
+
// Point to isolated database
|
|
130
|
+
DATABASE_URL: `file://${context.dbPath}/database.db`,
|
|
131
|
+
PGLITE_DATABASE_PATH: context.dbPath,
|
|
132
|
+
// Set isolated temp directory
|
|
133
|
+
TMPDIR: context.tempDir,
|
|
134
|
+
TEMP: context.tempDir,
|
|
135
|
+
TMP: context.tempDir,
|
|
136
|
+
// Set log configuration
|
|
137
|
+
LOG_FILE: context.logPath,
|
|
138
|
+
LOG_LEVEL: "debug",
|
|
139
|
+
// Mark as isolated execution
|
|
140
|
+
ELIZA_ISOLATED_RUN: "true",
|
|
141
|
+
ELIZA_RUN_ID: context.runId,
|
|
142
|
+
// Disable any global state or caching
|
|
143
|
+
DISABLE_GLOBAL_CACHE: "true",
|
|
144
|
+
FORCE_ISOLATED_MODE: "true"
|
|
145
|
+
};
|
|
146
|
+
return isolatedEnv;
|
|
147
|
+
}
|
|
148
|
+
function getIsolatedTempDir(prefix = "eliza-matrix") {
|
|
149
|
+
const timestamp = Date.now();
|
|
150
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
151
|
+
return join(tmpdir(), `${prefix}-${timestamp}-${random}`);
|
|
152
|
+
}
|
|
153
|
+
function estimateRunDiskSpace(baseScenario) {
|
|
154
|
+
const baseSize = 50 * 1024 * 1024;
|
|
155
|
+
const runCount = baseScenario.run?.length || 1;
|
|
156
|
+
const evaluationCount = baseScenario.run?.reduce((sum, run) => sum + (run.evaluations?.length || 0), 0) || 0;
|
|
157
|
+
const complexityMultiplier = 1 + runCount * 0.1 + evaluationCount * 0.05;
|
|
158
|
+
return Math.ceil(baseSize * complexityMultiplier);
|
|
159
|
+
}
|
|
160
|
+
async function checkDiskSpace(outputDir, estimatedSpace) {
|
|
161
|
+
try {
|
|
162
|
+
const stats = await fs.stat(outputDir);
|
|
163
|
+
return true;
|
|
164
|
+
} catch {
|
|
165
|
+
try {
|
|
166
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
167
|
+
return true;
|
|
168
|
+
} catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function monitorIsolatedResources(context) {
|
|
174
|
+
try {
|
|
175
|
+
let totalSize = 0;
|
|
176
|
+
let fileCount = 0;
|
|
177
|
+
async function calculateSize(dirPath) {
|
|
178
|
+
try {
|
|
179
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
180
|
+
for (const entry of entries) {
|
|
181
|
+
const fullPath = join(dirPath, entry.name);
|
|
182
|
+
if (entry.isDirectory()) {
|
|
183
|
+
await calculateSize(fullPath);
|
|
184
|
+
} else {
|
|
185
|
+
const stats = await fs.stat(fullPath);
|
|
186
|
+
totalSize += stats.size;
|
|
187
|
+
fileCount++;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
await calculateSize(context.tempDir);
|
|
194
|
+
return {
|
|
195
|
+
diskUsage: totalSize,
|
|
196
|
+
fileCount,
|
|
197
|
+
directorySize: totalSize
|
|
198
|
+
};
|
|
199
|
+
} catch {
|
|
200
|
+
return {
|
|
201
|
+
diskUsage: 0,
|
|
202
|
+
fileCount: 0,
|
|
203
|
+
directorySize: 0
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export {
|
|
209
|
+
resetRunSequence,
|
|
210
|
+
generateRunId,
|
|
211
|
+
createIsolatedEnvironment,
|
|
212
|
+
cleanupIsolatedEnvironment,
|
|
213
|
+
ensureIsolatedDatabase,
|
|
214
|
+
writeTemporaryScenario,
|
|
215
|
+
validateIsolationContext,
|
|
216
|
+
createIsolatedEnvironmentVariables,
|
|
217
|
+
getIsolatedTempDir,
|
|
218
|
+
estimateRunDiskSpace,
|
|
219
|
+
checkDiskSpace,
|
|
220
|
+
monitorIsolatedResources
|
|
221
|
+
};
|