@toolforge-js/sdk 0.8.6 → 0.8.8
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/{tool-BHVNhWPh.js → agent-DzYymaXh.js} +141 -108
- package/dist/cli/index.js +435 -196
- package/dist/components/index.d.ts +43 -59
- package/dist/components/index.js +1 -1
- package/package.json +3 -2
package/dist/cli/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as __require, S as __commonJS, _ as initCommunicationMessageSchema, a as TOOL_TAG_NAME, b as stopAgentMessageSchema, c as sessionIdStore, d as invariant, f as exponentialBackoff, g as heartbeatAckMessageSchema, h as baseMessageSchema, i as TOOL_HANDLER_TAG_NAME, l as convertToWords, m as ackMessageSchema, n as AGENT_TAG_NAME, o as Tool, p as runWithRetries, r as Agent, s as runnerIdStore, t as AGENT_STEP_TAG_NAME, u as getErrorMessage, v as startAgentMessageSchema, w as __toESM, x as stopToolMessageSchema, y as startToolMessageSchema } from "../agent-DzYymaXh.js";
|
|
2
2
|
import { a as sdkServerUrlSchema, n as appServerUrlSchema, o as toolForgeConfigSchema, r as appUrlSchema } from "../config-schema-Bb9oY-Ku.js";
|
|
3
|
+
import * as z$1 from "zod";
|
|
4
|
+
import z from "zod";
|
|
5
|
+
import { P, match } from "ts-pattern";
|
|
6
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
7
|
+
import { nanoid } from "nanoid";
|
|
3
8
|
import { createReadStream, readFileSync } from "node:fs";
|
|
4
9
|
import * as path from "node:path";
|
|
5
10
|
import { EventEmitter } from "node:events";
|
|
6
|
-
import * as z$1 from "zod";
|
|
7
|
-
import z from "zod";
|
|
8
11
|
import ora from "ora";
|
|
9
12
|
import { pino } from "pino";
|
|
10
13
|
import * as crypto from "node:crypto";
|
|
@@ -13,14 +16,12 @@ import { create } from "tar";
|
|
|
13
16
|
import * as os from "node:os";
|
|
14
17
|
import { camelCase, capitalize, kebabCase } from "es-toolkit/string";
|
|
15
18
|
import esbuild from "esbuild";
|
|
16
|
-
import { nanoid } from "nanoid";
|
|
17
|
-
import { P, match } from "ts-pattern";
|
|
18
|
-
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
19
19
|
import * as prompts from "@clack/prompts";
|
|
20
20
|
import picocolors from "picocolors";
|
|
21
21
|
import { createAuthClient } from "better-auth/client";
|
|
22
22
|
import { deviceAuthorizationClient } from "better-auth/client/plugins";
|
|
23
23
|
import chokidar from "chokidar";
|
|
24
|
+
import * as util from "node:util";
|
|
24
25
|
|
|
25
26
|
//#region ../../node_modules/.bun/commander@14.0.2/node_modules/commander/lib/error.js
|
|
26
27
|
var require_error = /* @__PURE__ */ __commonJS({ "../../node_modules/.bun/commander@14.0.2/node_modules/commander/lib/error.js": ((exports) => {
|
|
@@ -3227,7 +3228,8 @@ ${agentEntries.map(({ variableName, id }) => ` '${id}': agent_${variableName},`
|
|
|
3227
3228
|
"// @ts-nocheck",
|
|
3228
3229
|
"// noinspection JSUnusedGlobalSymbols",
|
|
3229
3230
|
"// This file is auto-generated by ToolForge. Do not edit manually."
|
|
3230
|
-
].join("\n\n") }
|
|
3231
|
+
].join("\n\n") },
|
|
3232
|
+
external: ["@toolforge-js/sdk/components", "@toolforge-js/sdk/config"]
|
|
3231
3233
|
});
|
|
3232
3234
|
logger.debug("esbuild bundling completed");
|
|
3233
3235
|
return {
|
|
@@ -3279,7 +3281,7 @@ function getMemoryUsage() {
|
|
|
3279
3281
|
}
|
|
3280
3282
|
|
|
3281
3283
|
//#endregion
|
|
3282
|
-
//#region src/cli/
|
|
3284
|
+
//#region src/cli/lib/utils.ts
|
|
3283
3285
|
async function getToolForgeConfig(configRelPath) {
|
|
3284
3286
|
try {
|
|
3285
3287
|
const configPath = path.resolve(process.cwd(), configRelPath);
|
|
@@ -3529,11 +3531,15 @@ async function deploy(configRelPath, debug) {
|
|
|
3529
3531
|
prompts.outro(getErrorMessage(error));
|
|
3530
3532
|
process.exit(1);
|
|
3531
3533
|
});
|
|
3534
|
+
if (environments.length === 0) {
|
|
3535
|
+
prompts.outro("No production environment found. Please create a production environment in your workspace. Learn more at https://docs.tool-forge.ai/concepts/environment#production-environment");
|
|
3536
|
+
process.exit(0);
|
|
3537
|
+
}
|
|
3532
3538
|
const environmentSelect = await prompts.select({
|
|
3533
3539
|
message: "Select the production environment to deploy to:",
|
|
3534
|
-
options: environments.map((env) => ({
|
|
3535
|
-
label: `${env.environmentName} (Workspace: ${env.workspaceName})`,
|
|
3536
|
-
value: env.id
|
|
3540
|
+
options: environments.map((env$1) => ({
|
|
3541
|
+
label: `${env$1.environmentName} (Workspace: ${env$1.workspaceName})`,
|
|
3542
|
+
value: env$1.id
|
|
3537
3543
|
}))
|
|
3538
3544
|
});
|
|
3539
3545
|
if (prompts.isCancel(environmentSelect)) {
|
|
@@ -3568,7 +3574,7 @@ async function deploy(configRelPath, debug) {
|
|
|
3568
3574
|
process.exit(1);
|
|
3569
3575
|
});
|
|
3570
3576
|
const deploySpinner = prompts.spinner();
|
|
3571
|
-
const environmentName = environments.find((env) => env.id === environmentSelect)?.environmentName;
|
|
3577
|
+
const environmentName = environments.find((env$1) => env$1.id === environmentSelect)?.environmentName;
|
|
3572
3578
|
deploySpinner.start(`Deploying tools to ${environmentName}...`);
|
|
3573
3579
|
const formData = new FormData();
|
|
3574
3580
|
formData.append("bundle", new File([await Bun.file(tarballPath).arrayBuffer()], path.basename(tarballPath), { type: "application/gzip" }));
|
|
@@ -3698,15 +3704,13 @@ const TOKEN_PREFIX = "tf_token--";
|
|
|
3698
3704
|
//#endregion
|
|
3699
3705
|
//#region src/internal/websocket-client.ts
|
|
3700
3706
|
const optionsSchema$1 = z$1.object({
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
retryBackoffMultiplier: z$1.number().min(1).optional().default(2)
|
|
3709
|
-
});
|
|
3707
|
+
apiKey: z$1.string().refine((val) => val.startsWith("sk_live") || val.startsWith("pk_test") || val.startsWith(TOKEN_PREFIX)),
|
|
3708
|
+
tokenProviderEndpoint: z$1.url().optional(),
|
|
3709
|
+
sdkServerUrl: z$1.url()
|
|
3710
|
+
}).refine((val) => {
|
|
3711
|
+
if (val.apiKey.startsWith(TOKEN_PREFIX) && !val.tokenProviderEndpoint) return false;
|
|
3712
|
+
return true;
|
|
3713
|
+
}, "tokenProviderEndpoint must be present for short term apiKey");
|
|
3710
3714
|
const WS_ERROR_CODES = {
|
|
3711
3715
|
NORMAL_CLOSURE: 1e3,
|
|
3712
3716
|
GOING_AWAY: 1001,
|
|
@@ -3725,8 +3729,18 @@ const WEB_SOCKET_CLIENT_EVENTS = {
|
|
|
3725
3729
|
COMMUNICATION_INITIALIZED: "COMMUNICATION_INITIALIZED",
|
|
3726
3730
|
STOPPED: "STOPPED"
|
|
3727
3731
|
};
|
|
3732
|
+
const MAX_ACK_WAIT_MS = 1e4;
|
|
3733
|
+
const MAX_RETRIES = 100;
|
|
3734
|
+
const RETRY_DELAY_MS = 1e3;
|
|
3735
|
+
const MAX_RETRY_DELAY_MS = 3e4;
|
|
3736
|
+
const RETRY_JITTER_FACTOR = .5;
|
|
3737
|
+
const RETRY_BACKOFF_MULTIPLIER = 2;
|
|
3728
3738
|
var WebSocketClient = class extends EventEmitter {
|
|
3729
3739
|
#options;
|
|
3740
|
+
#runnerId;
|
|
3741
|
+
#apiKey;
|
|
3742
|
+
#refreshApiKeyInterval;
|
|
3743
|
+
#serverUrl;
|
|
3730
3744
|
#forgeRunner;
|
|
3731
3745
|
#logger;
|
|
3732
3746
|
#connectionState = "disconnected";
|
|
@@ -3741,13 +3755,25 @@ var WebSocketClient = class extends EventEmitter {
|
|
|
3741
3755
|
#pendingMessagesBuffer = [];
|
|
3742
3756
|
#subscribeCallbacks = [];
|
|
3743
3757
|
constructor(options, forgeRunner, logger) {
|
|
3744
|
-
super();
|
|
3758
|
+
super({ captureRejections: true });
|
|
3745
3759
|
this.#options = optionsSchema$1.parse(options);
|
|
3746
3760
|
this.#forgeRunner = forgeRunner;
|
|
3747
|
-
|
|
3748
|
-
|
|
3761
|
+
const runnerId = runnerIdStore.getStore();
|
|
3762
|
+
if (!runnerId) throw new Error("runnerId not found");
|
|
3763
|
+
this.#runnerId = runnerId;
|
|
3764
|
+
this.#logger = logger.child({
|
|
3765
|
+
runnerId: this.#runnerId,
|
|
3766
|
+
component: "WebSocketClient"
|
|
3767
|
+
});
|
|
3768
|
+
this.#apiKey = this.#options.apiKey;
|
|
3769
|
+
const url = new URL("/socket", this.#options.sdkServerUrl);
|
|
3770
|
+
url.searchParams.set("apiKey", this.#apiKey);
|
|
3771
|
+
url.searchParams.set("runnerId", runnerId);
|
|
3772
|
+
this.#serverUrl = url;
|
|
3773
|
+
if (this.#apiKey.startsWith(TOKEN_PREFIX)) this.#refreshApiKeyInterval = setInterval(this.#refreshApiKey.bind(this), 840 * 1e3);
|
|
3774
|
+
this.#connect();
|
|
3749
3775
|
}
|
|
3750
|
-
#
|
|
3776
|
+
#connect() {
|
|
3751
3777
|
if (this.#connectionState === "closing") {
|
|
3752
3778
|
this.#logger.warn("start called while closing, ignoring");
|
|
3753
3779
|
return;
|
|
@@ -3757,8 +3783,8 @@ var WebSocketClient = class extends EventEmitter {
|
|
|
3757
3783
|
return;
|
|
3758
3784
|
}
|
|
3759
3785
|
this.#connectionState = "connecting";
|
|
3760
|
-
this.#logger.info("connecting to SDK server at %s", this.#options.
|
|
3761
|
-
this.#socket = new WebSocket(this.#
|
|
3786
|
+
this.#logger.info("connecting to SDK server at %s", this.#options.sdkServerUrl.toString());
|
|
3787
|
+
this.#socket = new WebSocket(this.#serverUrl);
|
|
3762
3788
|
this.#socket.addEventListener("open", this.#handleWebSocketOpen.bind(this));
|
|
3763
3789
|
this.#socket.addEventListener("close", this.#handleWebSocketClose.bind(this));
|
|
3764
3790
|
this.#socket.addEventListener("message", this.#handleWebSocketMessage.bind(this));
|
|
@@ -3773,34 +3799,57 @@ var WebSocketClient = class extends EventEmitter {
|
|
|
3773
3799
|
}
|
|
3774
3800
|
}
|
|
3775
3801
|
#handleWebSocketClose(event) {
|
|
3776
|
-
this.#connectionState
|
|
3802
|
+
if (this.#connectionState === "closing") return;
|
|
3777
3803
|
this.#logger.debug({
|
|
3778
3804
|
code: event.code,
|
|
3779
3805
|
reason: event.reason
|
|
3780
3806
|
}, "disconnected from SDK server");
|
|
3781
|
-
if (event.code === WS_ERROR_CODES.
|
|
3807
|
+
if (event.code === WS_ERROR_CODES.INVALID_FRAME_PAYLOAD_DATA && !this.#apiKey.startsWith(TOKEN_PREFIX)) {
|
|
3782
3808
|
this.#logger.error("authentication failed, exiting");
|
|
3809
|
+
this.#connectionState = "closing";
|
|
3810
|
+
this.#reset();
|
|
3783
3811
|
this.emit("error", /* @__PURE__ */ new Error("authentication failed"));
|
|
3784
3812
|
return;
|
|
3785
3813
|
}
|
|
3786
|
-
this.#
|
|
3814
|
+
this.#connectionState = "disconnected";
|
|
3815
|
+
this.#reset();
|
|
3787
3816
|
this.#retryConnect();
|
|
3788
3817
|
}
|
|
3789
3818
|
async #retryConnect() {
|
|
3790
|
-
if (this.#retryCount >=
|
|
3819
|
+
if (this.#retryCount >= MAX_RETRIES) {
|
|
3791
3820
|
this.#logger.error("max retries exceeded, exiting");
|
|
3792
3821
|
this.emit("error", /* @__PURE__ */ new Error("max retries exceeded"));
|
|
3793
3822
|
return;
|
|
3794
3823
|
}
|
|
3795
3824
|
this.#retryCount += 1;
|
|
3796
|
-
const delay = exponentialBackoff(this.#retryCount - 1,
|
|
3825
|
+
const delay = exponentialBackoff(this.#retryCount - 1, RETRY_DELAY_MS, MAX_RETRY_DELAY_MS, RETRY_JITTER_FACTOR, RETRY_BACKOFF_MULTIPLIER);
|
|
3797
3826
|
this.#logger.debug({
|
|
3798
3827
|
delay,
|
|
3799
|
-
url: this.#options.
|
|
3828
|
+
url: this.#options.sdkServerUrl,
|
|
3800
3829
|
attempt: this.#retryCount
|
|
3801
3830
|
}, "retrying connection to server");
|
|
3802
3831
|
await setTimeout$1(delay);
|
|
3803
|
-
this.#
|
|
3832
|
+
await this.#refreshApiKey();
|
|
3833
|
+
this.#connect();
|
|
3834
|
+
}
|
|
3835
|
+
async #refreshApiKey() {
|
|
3836
|
+
if (!this.#options.tokenProviderEndpoint) return;
|
|
3837
|
+
this.#apiKey = await fetch(new URL("/token/refresh", this.#options.tokenProviderEndpoint), {
|
|
3838
|
+
method: "POST",
|
|
3839
|
+
headers: { "Content-Type": "application/json" },
|
|
3840
|
+
body: JSON.stringify({ token: this.#apiKey })
|
|
3841
|
+
}).then((res) => {
|
|
3842
|
+
if (!res.ok) throw new Error(`failed to refresh token: ${res.status} ${res.statusText}`);
|
|
3843
|
+
return res.json();
|
|
3844
|
+
}).then((data) => {
|
|
3845
|
+
const result = z$1.object({ token: z$1.string().startsWith(TOKEN_PREFIX) }).safeParse(data);
|
|
3846
|
+
if (!result.success) throw new Error("invalid response from token refresh");
|
|
3847
|
+
return result.data.token;
|
|
3848
|
+
}).catch((error) => {
|
|
3849
|
+
this.emit("error", error);
|
|
3850
|
+
throw error;
|
|
3851
|
+
});
|
|
3852
|
+
this.#logger.info("successfully refreshed API token");
|
|
3804
3853
|
}
|
|
3805
3854
|
async #handleWebSocketMessage(event) {
|
|
3806
3855
|
const data = event.data;
|
|
@@ -3867,43 +3916,49 @@ var WebSocketClient = class extends EventEmitter {
|
|
|
3867
3916
|
if (this.#heartbeatTimeout) clearTimeout(this.#heartbeatTimeout);
|
|
3868
3917
|
const socket = this.#socket;
|
|
3869
3918
|
invariant(socket, "socket should be present");
|
|
3870
|
-
this.#heartbeatInterval = setInterval(()
|
|
3871
|
-
socket.send(JSON.stringify({
|
|
3872
|
-
id: nanoid(),
|
|
3873
|
-
type: "HEARTBEAT",
|
|
3874
|
-
timestamp: Date.now(),
|
|
3875
|
-
data: {
|
|
3876
|
-
clientType: "RUNNER",
|
|
3877
|
-
cpuUsage: getCPUUsage().usage,
|
|
3878
|
-
memoryUsage: getMemoryUsage().usage,
|
|
3879
|
-
runnerId: this.#options.runnerId,
|
|
3880
|
-
activeSessionsCount: this.#forgeRunner.activeSessionsCount
|
|
3881
|
-
}
|
|
3882
|
-
}));
|
|
3883
|
-
}, this.#heartbeatIntervalMs);
|
|
3919
|
+
this.#heartbeatInterval = setInterval(this.#sendHeartbeat.bind(this), this.#heartbeatIntervalMs);
|
|
3884
3920
|
this.#heartbeatTimeout = setTimeout(this.#handleHeartbeatAckMiss.bind(this), this.#heartbeatAckTimeoutMs);
|
|
3885
3921
|
this.emit(WEB_SOCKET_CLIENT_EVENTS.COMMUNICATION_INITIALIZED);
|
|
3886
3922
|
}
|
|
3923
|
+
#sendHeartbeat() {
|
|
3924
|
+
if (this.#socket && this.#socket.readyState === WebSocket.OPEN) this.#socket.send(JSON.stringify({
|
|
3925
|
+
id: nanoid(),
|
|
3926
|
+
type: "HEARTBEAT",
|
|
3927
|
+
timestamp: Date.now(),
|
|
3928
|
+
data: {
|
|
3929
|
+
clientType: "RUNNER",
|
|
3930
|
+
cpuUsage: getCPUUsage().usage,
|
|
3931
|
+
memoryUsage: getMemoryUsage().usage,
|
|
3932
|
+
runnerId: this.#runnerId,
|
|
3933
|
+
activeSessionsCount: this.#forgeRunner.activeSessionsCount
|
|
3934
|
+
}
|
|
3935
|
+
}));
|
|
3936
|
+
}
|
|
3887
3937
|
#handleHeartbeatAck(message) {
|
|
3888
3938
|
if (message.data.clientType !== "RUNNER") {
|
|
3889
3939
|
this.#logger.warn("received heartbeat ack from non-runner client, ignoring");
|
|
3890
3940
|
return;
|
|
3891
3941
|
}
|
|
3892
|
-
if (message.data.runnerId !== this.#
|
|
3942
|
+
if (message.data.runnerId !== this.#runnerId || message.data.serverId !== this.#connectedServerId) {
|
|
3893
3943
|
this.#logger.warn("received heartbeat ack for different runner or server, ignoring");
|
|
3894
|
-
this.#
|
|
3895
|
-
|
|
3944
|
+
if (this.#socket && this.#socket.readyState === this.#socket.OPEN) this.#socket.close(WS_ERROR_CODES.GOING_AWAY, "received heartbeat ack for different server or runner");
|
|
3945
|
+
else {
|
|
3946
|
+
this.#connectionState = "disconnected";
|
|
3947
|
+
this.#reset();
|
|
3948
|
+
this.#retryConnect();
|
|
3949
|
+
}
|
|
3896
3950
|
return;
|
|
3897
3951
|
}
|
|
3898
3952
|
const latency = Date.now() - message.timestamp;
|
|
3899
3953
|
this.#logger.debug({ latency }, "heartbeat acknowledged");
|
|
3900
3954
|
if (this.#heartbeatTimeout) clearTimeout(this.#heartbeatTimeout);
|
|
3901
|
-
invariant(this.#heartbeatAckTimeoutMs, "heartbeat interval should be set");
|
|
3902
3955
|
this.#heartbeatTimeout = setTimeout(this.#handleHeartbeatAckMiss.bind(this), this.#heartbeatAckTimeoutMs);
|
|
3903
3956
|
}
|
|
3904
3957
|
#handleHeartbeatAckMiss() {
|
|
3905
3958
|
this.#logger.error("heartbeat timeout, disconnecting");
|
|
3906
|
-
this.#
|
|
3959
|
+
this.#connectionState = "closing";
|
|
3960
|
+
if (this.#socket && this.#socket.readyState === this.#socket.OPEN) this.#socket.close(WS_ERROR_CODES.GOING_AWAY, "heartbeat timeout");
|
|
3961
|
+
this.#reset();
|
|
3907
3962
|
this.emit("error", /* @__PURE__ */ new Error("heartbeat timeout"));
|
|
3908
3963
|
}
|
|
3909
3964
|
#handleServerAckMessage(message) {
|
|
@@ -3922,7 +3977,7 @@ var WebSocketClient = class extends EventEmitter {
|
|
|
3922
3977
|
const timeout = setTimeout(() => {
|
|
3923
3978
|
this.#pendingServerAcks.delete(message.id);
|
|
3924
3979
|
reject(/* @__PURE__ */ new Error("acknowledgement timeout"));
|
|
3925
|
-
},
|
|
3980
|
+
}, MAX_ACK_WAIT_MS);
|
|
3926
3981
|
this.#pendingServerAcks.set(id, {
|
|
3927
3982
|
resolve: () => {
|
|
3928
3983
|
clearTimeout(timeout);
|
|
@@ -3965,27 +4020,32 @@ var WebSocketClient = class extends EventEmitter {
|
|
|
3965
4020
|
this.#subscribeCallbacks = this.#subscribeCallbacks.filter((cb) => cb !== callback);
|
|
3966
4021
|
};
|
|
3967
4022
|
}
|
|
3968
|
-
#
|
|
3969
|
-
if (this.#
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
this.#
|
|
4023
|
+
#reset() {
|
|
4024
|
+
if (this.#refreshApiKeyInterval) {
|
|
4025
|
+
clearInterval(this.#refreshApiKeyInterval);
|
|
4026
|
+
this.#refreshApiKeyInterval = void 0;
|
|
4027
|
+
this.#logger.info("token refresh interval cleared");
|
|
4028
|
+
}
|
|
4029
|
+
if (this.#socket) {
|
|
3973
4030
|
this.#socket.removeEventListener("open", this.#handleWebSocketOpen.bind(this));
|
|
3974
4031
|
this.#socket.removeEventListener("close", this.#handleWebSocketClose.bind(this));
|
|
3975
4032
|
this.#socket.removeEventListener("message", this.#handleWebSocketMessage.bind(this));
|
|
3976
4033
|
this.#socket = void 0;
|
|
3977
4034
|
}
|
|
4035
|
+
if (this.#heartbeatInterval) clearInterval(this.#heartbeatInterval);
|
|
4036
|
+
if (this.#heartbeatTimeout) clearTimeout(this.#heartbeatTimeout);
|
|
3978
4037
|
this.#heartbeatAckTimeoutMs = void 0;
|
|
3979
4038
|
this.#heartbeatIntervalMs = void 0;
|
|
3980
4039
|
this.#connectedServerId = void 0;
|
|
3981
4040
|
this.emit(WEB_SOCKET_CLIENT_EVENTS.STOPPED);
|
|
3982
4041
|
}
|
|
3983
4042
|
stop() {
|
|
3984
|
-
this.#logger.info("gracefully stopping
|
|
4043
|
+
this.#logger.info("gracefully stopping websocket client...");
|
|
3985
4044
|
this.#connectionState = "closing";
|
|
3986
|
-
this.#stop();
|
|
3987
4045
|
this.#retryCount = 0;
|
|
3988
|
-
this.#
|
|
4046
|
+
if (this.#socket && this.#socket.readyState === WebSocket.OPEN) this.#socket.close(WS_ERROR_CODES.GOING_AWAY, "stopping forge runner");
|
|
4047
|
+
this.#reset();
|
|
4048
|
+
this.#logger.info("websocket client stopped");
|
|
3989
4049
|
}
|
|
3990
4050
|
};
|
|
3991
4051
|
|
|
@@ -4014,12 +4074,9 @@ const optionsSchema = z$1.object({
|
|
|
4014
4074
|
* spawns Tool instances, and handles file system changes to reload tools in development mode.
|
|
4015
4075
|
*/
|
|
4016
4076
|
var ForgeRunner = class extends EventEmitter {
|
|
4017
|
-
#
|
|
4077
|
+
#runnerId;
|
|
4018
4078
|
#options;
|
|
4019
4079
|
#logger;
|
|
4020
|
-
#apiKey;
|
|
4021
|
-
#sdkServerUrl;
|
|
4022
|
-
#refreshApiKeyInterval;
|
|
4023
4080
|
#forgeItems = [];
|
|
4024
4081
|
#tools = {};
|
|
4025
4082
|
#agents = {};
|
|
@@ -4030,24 +4087,24 @@ var ForgeRunner = class extends EventEmitter {
|
|
|
4030
4087
|
#sessionAgents = /* @__PURE__ */ new Map();
|
|
4031
4088
|
constructor(options, logger) {
|
|
4032
4089
|
super({ captureRejections: true });
|
|
4090
|
+
const runnerId = runnerIdStore.getStore();
|
|
4091
|
+
if (!runnerId) throw new Error("runnerId not available");
|
|
4092
|
+
this.#runnerId = runnerId;
|
|
4033
4093
|
this.#options = optionsSchema.parse(options);
|
|
4034
|
-
this.#logger = logger.child({
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
url.searchParams.set("apiKey", this.#apiKey);
|
|
4039
|
-
url.searchParams.set("runnerId", this.#id);
|
|
4040
|
-
url.pathname = "/socket";
|
|
4041
|
-
this.#sdkServerUrl = url.toString();
|
|
4094
|
+
this.#logger = logger.child({
|
|
4095
|
+
runnerId: this.#runnerId,
|
|
4096
|
+
component: "ForgeRunner"
|
|
4097
|
+
});
|
|
4042
4098
|
this.#webSocketClient = new WebSocketClient({
|
|
4043
|
-
|
|
4044
|
-
|
|
4099
|
+
apiKey: this.#options.apiKey,
|
|
4100
|
+
sdkServerUrl: this.#options.sdkServerUrl
|
|
4045
4101
|
}, this, this.#logger);
|
|
4046
4102
|
this.#webSocketClient.on(WEB_SOCKET_CLIENT_EVENTS.COMMUNICATION_INITIALIZED, this.#handleWebSocketCommunicationInitialized.bind(this));
|
|
4103
|
+
this.#webSocketClient.on("error", this.#handleWebSocketClientError.bind(this));
|
|
4047
4104
|
this.#start();
|
|
4048
4105
|
}
|
|
4049
4106
|
get activeSessionsCount() {
|
|
4050
|
-
return this.#sessionTools.size;
|
|
4107
|
+
return this.#sessionTools.size + this.#sessionAgents.size;
|
|
4051
4108
|
}
|
|
4052
4109
|
async #start() {
|
|
4053
4110
|
try {
|
|
@@ -4070,6 +4127,11 @@ var ForgeRunner = class extends EventEmitter {
|
|
|
4070
4127
|
this.#logger.info("websocket communication initialized, sending forge list...");
|
|
4071
4128
|
await this.#sendListForge();
|
|
4072
4129
|
}
|
|
4130
|
+
#handleWebSocketClientError(error) {
|
|
4131
|
+
this.#logger.error(error, "received error from websocket client");
|
|
4132
|
+
this.#reset();
|
|
4133
|
+
this.emit("error", error);
|
|
4134
|
+
}
|
|
4073
4135
|
async #handleWebSocketMessage(message) {
|
|
4074
4136
|
const toolRunnerMessageParsed = toForgeRunnerMessages.safeParse(message);
|
|
4075
4137
|
if (toolRunnerMessageParsed.success) {
|
|
@@ -4094,42 +4156,42 @@ var ForgeRunner = class extends EventEmitter {
|
|
|
4094
4156
|
this.#logger.warn("received start tool message for unknown tool id %s, ignoring", itemId);
|
|
4095
4157
|
throw new Error(`tool with id ${itemId} not found`);
|
|
4096
4158
|
}
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4159
|
+
runnerIdStore.run(this.#runnerId, () => {
|
|
4160
|
+
sessionIdStore.run(sessionId, () => {
|
|
4161
|
+
const tool = new Tool({
|
|
4162
|
+
toolName: toolDefinition.name,
|
|
4163
|
+
toolDescription: toolDefinition.description,
|
|
4164
|
+
toolId: itemId,
|
|
4165
|
+
handler: toolDefinition.handler,
|
|
4166
|
+
webSocketClient: this.#webSocketClient
|
|
4167
|
+
}, this.#logger);
|
|
4168
|
+
this.#sessionTools.set(sessionId, tool);
|
|
4169
|
+
tool.run().then((output) => runWithRetries(() => this.#webSocketClient.sendToServerWithAcknowledgement({
|
|
4170
|
+
id: nanoid(),
|
|
4171
|
+
timestamp: Date.now(),
|
|
4172
|
+
type: "TOOL_COMPLETE",
|
|
4173
|
+
data: {
|
|
4174
|
+
output,
|
|
4175
|
+
sessionId,
|
|
4176
|
+
executionContext: { type: "TOOL" }
|
|
4177
|
+
}
|
|
4178
|
+
}))).catch((error) => runWithRetries(() => this.#webSocketClient.sendToServerWithAcknowledgement({
|
|
4179
|
+
id: nanoid(),
|
|
4180
|
+
timestamp: Date.now(),
|
|
4181
|
+
type: "TOOL_ERROR",
|
|
4182
|
+
data: {
|
|
4183
|
+
error: {
|
|
4184
|
+
message: getErrorMessage(error),
|
|
4185
|
+
stack: error instanceof Error ? error.stack : void 0,
|
|
4186
|
+
code: error instanceof Error && "code" in error ? String(error.code) : void 0
|
|
4187
|
+
},
|
|
4188
|
+
sessionId,
|
|
4189
|
+
executionContext: { type: "TOOL" }
|
|
4190
|
+
}
|
|
4191
|
+
}))).finally(() => {
|
|
4192
|
+
this.#sessionTools.delete(sessionId);
|
|
4193
|
+
});
|
|
4194
|
+
});
|
|
4133
4195
|
});
|
|
4134
4196
|
}
|
|
4135
4197
|
#handleStopToolMessage(message) {
|
|
@@ -4176,7 +4238,7 @@ var ForgeRunner = class extends EventEmitter {
|
|
|
4176
4238
|
type: "LIST_FORGE",
|
|
4177
4239
|
timestamp: Date.now(),
|
|
4178
4240
|
data: {
|
|
4179
|
-
runnerId: this.#
|
|
4241
|
+
runnerId: this.#runnerId,
|
|
4180
4242
|
forgeItems: this.#forgeItems
|
|
4181
4243
|
}
|
|
4182
4244
|
}));
|
|
@@ -4189,39 +4251,39 @@ var ForgeRunner = class extends EventEmitter {
|
|
|
4189
4251
|
this.#logger.warn("received start agent message for unknown agent id %s, ignoring", itemId);
|
|
4190
4252
|
throw new Error(`agent with id ${itemId} not found`);
|
|
4191
4253
|
}
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4254
|
+
runnerIdStore.run(this.#runnerId, () => {
|
|
4255
|
+
sessionIdStore.run(sessionId, () => {
|
|
4256
|
+
const agent = new Agent(agentDefinition, {
|
|
4257
|
+
agentId: itemId,
|
|
4258
|
+
webSocketClient: this.#webSocketClient
|
|
4259
|
+
}, this.#logger);
|
|
4260
|
+
this.#sessionAgents.set(sessionId, agent);
|
|
4261
|
+
agent.run().then(() => runWithRetries(() => this.#webSocketClient.sendToServerWithAcknowledgement({
|
|
4262
|
+
id: nanoid(),
|
|
4263
|
+
timestamp: Date.now(),
|
|
4264
|
+
type: "AGENT_COMPLETE",
|
|
4265
|
+
data: {
|
|
4266
|
+
output: {},
|
|
4267
|
+
sessionId,
|
|
4268
|
+
executionContext: { type: "AGENT" }
|
|
4269
|
+
}
|
|
4270
|
+
}))).catch((error) => runWithRetries(() => this.#webSocketClient.sendToServerWithAcknowledgement({
|
|
4271
|
+
id: nanoid(),
|
|
4272
|
+
timestamp: Date.now(),
|
|
4273
|
+
type: "AGENT_ERROR",
|
|
4274
|
+
data: {
|
|
4275
|
+
error: {
|
|
4276
|
+
message: getErrorMessage(error),
|
|
4277
|
+
stack: error instanceof Error ? error.stack : void 0,
|
|
4278
|
+
code: error instanceof Error && "code" in error ? String(error.code) : void 0
|
|
4279
|
+
},
|
|
4280
|
+
sessionId,
|
|
4281
|
+
executionContext: { type: "AGENT" }
|
|
4282
|
+
}
|
|
4283
|
+
}))).finally(() => {
|
|
4284
|
+
this.#sessionAgents.delete(sessionId);
|
|
4285
|
+
});
|
|
4286
|
+
});
|
|
4225
4287
|
});
|
|
4226
4288
|
}
|
|
4227
4289
|
#handleStopAgentMessage(message) {
|
|
@@ -4235,27 +4297,7 @@ var ForgeRunner = class extends EventEmitter {
|
|
|
4235
4297
|
agent.stop();
|
|
4236
4298
|
this.#sessionTools.delete(sessionId);
|
|
4237
4299
|
}
|
|
4238
|
-
|
|
4239
|
-
* Refreshes the API key by requesting a new token from the SDK server,
|
|
4240
|
-
* when the apiKey is a (short lived) token used when runner is deployed
|
|
4241
|
-
* using Tool Forge Cloud.
|
|
4242
|
-
*/
|
|
4243
|
-
async #refreshApiKey() {
|
|
4244
|
-
if (!this.#options.tokenProviderEndpoint) return;
|
|
4245
|
-
const res = await fetch(new URL("/token/refresh", this.#options.tokenProviderEndpoint), {
|
|
4246
|
-
method: "POST",
|
|
4247
|
-
headers: { "Content-Type": "application/json" },
|
|
4248
|
-
body: JSON.stringify({ token: this.#apiKey })
|
|
4249
|
-
});
|
|
4250
|
-
if (!res.ok) throw new Error(`failed to refresh token: ${res.status} ${res.statusText}`);
|
|
4251
|
-
const data = await res.json();
|
|
4252
|
-
const result = z$1.object({ token: z$1.string().startsWith(TOKEN_PREFIX) }).safeParse(data);
|
|
4253
|
-
if (!result.success) throw new Error("invalid response from token refresh");
|
|
4254
|
-
this.#apiKey = result.data.token;
|
|
4255
|
-
this.#logger.info("successfully refreshed API token");
|
|
4256
|
-
}
|
|
4257
|
-
stop() {
|
|
4258
|
-
this.#logger.info("gracefully stopping tool runner...");
|
|
4300
|
+
#reset() {
|
|
4259
4301
|
if (this.#fsWatcher) {
|
|
4260
4302
|
this.#fsWatcher.close();
|
|
4261
4303
|
this.#fsWatcher = void 0;
|
|
@@ -4267,20 +4309,213 @@ var ForgeRunner = class extends EventEmitter {
|
|
|
4267
4309
|
this.#logger.info("websocket message handler unsubscribed");
|
|
4268
4310
|
}
|
|
4269
4311
|
this.#webSocketClient.off(WEB_SOCKET_CLIENT_EVENTS.COMMUNICATION_INITIALIZED, this.#handleWebSocketCommunicationInitialized.bind(this));
|
|
4312
|
+
this.#webSocketClient.off("error", this.#handleWebSocketClientError.bind(this));
|
|
4313
|
+
}
|
|
4314
|
+
stop() {
|
|
4315
|
+
this.#logger.info("gracefully stopping tool runner...");
|
|
4316
|
+
this.#reset();
|
|
4270
4317
|
this.#webSocketClient.stop();
|
|
4271
|
-
if (this.#refreshApiKeyInterval) {
|
|
4272
|
-
clearInterval(this.#refreshApiKeyInterval);
|
|
4273
|
-
this.#refreshApiKeyInterval = void 0;
|
|
4274
|
-
this.#logger.info("token refresh interval cleared");
|
|
4275
|
-
}
|
|
4276
4318
|
this.#logger.info("tool runner stopped");
|
|
4277
4319
|
}
|
|
4278
4320
|
};
|
|
4279
4321
|
|
|
4322
|
+
//#endregion
|
|
4323
|
+
//#region src/cli/lib/logger.ts
|
|
4324
|
+
const env = z$1.object({
|
|
4325
|
+
LOKI_HOST: z$1.url().optional(),
|
|
4326
|
+
LOKI_USERNAME: z$1.string().optional(),
|
|
4327
|
+
LOKI_PASSWORD: z$1.string().optional()
|
|
4328
|
+
}).parse(process.env);
|
|
4329
|
+
const transportTargets = [];
|
|
4330
|
+
if (env.LOKI_HOST) transportTargets.push({
|
|
4331
|
+
target: "pino-loki",
|
|
4332
|
+
level: "trace",
|
|
4333
|
+
options: {
|
|
4334
|
+
host: env.LOKI_HOST,
|
|
4335
|
+
basicAuth: env.LOKI_USERNAME && env.LOKI_PASSWORD ? {
|
|
4336
|
+
username: env.LOKI_USERNAME,
|
|
4337
|
+
password: env.LOKI_PASSWORD
|
|
4338
|
+
} : void 0,
|
|
4339
|
+
propsToLabels: [
|
|
4340
|
+
"app",
|
|
4341
|
+
"component",
|
|
4342
|
+
"runnerId",
|
|
4343
|
+
"sessionId"
|
|
4344
|
+
]
|
|
4345
|
+
}
|
|
4346
|
+
});
|
|
4347
|
+
transportTargets.push({
|
|
4348
|
+
target: "pino-pretty",
|
|
4349
|
+
level: "trace"
|
|
4350
|
+
});
|
|
4351
|
+
const rootLogger = pino({
|
|
4352
|
+
level: "trace",
|
|
4353
|
+
transport: { targets: transportTargets },
|
|
4354
|
+
base: { app: "forge-runner" }
|
|
4355
|
+
});
|
|
4356
|
+
console.log = (...args) => {
|
|
4357
|
+
const runnerId = runnerIdStore.getStore();
|
|
4358
|
+
const sessionId = sessionIdStore.getStore();
|
|
4359
|
+
rootLogger.info({
|
|
4360
|
+
runnerId,
|
|
4361
|
+
sessionId
|
|
4362
|
+
}, util.format(...args));
|
|
4363
|
+
};
|
|
4364
|
+
console.info = (...args) => {
|
|
4365
|
+
const runnerId = runnerIdStore.getStore();
|
|
4366
|
+
const sessionId = sessionIdStore.getStore();
|
|
4367
|
+
rootLogger.info({
|
|
4368
|
+
runnerId,
|
|
4369
|
+
sessionId
|
|
4370
|
+
}, util.format(...args));
|
|
4371
|
+
};
|
|
4372
|
+
console.warn = (...args) => {
|
|
4373
|
+
const runnerId = runnerIdStore.getStore();
|
|
4374
|
+
const sessionId = sessionIdStore.getStore();
|
|
4375
|
+
rootLogger.warn({
|
|
4376
|
+
runnerId,
|
|
4377
|
+
sessionId
|
|
4378
|
+
}, util.format(...args));
|
|
4379
|
+
};
|
|
4380
|
+
console.error = (...args) => {
|
|
4381
|
+
const runnerId = runnerIdStore.getStore();
|
|
4382
|
+
const sessionId = sessionIdStore.getStore();
|
|
4383
|
+
rootLogger.error({
|
|
4384
|
+
runnerId,
|
|
4385
|
+
sessionId
|
|
4386
|
+
}, util.format(...args));
|
|
4387
|
+
};
|
|
4388
|
+
console.debug = (...args) => {
|
|
4389
|
+
const runnerId = runnerIdStore.getStore();
|
|
4390
|
+
const sessionId = sessionIdStore.getStore();
|
|
4391
|
+
rootLogger.debug({
|
|
4392
|
+
runnerId,
|
|
4393
|
+
sessionId
|
|
4394
|
+
}, util.format(...args));
|
|
4395
|
+
};
|
|
4396
|
+
console.trace = (...args) => {
|
|
4397
|
+
const runnerId = runnerIdStore.getStore();
|
|
4398
|
+
const sessionId = sessionIdStore.getStore();
|
|
4399
|
+
const stack = (/* @__PURE__ */ new Error()).stack;
|
|
4400
|
+
rootLogger.trace({
|
|
4401
|
+
runnerId,
|
|
4402
|
+
sessionId,
|
|
4403
|
+
stack
|
|
4404
|
+
}, util.format(...args));
|
|
4405
|
+
};
|
|
4406
|
+
console.group = (...args) => {
|
|
4407
|
+
const runnerId = runnerIdStore.getStore();
|
|
4408
|
+
const sessionId = sessionIdStore.getStore();
|
|
4409
|
+
rootLogger.info({
|
|
4410
|
+
runnerId,
|
|
4411
|
+
sessionId
|
|
4412
|
+
}, util.format("group:", ...args));
|
|
4413
|
+
};
|
|
4414
|
+
console.groupCollapsed = (...args) => {
|
|
4415
|
+
const runnerId = runnerIdStore.getStore();
|
|
4416
|
+
const sessionId = sessionIdStore.getStore();
|
|
4417
|
+
rootLogger.info({
|
|
4418
|
+
runnerId,
|
|
4419
|
+
sessionId
|
|
4420
|
+
}, util.format("group:", ...args));
|
|
4421
|
+
};
|
|
4422
|
+
console.groupEnd = () => {
|
|
4423
|
+
const runnerId = runnerIdStore.getStore();
|
|
4424
|
+
const sessionId = sessionIdStore.getStore();
|
|
4425
|
+
rootLogger.info({
|
|
4426
|
+
runnerId,
|
|
4427
|
+
sessionId
|
|
4428
|
+
}, "group end");
|
|
4429
|
+
};
|
|
4430
|
+
const timers = /* @__PURE__ */ new Map();
|
|
4431
|
+
console.time = (label = "default") => {
|
|
4432
|
+
timers.set(label, Date.now());
|
|
4433
|
+
};
|
|
4434
|
+
console.timeEnd = (label = "default") => {
|
|
4435
|
+
const runnerId = runnerIdStore.getStore();
|
|
4436
|
+
const sessionId = sessionIdStore.getStore();
|
|
4437
|
+
const start = timers.get(label);
|
|
4438
|
+
if (start) {
|
|
4439
|
+
const duration = Date.now() - start;
|
|
4440
|
+
rootLogger.info({
|
|
4441
|
+
runnerId,
|
|
4442
|
+
sessionId,
|
|
4443
|
+
duration
|
|
4444
|
+
}, `${label}: ${duration}ms`);
|
|
4445
|
+
timers.delete(label);
|
|
4446
|
+
}
|
|
4447
|
+
};
|
|
4448
|
+
console.timeLog = (label = "default", ...args) => {
|
|
4449
|
+
const runnerId = runnerIdStore.getStore();
|
|
4450
|
+
const sessionId = sessionIdStore.getStore();
|
|
4451
|
+
const start = timers.get(label);
|
|
4452
|
+
if (start) {
|
|
4453
|
+
const duration = Date.now() - start;
|
|
4454
|
+
rootLogger.info({
|
|
4455
|
+
runnerId,
|
|
4456
|
+
sessionId,
|
|
4457
|
+
duration
|
|
4458
|
+
}, util.format(`${label}: ${duration}ms`, ...args));
|
|
4459
|
+
}
|
|
4460
|
+
};
|
|
4461
|
+
console.assert = (condition, ...args) => {
|
|
4462
|
+
if (!condition) {
|
|
4463
|
+
const runnerId = runnerIdStore.getStore();
|
|
4464
|
+
const sessionId = sessionIdStore.getStore();
|
|
4465
|
+
rootLogger.error({
|
|
4466
|
+
runnerId,
|
|
4467
|
+
sessionId
|
|
4468
|
+
}, util.format("assertion failed:", ...args));
|
|
4469
|
+
}
|
|
4470
|
+
};
|
|
4471
|
+
console.table = (data) => {
|
|
4472
|
+
const runnerId = runnerIdStore.getStore();
|
|
4473
|
+
const sessionId = sessionIdStore.getStore();
|
|
4474
|
+
rootLogger.info({
|
|
4475
|
+
runnerId,
|
|
4476
|
+
sessionId,
|
|
4477
|
+
data
|
|
4478
|
+
}, "table data");
|
|
4479
|
+
};
|
|
4480
|
+
const counters = /* @__PURE__ */ new Map();
|
|
4481
|
+
console.count = (label = "default") => {
|
|
4482
|
+
const runnerId = runnerIdStore.getStore();
|
|
4483
|
+
const sessionId = sessionIdStore.getStore();
|
|
4484
|
+
const count = (counters.get(label) || 0) + 1;
|
|
4485
|
+
counters.set(label, count);
|
|
4486
|
+
rootLogger.info({
|
|
4487
|
+
runnerId,
|
|
4488
|
+
sessionId
|
|
4489
|
+
}, `${label}: ${count}`);
|
|
4490
|
+
};
|
|
4491
|
+
console.countReset = (label = "default") => {
|
|
4492
|
+
counters.delete(label);
|
|
4493
|
+
};
|
|
4494
|
+
console.clear = () => {};
|
|
4495
|
+
console.dir = (obj, options) => {
|
|
4496
|
+
const runnerId = runnerIdStore.getStore();
|
|
4497
|
+
const sessionId = sessionIdStore.getStore();
|
|
4498
|
+
rootLogger.info({
|
|
4499
|
+
runnerId,
|
|
4500
|
+
sessionId,
|
|
4501
|
+
obj,
|
|
4502
|
+
options
|
|
4503
|
+
}, "Dir output");
|
|
4504
|
+
};
|
|
4505
|
+
console.dirxml = (...args) => {
|
|
4506
|
+
const runnerId = runnerIdStore.getStore();
|
|
4507
|
+
const sessionId = sessionIdStore.getStore();
|
|
4508
|
+
rootLogger.info({
|
|
4509
|
+
runnerId,
|
|
4510
|
+
sessionId
|
|
4511
|
+
}, util.format(...args));
|
|
4512
|
+
};
|
|
4513
|
+
|
|
4280
4514
|
//#endregion
|
|
4281
4515
|
//#region src/cli/actions/start-tool-forge.ts
|
|
4282
4516
|
async function startToolForge({ configRelPath, debug, mode }) {
|
|
4283
|
-
const
|
|
4517
|
+
const runnerId = runnerIdStore.getStore();
|
|
4518
|
+
const logger = rootLogger.child({ runnerId }, { level: debug ? "debug" : "info" });
|
|
4284
4519
|
try {
|
|
4285
4520
|
const spinner = ora("loading configuration...").start();
|
|
4286
4521
|
const { config, configPath } = await getToolForgeConfig(configRelPath);
|
|
@@ -4312,19 +4547,15 @@ async function startToolForge({ configRelPath, debug, mode }) {
|
|
|
4312
4547
|
}, logger);
|
|
4313
4548
|
runner.on("error", async (error) => {
|
|
4314
4549
|
logger.error(error, "tool runner error - shutting down");
|
|
4315
|
-
await runner.stop();
|
|
4316
|
-
process.exit(1);
|
|
4317
|
-
});
|
|
4318
|
-
process.on("SIGTERM", async () => {
|
|
4319
|
-
logger.info("gracefully shutting down tool runner...");
|
|
4320
|
-
await runner.stop();
|
|
4321
4550
|
process.exit(1);
|
|
4322
4551
|
});
|
|
4323
|
-
|
|
4552
|
+
async function gracefulShutdown() {
|
|
4324
4553
|
logger.info("gracefully shutting down tool runner...");
|
|
4325
4554
|
await runner.stop();
|
|
4326
4555
|
process.exit(1);
|
|
4327
|
-
}
|
|
4556
|
+
}
|
|
4557
|
+
process.on("SIGTERM", gracefulShutdown);
|
|
4558
|
+
process.on("SIGINT", gracefulShutdown);
|
|
4328
4559
|
} catch (error) {
|
|
4329
4560
|
logger.error(error, "failed to start tool runner");
|
|
4330
4561
|
process.exit(1);
|
|
@@ -4337,24 +4568,32 @@ const version = JSON.parse(readFileSync(path.resolve(__dirname, "../../package.j
|
|
|
4337
4568
|
program.name("toolforge").description("Tool Forge SDK cli").version(version);
|
|
4338
4569
|
program.command("dev").description("start the tool forge development server").option("-c, --config <path>", "path to the tool-forge config file", (val) => z$1.string().parse(val), "toolforge.config.ts").option("-d, --debug", "enable debug logging", false).action(async function startServer() {
|
|
4339
4570
|
const debug = z$1.boolean().optional().default(false).parse(this.opts().debug);
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4571
|
+
const configRelPath = z$1.string().parse(this.opts().config);
|
|
4572
|
+
const runnerId = `tf-runner:${nanoid(32)}`;
|
|
4573
|
+
runnerIdStore.run(runnerId, () => {
|
|
4574
|
+
startToolForge({
|
|
4575
|
+
configRelPath,
|
|
4576
|
+
debug,
|
|
4577
|
+
mode: "development"
|
|
4578
|
+
}).catch((error) => {
|
|
4579
|
+
if (error instanceof Error) console.error(error, "failed to start toolforge runner");
|
|
4580
|
+
process.exit(1);
|
|
4581
|
+
});
|
|
4347
4582
|
});
|
|
4348
4583
|
});
|
|
4349
4584
|
program.command("start").description("start the tool forge server in production mode").option("-c, --config <path>", "path to the tool-forge config file", (val) => z$1.string().parse(val), "toolforge.config.ts").option("-d, --debug", "enable debug logging", false).action(async function startServer() {
|
|
4350
4585
|
const debug = z$1.boolean().optional().default(false).parse(this.opts().debug);
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4586
|
+
const configRelPath = z$1.string().parse(this.opts().config);
|
|
4587
|
+
const runnerId = `tf-runner:${nanoid(32)}`;
|
|
4588
|
+
runnerIdStore.run(runnerId, () => {
|
|
4589
|
+
startToolForge({
|
|
4590
|
+
configRelPath,
|
|
4591
|
+
debug,
|
|
4592
|
+
mode: "production"
|
|
4593
|
+
}).catch((error) => {
|
|
4594
|
+
if (error instanceof Error) console.error(error, "failed to start toolforge runner");
|
|
4595
|
+
process.exit(1);
|
|
4596
|
+
});
|
|
4358
4597
|
});
|
|
4359
4598
|
});
|
|
4360
4599
|
program.command("build").description("build the tools for production").option("-c, --config <path>", "path to the tool-forge config file", (val) => z$1.string().parse(val), "toolforge.config.ts").option("-d, --debug", "enable debug logging", false).action(async function() {
|