@lesscap/baton-cli 0.2.6 → 0.2.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/baton.mjs +73 -19
- package/package.json +1 -1
package/dist/baton.mjs
CHANGED
|
@@ -700,6 +700,7 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
700
700
|
import { join } from "node:path";
|
|
701
701
|
var PROJECT_CONFIG_NAME = ".baton.json";
|
|
702
702
|
var projectConfigPath = (cwd = process.cwd()) => join(cwd, PROJECT_CONFIG_NAME);
|
|
703
|
+
var configPathFromArgs = (args, cwd) => args.config ?? projectConfigPath(cwd);
|
|
703
704
|
var loadProjectConfig = (path) => {
|
|
704
705
|
try {
|
|
705
706
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
@@ -768,10 +769,17 @@ var common = {
|
|
|
768
769
|
},
|
|
769
770
|
json: { type: "boolean", description: "output JSON" }
|
|
770
771
|
};
|
|
772
|
+
var resolveAuth = (env, fileToken) => {
|
|
773
|
+
const envBearer = env.BATON_TOKEN ?? env.BATON_WORKER_TOKEN;
|
|
774
|
+
if (envBearer) return { bearer: envBearer };
|
|
775
|
+
if (env.BATON_USER && env.BATON_PASS) return "cookie";
|
|
776
|
+
return fileToken ? { bearer: fileToken } : void 0;
|
|
777
|
+
};
|
|
771
778
|
var clientFor = (args) => {
|
|
772
|
-
const
|
|
773
|
-
const
|
|
774
|
-
|
|
779
|
+
const baseUrl = resolveBaseUrl(args.url);
|
|
780
|
+
const fileToken = loadProjectConfigOrNull(projectConfigPath())?.worker?.apiToken;
|
|
781
|
+
const auth = resolveAuth(process.env, fileToken);
|
|
782
|
+
return createClient(baseUrl, auth && auth !== "cookie" ? auth : void 0);
|
|
775
783
|
};
|
|
776
784
|
var resolveProjectId = (args) => {
|
|
777
785
|
if (args.project !== void 0 && args.project !== "") return Number(args.project);
|
|
@@ -2645,11 +2653,35 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
2645
2653
|
const worktreeDir = defaultWorktreeDir();
|
|
2646
2654
|
const children = /* @__PURE__ */ new Map();
|
|
2647
2655
|
const log = (m) => console.log(`[worker #${cfg.workerId} ${cfg.name}] ${m}`);
|
|
2648
|
-
const
|
|
2649
|
-
|
|
2656
|
+
const HEARTBEAT_MS = 3e4;
|
|
2657
|
+
const HEARTBEAT_TIMEOUT_MS = 15e3;
|
|
2658
|
+
const MAX_HEARTBEAT_FAILURES = 5;
|
|
2659
|
+
let heartbeatFailures = 0;
|
|
2660
|
+
let fatal = false;
|
|
2661
|
+
let stop = () => {
|
|
2662
|
+
};
|
|
2663
|
+
const ping = async () => {
|
|
2664
|
+
try {
|
|
2665
|
+
await Promise.race([
|
|
2666
|
+
client.workers.heartbeat(cfg.machineId),
|
|
2667
|
+
new Promise(
|
|
2668
|
+
(_, reject) => setTimeout(() => reject(new Error("heartbeat timeout")), HEARTBEAT_TIMEOUT_MS)
|
|
2669
|
+
)
|
|
2670
|
+
]);
|
|
2671
|
+
heartbeatFailures = 0;
|
|
2672
|
+
} catch (e) {
|
|
2673
|
+
heartbeatFailures += 1;
|
|
2674
|
+
log(`heartbeat failed (${heartbeatFailures}/${MAX_HEARTBEAT_FAILURES}): ${String(e)}`);
|
|
2675
|
+
if (heartbeatFailures >= MAX_HEARTBEAT_FAILURES) {
|
|
2676
|
+
const downSec = MAX_HEARTBEAT_FAILURES * HEARTBEAT_MS / 1e3;
|
|
2677
|
+
log(`heartbeat down ~${downSec}s \u2014 exiting so the supervisor restarts a clean worker`);
|
|
2678
|
+
fatal = true;
|
|
2679
|
+
stop();
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2650
2682
|
};
|
|
2651
|
-
ping();
|
|
2652
|
-
const hb = setInterval(ping,
|
|
2683
|
+
void ping();
|
|
2684
|
+
const hb = setInterval(() => void ping(), HEARTBEAT_MS);
|
|
2653
2685
|
const killChild = (child) => {
|
|
2654
2686
|
if (child.pid === void 0) return;
|
|
2655
2687
|
try {
|
|
@@ -2769,12 +2801,14 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
2769
2801
|
es.onerror = () => log("command stream error (eventsource will retry)");
|
|
2770
2802
|
log(`listening for commands (server ${cfg.server}, repo ${repo})`);
|
|
2771
2803
|
await new Promise((resolve2) => {
|
|
2804
|
+
stop = resolve2;
|
|
2772
2805
|
if (signal.aborted) return resolve2();
|
|
2773
2806
|
signal.addEventListener("abort", () => resolve2(), { once: true });
|
|
2774
2807
|
});
|
|
2775
2808
|
es.close();
|
|
2776
2809
|
clearInterval(hb);
|
|
2777
2810
|
for (const { child } of children.values()) killChild(child);
|
|
2811
|
+
if (fatal) process.exit(1);
|
|
2778
2812
|
};
|
|
2779
2813
|
|
|
2780
2814
|
// src/worker/machine-id.ts
|
|
@@ -2837,6 +2871,10 @@ var worker = defineCommand({
|
|
|
2837
2871
|
args: {
|
|
2838
2872
|
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2839
2873
|
name: { type: "string", description: "worker display name (default: hostname)" },
|
|
2874
|
+
config: {
|
|
2875
|
+
type: "string",
|
|
2876
|
+
description: "path to the worker config file (default: ./.baton.json)"
|
|
2877
|
+
},
|
|
2840
2878
|
...common
|
|
2841
2879
|
},
|
|
2842
2880
|
run: async ({ args }) => {
|
|
@@ -2850,13 +2888,17 @@ var worker = defineCommand({
|
|
|
2850
2888
|
const hostname = osHostname();
|
|
2851
2889
|
const machineId = readOrCreateMachineId();
|
|
2852
2890
|
const name = args.name ?? hostname;
|
|
2853
|
-
const { out, configPath } = await registerWorker(
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2891
|
+
const { out, configPath } = await registerWorker(
|
|
2892
|
+
c,
|
|
2893
|
+
{
|
|
2894
|
+
projectId: resolveProjectId(args),
|
|
2895
|
+
name,
|
|
2896
|
+
server,
|
|
2897
|
+
hostname,
|
|
2898
|
+
machineId
|
|
2899
|
+
},
|
|
2900
|
+
configPathFromArgs(args)
|
|
2901
|
+
);
|
|
2860
2902
|
if (args.json) {
|
|
2861
2903
|
console.log(toJson({ ...out, configPath, machineIdPath: machineIdPath() }));
|
|
2862
2904
|
return;
|
|
@@ -2873,9 +2915,15 @@ var worker = defineCommand({
|
|
|
2873
2915
|
name: "run",
|
|
2874
2916
|
description: "run the persistent worker daemon (listens for session create/delete commands)"
|
|
2875
2917
|
},
|
|
2876
|
-
args: {
|
|
2877
|
-
|
|
2878
|
-
|
|
2918
|
+
args: {
|
|
2919
|
+
config: {
|
|
2920
|
+
type: "string",
|
|
2921
|
+
description: "path to the worker config file (default: ./.baton.json)"
|
|
2922
|
+
},
|
|
2923
|
+
...common
|
|
2924
|
+
},
|
|
2925
|
+
run: async ({ args }) => {
|
|
2926
|
+
const cfg = viewWorker(loadProjectConfig(configPathFromArgs(args)));
|
|
2879
2927
|
const client = createClient(cfg.server, { bearer: cfg.apiToken });
|
|
2880
2928
|
const ac = new AbortController();
|
|
2881
2929
|
const stop = () => ac.abort();
|
|
@@ -2944,11 +2992,17 @@ var worker = defineCommand({
|
|
|
2944
2992
|
}),
|
|
2945
2993
|
whoami: defineCommand({
|
|
2946
2994
|
meta: { name: "whoami", description: "show local worker config from .baton.json" },
|
|
2947
|
-
args: {
|
|
2995
|
+
args: {
|
|
2996
|
+
config: {
|
|
2997
|
+
type: "string",
|
|
2998
|
+
description: "path to the worker config file (default: ./.baton.json)"
|
|
2999
|
+
},
|
|
3000
|
+
...common
|
|
3001
|
+
},
|
|
2948
3002
|
run: ({ args }) => {
|
|
2949
3003
|
const cfg = (() => {
|
|
2950
3004
|
try {
|
|
2951
|
-
return loadProjectConfig(
|
|
3005
|
+
return loadProjectConfig(configPathFromArgs(args));
|
|
2952
3006
|
} catch {
|
|
2953
3007
|
return null;
|
|
2954
3008
|
}
|