@botiverse/raft-computer 0.0.60 → 0.0.61
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/index.js +271 -200
- package/dist/lib/index.js +51 -13
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -29592,6 +29592,7 @@ var {
|
|
|
29592
29592
|
|
|
29593
29593
|
// src/login.ts
|
|
29594
29594
|
init_esm_shims();
|
|
29595
|
+
import { unlink } from "fs/promises";
|
|
29595
29596
|
|
|
29596
29597
|
// src/output.ts
|
|
29597
29598
|
init_esm_shims();
|
|
@@ -29619,6 +29620,124 @@ function fail(code, message, exitCode = 1) {
|
|
|
29619
29620
|
throw new CliExit(exitCode, code);
|
|
29620
29621
|
}
|
|
29621
29622
|
|
|
29623
|
+
// src/paths.ts
|
|
29624
|
+
init_esm_shims();
|
|
29625
|
+
import { createHash } from "crypto";
|
|
29626
|
+
import os from "os";
|
|
29627
|
+
import path2 from "path";
|
|
29628
|
+
var CURRENT_SCHEMA_VERSION = 1;
|
|
29629
|
+
function resolveSlockHome(env = process.env, homeDir = os.homedir()) {
|
|
29630
|
+
const configured = env.SLOCK_HOME?.trim();
|
|
29631
|
+
const raw = configured && configured.length > 0 ? configured : path2.join(homeDir, ".slock");
|
|
29632
|
+
return path2.resolve(expandHome(raw, homeDir));
|
|
29633
|
+
}
|
|
29634
|
+
function expandHome(input, homeDir) {
|
|
29635
|
+
if (input === "~") return homeDir;
|
|
29636
|
+
if (input.startsWith("~/")) return path2.join(homeDir, input.slice(2));
|
|
29637
|
+
return input;
|
|
29638
|
+
}
|
|
29639
|
+
function computerDir(slockHome) {
|
|
29640
|
+
return path2.join(slockHome, "computer");
|
|
29641
|
+
}
|
|
29642
|
+
function userSessionPath(slockHome) {
|
|
29643
|
+
return path2.join(computerDir(slockHome), "user-session.json");
|
|
29644
|
+
}
|
|
29645
|
+
var SERVER_ID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
29646
|
+
function isValidServerId(serverId) {
|
|
29647
|
+
return SERVER_ID_RE.test(serverId);
|
|
29648
|
+
}
|
|
29649
|
+
function assertValidServerId(serverId) {
|
|
29650
|
+
if (!isValidServerId(serverId)) {
|
|
29651
|
+
throw new Error(`invalid server id: ${JSON.stringify(serverId)} (expected a UUID)`);
|
|
29652
|
+
}
|
|
29653
|
+
return serverId;
|
|
29654
|
+
}
|
|
29655
|
+
function serversDir(slockHome) {
|
|
29656
|
+
return path2.join(computerDir(slockHome), "servers");
|
|
29657
|
+
}
|
|
29658
|
+
function serverDir(slockHome, serverId) {
|
|
29659
|
+
return path2.join(serversDir(slockHome), assertValidServerId(serverId));
|
|
29660
|
+
}
|
|
29661
|
+
function serverAttachmentPath(slockHome, serverId) {
|
|
29662
|
+
return path2.join(serverDir(slockHome, serverId), "runner.state.json");
|
|
29663
|
+
}
|
|
29664
|
+
function legacyServerAttachmentPath(slockHome, serverId) {
|
|
29665
|
+
return path2.join(serverDir(slockHome, serverId), "attachment.json");
|
|
29666
|
+
}
|
|
29667
|
+
function serverRunnerPidPath(slockHome, serverId) {
|
|
29668
|
+
return path2.join(serverDir(slockHome, serverId), "runner.pid");
|
|
29669
|
+
}
|
|
29670
|
+
function serverRunnerLogPath(slockHome, serverId) {
|
|
29671
|
+
return path2.join(serverDir(slockHome, serverId), "runner.log");
|
|
29672
|
+
}
|
|
29673
|
+
function serverManagedFlagPath(slockHome, serverId) {
|
|
29674
|
+
return path2.join(serverDir(slockHome, serverId), "managed.flag");
|
|
29675
|
+
}
|
|
29676
|
+
function serverHealthPath(slockHome, serverId) {
|
|
29677
|
+
return path2.join(serverDir(slockHome, serverId), "health.json");
|
|
29678
|
+
}
|
|
29679
|
+
function serviceRunDir(slockHome) {
|
|
29680
|
+
return path2.join(computerDir(slockHome), "run");
|
|
29681
|
+
}
|
|
29682
|
+
function serviceStatePath(slockHome) {
|
|
29683
|
+
return path2.join(serviceRunDir(slockHome), "service.state.json");
|
|
29684
|
+
}
|
|
29685
|
+
function servicePidPath(slockHome) {
|
|
29686
|
+
return path2.join(serviceRunDir(slockHome), "service.pid");
|
|
29687
|
+
}
|
|
29688
|
+
function servicePidReadFallback(slockHome) {
|
|
29689
|
+
return [servicePidPath(slockHome)];
|
|
29690
|
+
}
|
|
29691
|
+
function serviceLogPath(slockHome) {
|
|
29692
|
+
return path2.join(serviceRunDir(slockHome), "service.log");
|
|
29693
|
+
}
|
|
29694
|
+
function serviceSocketPath(slockHome) {
|
|
29695
|
+
return path2.join(computerDir(slockHome), "run", "service.sock");
|
|
29696
|
+
}
|
|
29697
|
+
function serviceWindowsPipeName(slockHome) {
|
|
29698
|
+
const hash = createHash("sha256").update(computerDir(slockHome)).digest("hex").slice(0, 16);
|
|
29699
|
+
return `\\\\.\\pipe\\slock-computer-${hash}`;
|
|
29700
|
+
}
|
|
29701
|
+
function serviceVersionPath(slockHome) {
|
|
29702
|
+
return path2.join(computerDir(slockHome), "service-version.json");
|
|
29703
|
+
}
|
|
29704
|
+
var HOSTNAME_SUFFIXES = [
|
|
29705
|
+
".fritz.box",
|
|
29706
|
+
".localdomain",
|
|
29707
|
+
".local",
|
|
29708
|
+
".lan",
|
|
29709
|
+
".home"
|
|
29710
|
+
];
|
|
29711
|
+
function shortHostnameHash(hostname) {
|
|
29712
|
+
return createHash("sha256").update(hostname).digest("hex").slice(0, 8);
|
|
29713
|
+
}
|
|
29714
|
+
function deriveDefaultComputerName(hostname = os.hostname()) {
|
|
29715
|
+
const original = hostname.trim();
|
|
29716
|
+
let name = original;
|
|
29717
|
+
let lower = name.toLowerCase();
|
|
29718
|
+
for (; ; ) {
|
|
29719
|
+
const suffix = HOSTNAME_SUFFIXES.find((candidate) => lower.endsWith(candidate));
|
|
29720
|
+
if (!suffix) break;
|
|
29721
|
+
name = name.slice(0, -suffix.length);
|
|
29722
|
+
lower = name.toLowerCase();
|
|
29723
|
+
}
|
|
29724
|
+
name = name.replace(/[\s'"]+/g, "-").replace(/-+$/g, "");
|
|
29725
|
+
return name.length > 0 ? name : `slock-computer-${shortHostnameHash(original)}`;
|
|
29726
|
+
}
|
|
29727
|
+
function adoptionLogPath(slockHome) {
|
|
29728
|
+
return path2.join(computerDir(slockHome), "adoption.log");
|
|
29729
|
+
}
|
|
29730
|
+
function channelPath(slockHome) {
|
|
29731
|
+
return path2.join(computerDir(slockHome), "channel");
|
|
29732
|
+
}
|
|
29733
|
+
function upgradeLogPath(slockHome) {
|
|
29734
|
+
return path2.join(computerDir(slockHome), "upgrade.log");
|
|
29735
|
+
}
|
|
29736
|
+
function formatUpgradeLogTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
29737
|
+
const iso = date.toISOString();
|
|
29738
|
+
return iso.replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
29739
|
+
}
|
|
29740
|
+
|
|
29622
29741
|
// src/services/errors.ts
|
|
29623
29742
|
init_esm_shims();
|
|
29624
29743
|
var ComputerServiceError = class extends Error {
|
|
@@ -29931,123 +30050,6 @@ var RunnersClient = class {
|
|
|
29931
30050
|
}
|
|
29932
30051
|
};
|
|
29933
30052
|
|
|
29934
|
-
// src/paths.ts
|
|
29935
|
-
init_esm_shims();
|
|
29936
|
-
import { createHash } from "crypto";
|
|
29937
|
-
import os from "os";
|
|
29938
|
-
import path2 from "path";
|
|
29939
|
-
function resolveSlockHome(env = process.env, homeDir = os.homedir()) {
|
|
29940
|
-
const configured = env.SLOCK_HOME?.trim();
|
|
29941
|
-
const raw = configured && configured.length > 0 ? configured : path2.join(homeDir, ".slock");
|
|
29942
|
-
return path2.resolve(expandHome(raw, homeDir));
|
|
29943
|
-
}
|
|
29944
|
-
function expandHome(input, homeDir) {
|
|
29945
|
-
if (input === "~") return homeDir;
|
|
29946
|
-
if (input.startsWith("~/")) return path2.join(homeDir, input.slice(2));
|
|
29947
|
-
return input;
|
|
29948
|
-
}
|
|
29949
|
-
function computerDir(slockHome) {
|
|
29950
|
-
return path2.join(slockHome, "computer");
|
|
29951
|
-
}
|
|
29952
|
-
function userSessionPath(slockHome) {
|
|
29953
|
-
return path2.join(computerDir(slockHome), "user-session.json");
|
|
29954
|
-
}
|
|
29955
|
-
var SERVER_ID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
29956
|
-
function isValidServerId(serverId) {
|
|
29957
|
-
return SERVER_ID_RE.test(serverId);
|
|
29958
|
-
}
|
|
29959
|
-
function assertValidServerId(serverId) {
|
|
29960
|
-
if (!isValidServerId(serverId)) {
|
|
29961
|
-
throw new Error(`invalid server id: ${JSON.stringify(serverId)} (expected a UUID)`);
|
|
29962
|
-
}
|
|
29963
|
-
return serverId;
|
|
29964
|
-
}
|
|
29965
|
-
function serversDir(slockHome) {
|
|
29966
|
-
return path2.join(computerDir(slockHome), "servers");
|
|
29967
|
-
}
|
|
29968
|
-
function serverDir(slockHome, serverId) {
|
|
29969
|
-
return path2.join(serversDir(slockHome), assertValidServerId(serverId));
|
|
29970
|
-
}
|
|
29971
|
-
function serverAttachmentPath(slockHome, serverId) {
|
|
29972
|
-
return path2.join(serverDir(slockHome, serverId), "runner.state.json");
|
|
29973
|
-
}
|
|
29974
|
-
function legacyServerAttachmentPath(slockHome, serverId) {
|
|
29975
|
-
return path2.join(serverDir(slockHome, serverId), "attachment.json");
|
|
29976
|
-
}
|
|
29977
|
-
function serverRunnerPidPath(slockHome, serverId) {
|
|
29978
|
-
return path2.join(serverDir(slockHome, serverId), "server-runner.pid");
|
|
29979
|
-
}
|
|
29980
|
-
function serverRunnerLogPath(slockHome, serverId) {
|
|
29981
|
-
return path2.join(serverDir(slockHome, serverId), "server-runner.log");
|
|
29982
|
-
}
|
|
29983
|
-
function serverManagedFlagPath(slockHome, serverId) {
|
|
29984
|
-
return path2.join(serverDir(slockHome, serverId), "managed.flag");
|
|
29985
|
-
}
|
|
29986
|
-
function serverHealthPath(slockHome, serverId) {
|
|
29987
|
-
return path2.join(serverDir(slockHome, serverId), "health.json");
|
|
29988
|
-
}
|
|
29989
|
-
function serviceRunDir(slockHome) {
|
|
29990
|
-
return path2.join(computerDir(slockHome), "run");
|
|
29991
|
-
}
|
|
29992
|
-
function serviceStatePath(slockHome) {
|
|
29993
|
-
return path2.join(serviceRunDir(slockHome), "service.state.json");
|
|
29994
|
-
}
|
|
29995
|
-
function servicePidPath(slockHome) {
|
|
29996
|
-
return path2.join(serviceRunDir(slockHome), "service.pid");
|
|
29997
|
-
}
|
|
29998
|
-
function servicePidReadFallback(slockHome) {
|
|
29999
|
-
return [servicePidPath(slockHome)];
|
|
30000
|
-
}
|
|
30001
|
-
function serviceLogPath(slockHome) {
|
|
30002
|
-
return path2.join(serviceRunDir(slockHome), "service.log");
|
|
30003
|
-
}
|
|
30004
|
-
function serviceSocketPath(slockHome) {
|
|
30005
|
-
return path2.join(computerDir(slockHome), "run", "service.sock");
|
|
30006
|
-
}
|
|
30007
|
-
function serviceWindowsPipeName(slockHome) {
|
|
30008
|
-
const hash = createHash("sha256").update(computerDir(slockHome)).digest("hex").slice(0, 16);
|
|
30009
|
-
return `\\\\.\\pipe\\slock-computer-${hash}`;
|
|
30010
|
-
}
|
|
30011
|
-
function serviceVersionPath(slockHome) {
|
|
30012
|
-
return path2.join(computerDir(slockHome), "service-version.json");
|
|
30013
|
-
}
|
|
30014
|
-
var HOSTNAME_SUFFIXES = [
|
|
30015
|
-
".fritz.box",
|
|
30016
|
-
".localdomain",
|
|
30017
|
-
".local",
|
|
30018
|
-
".lan",
|
|
30019
|
-
".home"
|
|
30020
|
-
];
|
|
30021
|
-
function shortHostnameHash(hostname) {
|
|
30022
|
-
return createHash("sha256").update(hostname).digest("hex").slice(0, 8);
|
|
30023
|
-
}
|
|
30024
|
-
function deriveDefaultComputerName(hostname = os.hostname()) {
|
|
30025
|
-
const original = hostname.trim();
|
|
30026
|
-
let name = original;
|
|
30027
|
-
let lower = name.toLowerCase();
|
|
30028
|
-
for (; ; ) {
|
|
30029
|
-
const suffix = HOSTNAME_SUFFIXES.find((candidate) => lower.endsWith(candidate));
|
|
30030
|
-
if (!suffix) break;
|
|
30031
|
-
name = name.slice(0, -suffix.length);
|
|
30032
|
-
lower = name.toLowerCase();
|
|
30033
|
-
}
|
|
30034
|
-
name = name.replace(/[\s'"]+/g, "-").replace(/-+$/g, "");
|
|
30035
|
-
return name.length > 0 ? name : `slock-computer-${shortHostnameHash(original)}`;
|
|
30036
|
-
}
|
|
30037
|
-
function adoptionLogPath(slockHome) {
|
|
30038
|
-
return path2.join(computerDir(slockHome), "adoption.log");
|
|
30039
|
-
}
|
|
30040
|
-
function channelPath(slockHome) {
|
|
30041
|
-
return path2.join(computerDir(slockHome), "channel");
|
|
30042
|
-
}
|
|
30043
|
-
function upgradeLogPath(slockHome) {
|
|
30044
|
-
return path2.join(computerDir(slockHome), "upgrade.log");
|
|
30045
|
-
}
|
|
30046
|
-
function formatUpgradeLogTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
30047
|
-
const iso = date.toISOString();
|
|
30048
|
-
return iso.replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
30049
|
-
}
|
|
30050
|
-
|
|
30051
30053
|
// src/serverUrl.ts
|
|
30052
30054
|
init_esm_shims();
|
|
30053
30055
|
var DEFAULT_SLOCK_SERVER_URL = "https://api.raft.build";
|
|
@@ -30148,6 +30150,8 @@ async function login(input, options = {}) {
|
|
|
30148
30150
|
JSON.stringify(
|
|
30149
30151
|
{
|
|
30150
30152
|
kind: "user-session",
|
|
30153
|
+
// On-disk schema version; readers tolerate a missing value.
|
|
30154
|
+
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
30151
30155
|
userId: r.userId,
|
|
30152
30156
|
accessToken: r.accessToken,
|
|
30153
30157
|
refreshToken: r.refreshToken,
|
|
@@ -30196,21 +30200,36 @@ async function runLogin(opts) {
|
|
|
30196
30200
|
throw err;
|
|
30197
30201
|
}
|
|
30198
30202
|
}
|
|
30203
|
+
async function runLogout() {
|
|
30204
|
+
const sessionPath = userSessionPath(resolveSlockHome());
|
|
30205
|
+
try {
|
|
30206
|
+
await unlink(sessionPath);
|
|
30207
|
+
info(`Logged out. Cleared user session at ${sessionPath}.`);
|
|
30208
|
+
} catch (err) {
|
|
30209
|
+
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
|
|
30210
|
+
info("Already logged out (no saved user session).");
|
|
30211
|
+
return;
|
|
30212
|
+
}
|
|
30213
|
+
throw err;
|
|
30214
|
+
}
|
|
30215
|
+
}
|
|
30199
30216
|
|
|
30200
30217
|
// src/attach.ts
|
|
30201
30218
|
init_esm_shims();
|
|
30202
30219
|
|
|
30203
30220
|
// src/serverState.ts
|
|
30204
30221
|
init_esm_shims();
|
|
30205
|
-
import { readFile, readdir, writeFile as writeFile2, mkdir as mkdir2, unlink, access, chmod } from "fs/promises";
|
|
30222
|
+
import { readFile, readdir, writeFile as writeFile2, mkdir as mkdir2, unlink as unlink2, access, chmod } from "fs/promises";
|
|
30206
30223
|
import { dirname as dirname2 } from "path";
|
|
30207
30224
|
import { constants as fsConstants } from "fs";
|
|
30208
30225
|
function parseAttachment(raw) {
|
|
30209
30226
|
try {
|
|
30210
30227
|
const a = JSON.parse(raw);
|
|
30211
30228
|
if (a.kind === "computer-attachment" && typeof a.serverId === "string" && typeof a.serverMachineId === "string" && typeof a.apiKey === "string" && a.apiKey.length > 0 && typeof a.serverUrl === "string") {
|
|
30229
|
+
const schemaVersion = typeof a.schemaVersion === "number" ? a.schemaVersion : CURRENT_SCHEMA_VERSION;
|
|
30212
30230
|
return {
|
|
30213
30231
|
kind: "computer-attachment",
|
|
30232
|
+
schemaVersion,
|
|
30214
30233
|
serverId: a.serverId,
|
|
30215
30234
|
serverSlug: typeof a.serverSlug === "string" && a.serverSlug.length > 0 ? a.serverSlug : void 0,
|
|
30216
30235
|
serverMachineId: a.serverMachineId,
|
|
@@ -30236,18 +30255,41 @@ async function readServerAttachment(slockHome, serverId) {
|
|
|
30236
30255
|
if (!isValidServerId(serverId)) return null;
|
|
30237
30256
|
const current = await readAttachmentAt(serverAttachmentPath(slockHome, serverId));
|
|
30238
30257
|
const legacy = await readAttachmentAt(legacyServerAttachmentPath(slockHome, serverId));
|
|
30239
|
-
|
|
30240
|
-
|
|
30241
|
-
if (
|
|
30242
|
-
|
|
30258
|
+
let effective;
|
|
30259
|
+
let decidedByLegacy;
|
|
30260
|
+
if (!current) {
|
|
30261
|
+
effective = legacy;
|
|
30262
|
+
decidedByLegacy = legacy !== null;
|
|
30263
|
+
} else if (!legacy) {
|
|
30264
|
+
effective = current;
|
|
30265
|
+
decidedByLegacy = false;
|
|
30266
|
+
} else if (
|
|
30267
|
+
// Adopted-machine-still-wins: when the legacy attachment is an adopted
|
|
30268
|
+
// (working) machine and the current one is a different, not-adopted machine
|
|
30269
|
+
// (e.g. a fresh attach that the server rejects), prefer the legacy creds.
|
|
30270
|
+
legacy.adoptedFromLegacy === true && current.adoptedFromLegacy !== true && legacy.serverMachineId !== current.serverMachineId
|
|
30271
|
+
) {
|
|
30272
|
+
effective = legacy;
|
|
30273
|
+
decidedByLegacy = true;
|
|
30274
|
+
} else {
|
|
30275
|
+
effective = current;
|
|
30276
|
+
decidedByLegacy = false;
|
|
30277
|
+
}
|
|
30278
|
+
if (decidedByLegacy && effective) {
|
|
30279
|
+
try {
|
|
30280
|
+
await writeServerAttachment(slockHome, effective);
|
|
30281
|
+
await unlink2(legacyServerAttachmentPath(slockHome, serverId));
|
|
30282
|
+
} catch {
|
|
30283
|
+
}
|
|
30243
30284
|
}
|
|
30244
|
-
return
|
|
30285
|
+
return effective;
|
|
30245
30286
|
}
|
|
30246
30287
|
async function writeServerAttachment(slockHome, attachment) {
|
|
30247
30288
|
if (!isValidServerId(attachment.serverId)) return;
|
|
30248
30289
|
const path3 = serverAttachmentPath(slockHome, attachment.serverId);
|
|
30249
30290
|
await mkdir2(dirname2(path3), { recursive: true });
|
|
30250
|
-
|
|
30291
|
+
const stamped = { ...attachment, schemaVersion: CURRENT_SCHEMA_VERSION };
|
|
30292
|
+
await writeFile2(path3, JSON.stringify(stamped, null, 2), { mode: 384 });
|
|
30251
30293
|
await chmod(path3, 384);
|
|
30252
30294
|
}
|
|
30253
30295
|
async function listAttachedServerIds(slockHome) {
|
|
@@ -30297,7 +30339,7 @@ async function setServerManaged(slockHome, serverId) {
|
|
|
30297
30339
|
async function clearServerManaged(slockHome, serverId) {
|
|
30298
30340
|
if (!isValidServerId(serverId)) return;
|
|
30299
30341
|
try {
|
|
30300
|
-
await
|
|
30342
|
+
await unlink2(serverManagedFlagPath(slockHome, serverId));
|
|
30301
30343
|
} catch {
|
|
30302
30344
|
}
|
|
30303
30345
|
}
|
|
@@ -30492,7 +30534,7 @@ async function runAttach(opts) {
|
|
|
30492
30534
|
if (opts.orchestrated) {
|
|
30493
30535
|
return;
|
|
30494
30536
|
}
|
|
30495
|
-
if (opts.
|
|
30537
|
+
if (opts.start === false) {
|
|
30496
30538
|
info("Next: run `slock-computer start` to run it in the background.");
|
|
30497
30539
|
} else {
|
|
30498
30540
|
info("Next: run `slock-computer start` (background) \u2014 closing the terminal is fine.");
|
|
@@ -31035,13 +31077,13 @@ import { fileURLToPath as fileURLToPath2 } from "url";
|
|
|
31035
31077
|
|
|
31036
31078
|
// src/cleanup.ts
|
|
31037
31079
|
init_esm_shims();
|
|
31038
|
-
import { readdir as readdir3, stat as stat3, unlink as
|
|
31080
|
+
import { readdir as readdir3, stat as stat3, unlink as unlink4, rm, rmdir, rename, mkdir as mkdir6 } from "fs/promises";
|
|
31039
31081
|
import { spawn } from "child_process";
|
|
31040
31082
|
import { join as join3 } from "path";
|
|
31041
31083
|
|
|
31042
31084
|
// src/internal/process-primitives.ts
|
|
31043
31085
|
init_esm_shims();
|
|
31044
|
-
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5, unlink as
|
|
31086
|
+
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5, unlink as unlink3 } from "fs/promises";
|
|
31045
31087
|
import { dirname as dirname5 } from "path";
|
|
31046
31088
|
async function readPidfileAt(pidfilePath) {
|
|
31047
31089
|
try {
|
|
@@ -31067,7 +31109,7 @@ async function writePidfileAt(pidfilePath, pid) {
|
|
|
31067
31109
|
}
|
|
31068
31110
|
async function clearPidfileAt(pidfilePath) {
|
|
31069
31111
|
try {
|
|
31070
|
-
await
|
|
31112
|
+
await unlink3(pidfilePath);
|
|
31071
31113
|
} catch {
|
|
31072
31114
|
}
|
|
31073
31115
|
}
|
|
@@ -31088,7 +31130,7 @@ async function cleanupStalePidfile(pidfilePath) {
|
|
|
31088
31130
|
if (pid === null) return false;
|
|
31089
31131
|
if (isProcessAlive2(pid)) return false;
|
|
31090
31132
|
try {
|
|
31091
|
-
await
|
|
31133
|
+
await unlink4(pidfilePath);
|
|
31092
31134
|
return true;
|
|
31093
31135
|
} catch {
|
|
31094
31136
|
return false;
|
|
@@ -31236,7 +31278,7 @@ async function cleanupTmpFiles(slockHome) {
|
|
|
31236
31278
|
try {
|
|
31237
31279
|
const s = await stat3(snap);
|
|
31238
31280
|
if (Date.now() - s.mtimeMs > TMP_MAX_AGE_MS) {
|
|
31239
|
-
await
|
|
31281
|
+
await unlink4(snap);
|
|
31240
31282
|
removed.push(snap);
|
|
31241
31283
|
}
|
|
31242
31284
|
} catch {
|
|
@@ -31280,7 +31322,7 @@ async function runFullCleanup(slockHome, options = {}) {
|
|
|
31280
31322
|
|
|
31281
31323
|
// src/health.ts
|
|
31282
31324
|
init_esm_shims();
|
|
31283
|
-
import { readFile as readFile6, writeFile as writeFile6, unlink as
|
|
31325
|
+
import { readFile as readFile6, writeFile as writeFile6, unlink as unlink5, mkdir as mkdir7, appendFile as appendFile2 } from "fs/promises";
|
|
31284
31326
|
import { dirname as dirname7 } from "path";
|
|
31285
31327
|
var CRASH_WINDOW_MS = 6e4;
|
|
31286
31328
|
var DEGRADED_THRESHOLD = 3;
|
|
@@ -31290,7 +31332,9 @@ async function readHealthFile(slockHome, serverId) {
|
|
|
31290
31332
|
const raw = await readFile6(serverHealthPath(slockHome, serverId), "utf8");
|
|
31291
31333
|
const parsed = JSON.parse(raw);
|
|
31292
31334
|
if (parsed && typeof parsed === "object" && Array.isArray(parsed.crashes)) {
|
|
31293
|
-
|
|
31335
|
+
const file = parsed;
|
|
31336
|
+
if (typeof file.schemaVersion !== "number") file.schemaVersion = CURRENT_SCHEMA_VERSION;
|
|
31337
|
+
return file;
|
|
31294
31338
|
}
|
|
31295
31339
|
} catch {
|
|
31296
31340
|
}
|
|
@@ -31299,7 +31343,8 @@ async function readHealthFile(slockHome, serverId) {
|
|
|
31299
31343
|
async function writeHealthFile(slockHome, serverId, file) {
|
|
31300
31344
|
const path3 = serverHealthPath(slockHome, serverId);
|
|
31301
31345
|
await mkdir7(dirname7(path3), { recursive: true });
|
|
31302
|
-
|
|
31346
|
+
const stamped = { ...file, schemaVersion: CURRENT_SCHEMA_VERSION };
|
|
31347
|
+
await writeFile6(path3, JSON.stringify(stamped), { mode: 384 });
|
|
31303
31348
|
}
|
|
31304
31349
|
async function recordCrash(slockHome, serverId, exitCode, signal, nowMs = Date.now()) {
|
|
31305
31350
|
if (!isValidServerId(serverId)) return;
|
|
@@ -31348,7 +31393,7 @@ async function markFatalConfig(slockHome, serverId, exitCode, signal, nowMs = Da
|
|
|
31348
31393
|
async function resetHealth(slockHome, serverId) {
|
|
31349
31394
|
if (!isValidServerId(serverId)) return;
|
|
31350
31395
|
try {
|
|
31351
|
-
await
|
|
31396
|
+
await unlink5(serverHealthPath(slockHome, serverId));
|
|
31352
31397
|
} catch {
|
|
31353
31398
|
}
|
|
31354
31399
|
}
|
|
@@ -31517,7 +31562,7 @@ async function waitForManagedDaemonPids(slockHome, serverIds, opts) {
|
|
|
31517
31562
|
function buildTimeoutMessage(slockHome, serverIds, ready, input) {
|
|
31518
31563
|
const missing = serverIds.filter((id) => !ready.has(id));
|
|
31519
31564
|
const target = input.serverId && missing.length === 1 ? `${input.serverLabel ?? input.serverId}` : `${missing.length} server runner(s): ${missing.join(", ")}`;
|
|
31520
|
-
return `Timed out waiting for ${target} to start. Run \`slock-computer status\` and inspect ${serviceLogPath(slockHome)} plus per-server
|
|
31565
|
+
return `Timed out waiting for ${target} to start. Run \`slock-computer status\` and inspect ${serviceLogPath(slockHome)} plus per-server runner logs under ~/.slock/computer/servers/<serverId>/runner.log.`;
|
|
31521
31566
|
}
|
|
31522
31567
|
async function start(input, options = {}) {
|
|
31523
31568
|
options.signal?.throwIfAborted?.();
|
|
@@ -31837,7 +31882,7 @@ async function detach(input, options = {}) {
|
|
|
31837
31882
|
// src/upgradeSea.ts
|
|
31838
31883
|
init_esm_shims();
|
|
31839
31884
|
import { createHash as createHash3 } from "crypto";
|
|
31840
|
-
import { chmod as chmod4, mkdir as mkdir9, readFile as readFile8, rename as rename2, rm as rm2, writeFile as writeFile8 } from "fs/promises";
|
|
31885
|
+
import { access as access2, chmod as chmod4, mkdir as mkdir9, readFile as readFile8, rename as rename2, rm as rm2, writeFile as writeFile8 } from "fs/promises";
|
|
31841
31886
|
import { join as join4 } from "path";
|
|
31842
31887
|
|
|
31843
31888
|
// src/channel.ts
|
|
@@ -31993,6 +32038,24 @@ async function swapSeaPhase(currentBinaryPath, stagedBinaryPath) {
|
|
|
31993
32038
|
}
|
|
31994
32039
|
return { prevBinaryPath, currentBinaryPath };
|
|
31995
32040
|
}
|
|
32041
|
+
async function rollbackSeaSwap(swap) {
|
|
32042
|
+
await rm2(swap.currentBinaryPath, { force: true });
|
|
32043
|
+
await rename2(swap.prevBinaryPath, swap.currentBinaryPath);
|
|
32044
|
+
await chmod4(swap.currentBinaryPath, 493);
|
|
32045
|
+
}
|
|
32046
|
+
function seaPrevBinaryPath(currentBinaryPath) {
|
|
32047
|
+
return `${currentBinaryPath}.prev`;
|
|
32048
|
+
}
|
|
32049
|
+
async function rollbackToPrev(currentBinaryPath) {
|
|
32050
|
+
const prevBinaryPath = seaPrevBinaryPath(currentBinaryPath);
|
|
32051
|
+
try {
|
|
32052
|
+
await access2(prevBinaryPath);
|
|
32053
|
+
} catch {
|
|
32054
|
+
throw new Error("UPGRADE_NO_ROLLBACK");
|
|
32055
|
+
}
|
|
32056
|
+
await rollbackSeaSwap({ prevBinaryPath, currentBinaryPath });
|
|
32057
|
+
return { restoredFrom: prevBinaryPath, currentBinaryPath };
|
|
32058
|
+
}
|
|
31996
32059
|
function pendingUpgradeMarkerPath(slockHome) {
|
|
31997
32060
|
return join4(slockHome, "upgrade-pending.json");
|
|
31998
32061
|
}
|
|
@@ -32000,7 +32063,8 @@ async function writePendingUpgradeMarker(slockHome, marker) {
|
|
|
32000
32063
|
const path3 = pendingUpgradeMarkerPath(slockHome);
|
|
32001
32064
|
const tmp = `${path3}.tmp`;
|
|
32002
32065
|
await mkdir9(slockHome, { recursive: true });
|
|
32003
|
-
|
|
32066
|
+
const stamped = { ...marker, schemaVersion: CURRENT_SCHEMA_VERSION };
|
|
32067
|
+
await writeFile8(tmp, `${JSON.stringify(stamped, null, 2)}
|
|
32004
32068
|
`, "utf8");
|
|
32005
32069
|
await rename2(tmp, path3);
|
|
32006
32070
|
}
|
|
@@ -32009,7 +32073,8 @@ async function readPendingUpgradeMarker(slockHome) {
|
|
|
32009
32073
|
const raw = await readFile8(pendingUpgradeMarkerPath(slockHome), "utf8");
|
|
32010
32074
|
const parsed = JSON.parse(raw);
|
|
32011
32075
|
if (typeof parsed.requestId === "string" && typeof parsed.targetVersion === "string" && typeof parsed.fromVersion === "string" && typeof parsed.startedAt === "string") {
|
|
32012
|
-
|
|
32076
|
+
const schemaVersion = typeof parsed.schemaVersion === "number" ? parsed.schemaVersion : CURRENT_SCHEMA_VERSION;
|
|
32077
|
+
return { ...parsed, schemaVersion };
|
|
32013
32078
|
}
|
|
32014
32079
|
return null;
|
|
32015
32080
|
} catch {
|
|
@@ -32128,7 +32193,7 @@ async function resolveAndRunSeaUpgrade(opts) {
|
|
|
32128
32193
|
// src/internal/ipc-server.ts
|
|
32129
32194
|
init_esm_shims();
|
|
32130
32195
|
import { connect, createServer } from "net";
|
|
32131
|
-
import { chmod as chmod5, mkdir as mkdir10, stat as stat4, unlink as
|
|
32196
|
+
import { chmod as chmod5, mkdir as mkdir10, stat as stat4, unlink as unlink6 } from "fs/promises";
|
|
32132
32197
|
import { dirname as dirname9 } from "path";
|
|
32133
32198
|
|
|
32134
32199
|
// src/internal/ipc-codec.ts
|
|
@@ -32239,7 +32304,7 @@ async function probeAndClearStaleSocket(socketPath) {
|
|
|
32239
32304
|
return;
|
|
32240
32305
|
}
|
|
32241
32306
|
try {
|
|
32242
|
-
await
|
|
32307
|
+
await unlink6(socketPath);
|
|
32243
32308
|
} catch (err) {
|
|
32244
32309
|
if (isErrnoException(err) && err.code === "ENOENT") return;
|
|
32245
32310
|
throw err;
|
|
@@ -32505,12 +32570,8 @@ async function buildStatusReport(installRoot) {
|
|
|
32505
32570
|
function pad(s, n) {
|
|
32506
32571
|
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
32507
32572
|
}
|
|
32508
|
-
async function runStatus(
|
|
32573
|
+
async function runStatus() {
|
|
32509
32574
|
const report = await buildStatusReport(resolveSlockHome());
|
|
32510
|
-
if (opts.json) {
|
|
32511
|
-
info(JSON.stringify(report, null, 2));
|
|
32512
|
-
return;
|
|
32513
|
-
}
|
|
32514
32575
|
info("");
|
|
32515
32576
|
info(`SLOCK_HOME: ${report.slockHome}`);
|
|
32516
32577
|
const loginDetail = report.userSessionError ? "no \u2014 user session file is invalid; re-run `slock-computer login`" : report.loggedIn ? `yes (user ${report.userId ?? "?"})` : "no \u2014 run `slock-computer login`";
|
|
@@ -32635,6 +32696,7 @@ function isServiceState(value) {
|
|
|
32635
32696
|
|
|
32636
32697
|
// src/serviceState.ts
|
|
32637
32698
|
var DEFAULT_STATE = {
|
|
32699
|
+
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
32638
32700
|
state: "running",
|
|
32639
32701
|
crashHistory: []
|
|
32640
32702
|
};
|
|
@@ -32644,9 +32706,10 @@ async function readServiceState(slockHome) {
|
|
|
32644
32706
|
const parsed = JSON.parse(raw);
|
|
32645
32707
|
if (!parsed || typeof parsed !== "object") return { ...DEFAULT_STATE };
|
|
32646
32708
|
const obj = parsed;
|
|
32709
|
+
const schemaVersion = typeof obj.schemaVersion === "number" ? obj.schemaVersion : CURRENT_SCHEMA_VERSION;
|
|
32647
32710
|
const state = isServiceState(obj.state) ? obj.state : "running";
|
|
32648
32711
|
const crashHistory = Array.isArray(obj.crashHistory) ? obj.crashHistory.filter(isCrashEntry) : [];
|
|
32649
|
-
return { state, crashHistory };
|
|
32712
|
+
return { schemaVersion, state, crashHistory };
|
|
32650
32713
|
} catch {
|
|
32651
32714
|
return { ...DEFAULT_STATE };
|
|
32652
32715
|
}
|
|
@@ -32654,7 +32717,8 @@ async function readServiceState(slockHome) {
|
|
|
32654
32717
|
async function writeServiceState(slockHome, file) {
|
|
32655
32718
|
const path3 = serviceStatePath(slockHome);
|
|
32656
32719
|
await mkdir11(dirname10(path3), { recursive: true });
|
|
32657
|
-
|
|
32720
|
+
const stamped = { ...file, schemaVersion: CURRENT_SCHEMA_VERSION };
|
|
32721
|
+
await writeFile9(path3, JSON.stringify(stamped), { mode: 384 });
|
|
32658
32722
|
}
|
|
32659
32723
|
function isCrashEntry(value) {
|
|
32660
32724
|
if (!value || typeof value !== "object") return false;
|
|
@@ -32738,7 +32802,7 @@ async function resolveTargetServerId(opts) {
|
|
|
32738
32802
|
if (attachments.length === 1) return attachments[0].serverId;
|
|
32739
32803
|
fail(
|
|
32740
32804
|
"AMBIGUOUS_SERVER",
|
|
32741
|
-
`Multiple servers attached (${attachments.map(attachmentLabel).join(", ")}). Pass
|
|
32805
|
+
`Multiple servers attached (${attachments.map(attachmentLabel).join(", ")}). Pass the server slug positionally (e.g. \`${attachmentLabel(attachments[0])}\`) to choose one.`
|
|
32742
32806
|
);
|
|
32743
32807
|
}
|
|
32744
32808
|
async function resolveTargetAttachment(opts) {
|
|
@@ -33028,17 +33092,13 @@ async function runReset(opts) {
|
|
|
33028
33092
|
(client) => client.request("reset-service", void 0),
|
|
33029
33093
|
() => resetService(slockHome)
|
|
33030
33094
|
);
|
|
33031
|
-
if (opts.json) {
|
|
33032
|
-
info(JSON.stringify(result2));
|
|
33033
|
-
return;
|
|
33034
|
-
}
|
|
33035
33095
|
info(
|
|
33036
33096
|
`Reset service crash history (previous state: ${result2.previousState}; cleared ${result2.clearedCrashCount} entr${result2.clearedCrashCount === 1 ? "y" : "ies"}).`
|
|
33037
33097
|
);
|
|
33038
33098
|
info("Service state transitioned to `running`. Runners were not touched.");
|
|
33039
33099
|
return;
|
|
33040
33100
|
}
|
|
33041
|
-
const serverId = await resolveTargetServerId({ server: opts.
|
|
33101
|
+
const serverId = await resolveTargetServerId({ server: opts.serverSlug });
|
|
33042
33102
|
const result = await resetViaServiceOrDisk(
|
|
33043
33103
|
slockHome,
|
|
33044
33104
|
(client) => client.request("reset-runner", { serverId }),
|
|
@@ -33050,10 +33110,6 @@ async function runReset(opts) {
|
|
|
33050
33110
|
`Runner for server ${serverId} was not found.`
|
|
33051
33111
|
);
|
|
33052
33112
|
}
|
|
33053
|
-
if (opts.json) {
|
|
33054
|
-
info(JSON.stringify(result));
|
|
33055
|
-
return;
|
|
33056
|
-
}
|
|
33057
33113
|
info(
|
|
33058
33114
|
`Reset runner crash history for server ${result.serverId} (previous state: ${result.previousState}; cleared ${result.clearedCrashCount} entr${result.clearedCrashCount === 1 ? "y" : "ies"}).`
|
|
33059
33115
|
);
|
|
@@ -33626,7 +33682,7 @@ async function runStart(opts = {}, deps = {}) {
|
|
|
33626
33682
|
info(
|
|
33627
33683
|
`Managing ${sb.managedCount} of ${sb.attachedCount} attached server(s). Logs: ${sb.logPath}`
|
|
33628
33684
|
);
|
|
33629
|
-
info(`Per-server
|
|
33685
|
+
info(`Per-server runner logs: ~/.slock/computer/servers/<serverId>/runner.log`);
|
|
33630
33686
|
info(`Check state with \`slock-computer status\`.`);
|
|
33631
33687
|
}
|
|
33632
33688
|
}
|
|
@@ -33747,6 +33803,8 @@ async function refreshUserSession(slockHome, serverUrl) {
|
|
|
33747
33803
|
JSON.stringify(
|
|
33748
33804
|
{
|
|
33749
33805
|
kind: "user-session",
|
|
33806
|
+
// Stamp the current on-disk schema version on every write.
|
|
33807
|
+
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
33750
33808
|
userId: session.userId,
|
|
33751
33809
|
accessToken: body.accessToken,
|
|
33752
33810
|
refreshToken: body.refreshToken,
|
|
@@ -34046,7 +34104,7 @@ async function runSetup(opts, deps = {}) {
|
|
|
34046
34104
|
serverSlug: opts.serverSlug,
|
|
34047
34105
|
serverUrl: opts.serverUrl,
|
|
34048
34106
|
name: opts.name,
|
|
34049
|
-
|
|
34107
|
+
start: false,
|
|
34050
34108
|
orchestrated: true
|
|
34051
34109
|
});
|
|
34052
34110
|
}
|
|
@@ -34089,16 +34147,6 @@ async function runRunnersList(opts) {
|
|
|
34089
34147
|
`Could not list runners on ${label} (${block.code}). Check --server-url / server version.`
|
|
34090
34148
|
);
|
|
34091
34149
|
}
|
|
34092
|
-
if (opts.json) {
|
|
34093
|
-
info(
|
|
34094
|
-
JSON.stringify(
|
|
34095
|
-
{ server: label, serverId: block.serverId, whitelist: block.whitelist, runners: block.runners },
|
|
34096
|
-
null,
|
|
34097
|
-
2
|
|
34098
|
-
)
|
|
34099
|
-
);
|
|
34100
|
-
return;
|
|
34101
|
-
}
|
|
34102
34150
|
if (block.runners.length === 0) {
|
|
34103
34151
|
info(`No runners on server ${label}.`);
|
|
34104
34152
|
return;
|
|
@@ -34115,7 +34163,7 @@ async function runRunnersList(opts) {
|
|
|
34115
34163
|
}
|
|
34116
34164
|
async function runRunnersStop(agentId, opts = {}) {
|
|
34117
34165
|
if (!agentId || agentId.trim().length === 0) {
|
|
34118
|
-
fail("AGENT_ID_REQUIRED", "Usage: slock-computer runners stop <agentId> [
|
|
34166
|
+
fail("AGENT_ID_REQUIRED", "Usage: slock-computer runners stop <agentId> [serverSlug]");
|
|
34119
34167
|
}
|
|
34120
34168
|
const a = await resolveTargetAttachment({ server: opts.server });
|
|
34121
34169
|
const client = new RunnersClient(a.serverUrl, a.apiKey);
|
|
@@ -34217,14 +34265,6 @@ async function runDoctor(opts) {
|
|
|
34217
34265
|
if (opts.serverId) {
|
|
34218
34266
|
crashes = await readCrashHistory(slockHome, opts.serverId);
|
|
34219
34267
|
}
|
|
34220
|
-
if (opts.json) {
|
|
34221
|
-
const payload = { ok: allOk, checks };
|
|
34222
|
-
if (cleanupReport) payload.cleanup = cleanupReport;
|
|
34223
|
-
if (crashes.length > 0) payload.crashes = crashes;
|
|
34224
|
-
info(redactSecrets(JSON.stringify(payload, null, 2)));
|
|
34225
|
-
process.exitCode = allOk ? 0 : 1;
|
|
34226
|
-
return;
|
|
34227
|
-
}
|
|
34228
34268
|
info("");
|
|
34229
34269
|
for (const c of checks) {
|
|
34230
34270
|
info(redactSecrets(`${c.ok ? "\u2713" : "\u2717"} ${c.name.padEnd(48)} ${c.detail}`));
|
|
@@ -34240,7 +34280,7 @@ async function runDoctor(opts) {
|
|
|
34240
34280
|
info(` - ${c.at}${code}${sig}`);
|
|
34241
34281
|
}
|
|
34242
34282
|
info(` \u2192 Once you fix the underlying issue, run`);
|
|
34243
|
-
info(` \`slock-computer reset --runner
|
|
34283
|
+
info(` \`slock-computer reset --runner ${opts.serverLabel ?? opts.serverId}\` to resume auto-restart.`);
|
|
34244
34284
|
}
|
|
34245
34285
|
if (cleanupReport) {
|
|
34246
34286
|
info("");
|
|
@@ -34431,6 +34471,32 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
|
34431
34471
|
"`slock-computer upgrade` self-upgrades the SEA single-binary; this run is not a SEA binary (npm-installed or source/dev). Re-install the SEA binary to upgrade: `curl -fsSL https://github.com/botiverse/slock/releases/latest/download/install.sh | sh`."
|
|
34432
34472
|
);
|
|
34433
34473
|
}
|
|
34474
|
+
if (opts.rollback) {
|
|
34475
|
+
if (opts.targetVersion !== void 0 || opts.channel !== void 0 || opts.dryRun) {
|
|
34476
|
+
fail(
|
|
34477
|
+
"UPGRADE_ROLLBACK_CONFLICT",
|
|
34478
|
+
"`--rollback` cannot be combined with --target-version, --channel, or --dry-run. Rollback restores the previous binary and resolves/downloads nothing."
|
|
34479
|
+
);
|
|
34480
|
+
}
|
|
34481
|
+
const currentBinaryPath2 = (deps.currentBinaryPath ?? (() => process.execPath))();
|
|
34482
|
+
const rollbackFn = deps.rollbackToPrevFn ?? rollbackToPrev;
|
|
34483
|
+
try {
|
|
34484
|
+
const r = await rollbackFn(currentBinaryPath2);
|
|
34485
|
+
info(
|
|
34486
|
+
`Rolled back: restored the previous binary from ${r.restoredFrom}. Restart the Computer service to run the restored binary (the managed supervisor does this automatically).`
|
|
34487
|
+
);
|
|
34488
|
+
} catch (e) {
|
|
34489
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
34490
|
+
if (/UPGRADE_NO_ROLLBACK/.test(msg)) {
|
|
34491
|
+
fail(
|
|
34492
|
+
"UPGRADE_NO_ROLLBACK",
|
|
34493
|
+
"Nothing to roll back: no previous binary (`<exe>.prev`) exists. A rollback target is only kept after a successful upgrade swap."
|
|
34494
|
+
);
|
|
34495
|
+
}
|
|
34496
|
+
fail("UPGRADE_SWAP_FAILED", `Rollback failed: ${msg}.`);
|
|
34497
|
+
}
|
|
34498
|
+
return;
|
|
34499
|
+
}
|
|
34434
34500
|
let channel2;
|
|
34435
34501
|
if (opts.channel !== void 0) {
|
|
34436
34502
|
const parsed = parseChannel(opts.channel);
|
|
@@ -34604,9 +34670,12 @@ program2.name("slock-computer").description("Slock Computer \u2014 local-machine
|
|
|
34604
34670
|
program2.command("login").description("Log in via device-code (one user identity per Computer / SLOCK_HOME).").option("--server-url <url>", `Slock API base URL; defaults to SLOCK_SERVER_URL or ${DEFAULT_SLOCK_SERVER_URL}`).action(withCliExit(async (opts) => {
|
|
34605
34671
|
await runLogin({ serverUrl: opts.serverUrl });
|
|
34606
34672
|
}));
|
|
34607
|
-
program2.command("
|
|
34673
|
+
program2.command("logout").description("Log out (clear the saved user session for this Computer); per-server attachments are untouched.").action(withCliExit(async () => {
|
|
34674
|
+
await runLogout();
|
|
34675
|
+
}));
|
|
34676
|
+
program2.command("attach").argument("<serverSlug>", SERVER_SLUG_TARGET_DESC).description("Attach this Computer to one Slock server (add-not-replace; multi-server OK).").option("--server-url <url>", `Slock API base URL; defaults to the saved user session, SLOCK_SERVER_URL, or ${DEFAULT_SLOCK_SERVER_URL}`).option("--name <name>", "Computer display name; defaults to a sanitized hostname").option("--no-start", "only authorize + write local state; do not start the service").option("--foreground", FOREGROUND_DESC).action(withCliExit(async (serverSlug, opts) => {
|
|
34608
34677
|
await withMutationLock(
|
|
34609
|
-
() => runAttach({ serverSlug, serverUrl: opts.serverUrl, name: opts.name,
|
|
34678
|
+
() => runAttach({ serverSlug, serverUrl: opts.serverUrl, name: opts.name, start: opts.start, foreground: opts.foreground })
|
|
34610
34679
|
);
|
|
34611
34680
|
}));
|
|
34612
34681
|
program2.command("setup").argument("<serverSlug>", SERVER_SLUG_TARGET_DESC).description("Set up this Computer for one server: login if needed, attach (or \xA7X.1 migrate-prompt) if needed, then start.").option("--server-url <url>", `Slock API base URL; defaults to the saved user session, SLOCK_SERVER_URL, or ${DEFAULT_SLOCK_SERVER_URL}`).option("--name <name>", "Computer display name for a new attachment; defaults to a sanitized hostname").option("--no-start", "stop after login + attach; do not start the service").option("--foreground", FOREGROUND_DESC).option("-y, --yes", "allow non-interactive setup after confirming the planned actions").action(
|
|
@@ -34626,10 +34695,10 @@ program2.command("setup").argument("<serverSlug>", SERVER_SLUG_TARGET_DESC).desc
|
|
|
34626
34695
|
program2.command("detach").argument("<serverSlug>", `${SERVER_SLUG_TARGET_DESC} (the server to detach from this Computer)`).description("Remove ONE server's local attachment; never touches user-session or other servers.").action(withCliExit(async (serverSlug) => {
|
|
34627
34696
|
await withMutationLock(async () => runDetach(await resolveTargetServerId({ server: serverSlug }), serverSlug));
|
|
34628
34697
|
}));
|
|
34629
|
-
program2.command("status").description("Show this Computer's aggregate state (login + service + per-server
|
|
34630
|
-
await runStatus(
|
|
34698
|
+
program2.command("status").description("Show this Computer's aggregate state (login + service + per-server runners).").action(withCliExit(async () => {
|
|
34699
|
+
await runStatus();
|
|
34631
34700
|
}));
|
|
34632
|
-
program2.command("start").argument("[serverSlug]", SERVER_SLUG_OPTIONAL_DESC).description("Start/ensure the Computer service (manages all per-server
|
|
34701
|
+
program2.command("start").argument("[serverSlug]", SERVER_SLUG_OPTIONAL_DESC).description("Start/ensure the Computer service (manages all per-server runners).").option("--foreground", FOREGROUND_DESC).action(withCliExit(async (serverSlug, opts) => {
|
|
34633
34702
|
await withMutationLock(
|
|
34634
34703
|
async () => runStart({
|
|
34635
34704
|
foreground: opts.foreground,
|
|
@@ -34638,10 +34707,10 @@ program2.command("start").argument("[serverSlug]", SERVER_SLUG_OPTIONAL_DESC).de
|
|
|
34638
34707
|
})
|
|
34639
34708
|
);
|
|
34640
34709
|
}));
|
|
34641
|
-
program2.command("stop").description("Stop the Computer service (and all managed per-server
|
|
34710
|
+
program2.command("stop").description("Stop the Computer service (and all managed per-server runners).").action(withCliExit(async () => {
|
|
34642
34711
|
await withMutationLock(() => runStop());
|
|
34643
34712
|
}));
|
|
34644
|
-
program2.command("restart").argument("[serverSlug]", SERVER_SLUG_OPTIONAL_DESC).description("Restart the Computer service (stop + start; all managed per-server
|
|
34713
|
+
program2.command("restart").argument("[serverSlug]", SERVER_SLUG_OPTIONAL_DESC).description("Restart the Computer service (stop + start; all managed per-server runners).").option("--foreground", FOREGROUND_DESC).action(withCliExit(async (serverSlug, opts) => {
|
|
34645
34714
|
await withMutationLock(async () => {
|
|
34646
34715
|
await runStop();
|
|
34647
34716
|
await runStart({
|
|
@@ -34651,12 +34720,11 @@ program2.command("restart").argument("[serverSlug]", SERVER_SLUG_OPTIONAL_DESC).
|
|
|
34651
34720
|
});
|
|
34652
34721
|
});
|
|
34653
34722
|
}));
|
|
34654
|
-
program2.command("doctor").argument("[serverSlug]", `${SERVER_SLUG_OPTIONAL_DESC} (scopes recent-crash detail to that server)`).description("Diagnose login + per-server attachments + per-server preflight (no secrets).").option("--
|
|
34723
|
+
program2.command("doctor").argument("[serverSlug]", `${SERVER_SLUG_OPTIONAL_DESC} (scopes recent-crash detail to that server)`).description("Diagnose login + per-server attachments + per-server preflight (no secrets).").option("--fix", "after diagnosis, run the local residue cleanup pass").action(
|
|
34655
34724
|
withCliExit(
|
|
34656
34725
|
async (serverSlug, opts) => {
|
|
34657
34726
|
const serverId = serverSlug ? await resolveTargetServerId({ server: serverSlug }) : void 0;
|
|
34658
34727
|
await runDoctor({
|
|
34659
|
-
json: opts.json,
|
|
34660
34728
|
cleanup: opts.fix,
|
|
34661
34729
|
serverId,
|
|
34662
34730
|
serverLabel: serverSlug
|
|
@@ -34664,27 +34732,26 @@ program2.command("doctor").argument("[serverSlug]", `${SERVER_SLUG_OPTIONAL_DESC
|
|
|
34664
34732
|
}
|
|
34665
34733
|
)
|
|
34666
34734
|
);
|
|
34667
|
-
program2.command("reset").description("Clear a degraded state and resume the service's auto-restart loop.").option("--service", "clear the service-level crash history (cascade record)").option("--runner", "clear a runner's crash history (selected by
|
|
34668
|
-
withCliExit(async (opts) => {
|
|
34735
|
+
program2.command("reset").argument("[serverSlug]", `${SERVER_SLUG_OPTIONAL_DESC} (with \`--runner\`, selects the target runner)`).description("Clear a degraded state and resume the service's auto-restart loop.").option("--service", "clear the service-level crash history (cascade record)").option("--runner", "clear a runner's crash history (selected by the [serverSlug] positional)").action(
|
|
34736
|
+
withCliExit(async (serverSlug, opts) => {
|
|
34669
34737
|
await withMutationLock(
|
|
34670
34738
|
() => runReset({
|
|
34671
34739
|
service: opts.service,
|
|
34672
34740
|
runner: opts.runner,
|
|
34673
|
-
|
|
34674
|
-
json: opts.json
|
|
34741
|
+
serverSlug
|
|
34675
34742
|
})
|
|
34676
34743
|
);
|
|
34677
34744
|
})
|
|
34678
34745
|
);
|
|
34679
|
-
program2.command("logs").argument("[serverSlug]", `${SERVER_SLUG_OPTIONAL_DESC} (required when \u22652 attached; ignored with --service)`).description("Tail one server's
|
|
34746
|
+
program2.command("logs").argument("[serverSlug]", `${SERVER_SLUG_OPTIONAL_DESC} (required when \u22652 attached; ignored with --service)`).description("Tail one server's runner log (or the service log); secrets redacted.").option("--lines <n>", "trailing lines to show (default 200)", (v) => Number.parseInt(v, 10)).option("--service", "tail the global service log instead of a per-server runner log").action(withCliExit(async (serverSlug, opts) => {
|
|
34680
34747
|
await runLogs({ lines: opts.lines, server: serverSlug ?? null, service: !!opts.service });
|
|
34681
34748
|
}));
|
|
34682
34749
|
var runners = program2.command("runners").description("Computer runner control plane (per-server scoped; \xA712 whitelist server-side).");
|
|
34683
|
-
runners.command("list").
|
|
34684
|
-
await runRunnersList({
|
|
34750
|
+
runners.command("list").argument("[serverSlug]", `${SERVER_SLUG_OPTIONAL_DESC} (required when \u22652 attached)`).description("List runners on one attached server.").action(withCliExit(async (serverSlug) => {
|
|
34751
|
+
await runRunnersList({ server: serverSlug ?? null });
|
|
34685
34752
|
}));
|
|
34686
|
-
runners.command("stop").argument("<agentId>", "id of the runner to stop").
|
|
34687
|
-
await withMutationLock(() => runRunnersStop(agentId, { server:
|
|
34753
|
+
runners.command("stop").argument("<agentId>", "id of the runner to stop").argument("[serverSlug]", `${SERVER_SLUG_OPTIONAL_DESC} (required when \u22652 attached)`).description("Stop a runner (server-mediated; reuses the orchestrator's agent stop).").action(withCliExit(async (agentId, serverSlug) => {
|
|
34754
|
+
await withMutationLock(() => runRunnersStop(agentId, { server: serverSlug ?? null }));
|
|
34688
34755
|
}));
|
|
34689
34756
|
var channel = program2.command("channel").description("Show or set the Computer release channel (latest | alpha | pinned:<semver>).");
|
|
34690
34757
|
channel.command("show").description("Show the current Computer release channel (default `latest` when unset).").action(
|
|
@@ -34706,12 +34773,15 @@ program2.command("upgrade").description(
|
|
|
34706
34773
|
"supervisor restarts on the swapped binary. SEA-only: a non-SEA (npm/dev)",
|
|
34707
34774
|
"run has no single binary to self-swap and is refused (UPGRADE_SEA_ONLY)."
|
|
34708
34775
|
].join("\n")
|
|
34709
|
-
).option("--dry-run", "download + sha256-verify only; do not swap or restart").option("--channel <name>", "override channel for this invocation (latest | alpha | pinned:<semver>)").option("--target-version <semver>", "override target version explicitly (bypasses channel resolution)").
|
|
34776
|
+
).option("--dry-run", "download + sha256-verify only; do not swap or restart").option("--channel <name>", "override channel for this invocation (latest | alpha | pinned:<semver>)").option("--target-version <semver>", "override target version explicitly (bypasses channel resolution)").option(
|
|
34777
|
+
"--rollback",
|
|
34778
|
+
"restore the previous binary (<exe>.prev) from the last successful upgrade; mutually exclusive with --target-version/--channel/--dry-run"
|
|
34779
|
+
).action(
|
|
34710
34780
|
withCliExit(
|
|
34711
34781
|
async (opts) => {
|
|
34712
34782
|
const slockHome = resolveSlockHome();
|
|
34713
34783
|
const trigger = resolveUpgradeTrigger(process.env.SLOCK_UPGRADE_TRIGGER);
|
|
34714
|
-
if (!opts.dryRun && !opts.channel) {
|
|
34784
|
+
if (!opts.dryRun && !opts.channel && !opts.rollback) {
|
|
34715
34785
|
let client = null;
|
|
34716
34786
|
try {
|
|
34717
34787
|
client = await connectService(slockHome);
|
|
@@ -34742,6 +34812,7 @@ program2.command("upgrade").description(
|
|
|
34742
34812
|
dryRun: opts.dryRun,
|
|
34743
34813
|
channel: opts.channel,
|
|
34744
34814
|
targetVersion: opts.targetVersion,
|
|
34815
|
+
rollback: opts.rollback,
|
|
34745
34816
|
trigger
|
|
34746
34817
|
})
|
|
34747
34818
|
);
|
package/dist/lib/index.js
CHANGED
|
@@ -333,6 +333,7 @@ import { constants as fsConstants } from "fs";
|
|
|
333
333
|
import { createHash } from "crypto";
|
|
334
334
|
import os from "os";
|
|
335
335
|
import path from "path";
|
|
336
|
+
var CURRENT_SCHEMA_VERSION = 1;
|
|
336
337
|
function computerDir(slockHome) {
|
|
337
338
|
return path.join(slockHome, "computer");
|
|
338
339
|
}
|
|
@@ -362,10 +363,10 @@ function legacyServerAttachmentPath(slockHome, serverId) {
|
|
|
362
363
|
return path.join(serverDir(slockHome, serverId), "attachment.json");
|
|
363
364
|
}
|
|
364
365
|
function serverRunnerPidPath(slockHome, serverId) {
|
|
365
|
-
return path.join(serverDir(slockHome, serverId), "
|
|
366
|
+
return path.join(serverDir(slockHome, serverId), "runner.pid");
|
|
366
367
|
}
|
|
367
368
|
function serverRunnerLogPath(slockHome, serverId) {
|
|
368
|
-
return path.join(serverDir(slockHome, serverId), "
|
|
369
|
+
return path.join(serverDir(slockHome, serverId), "runner.log");
|
|
369
370
|
}
|
|
370
371
|
function serverHealthPath(slockHome, serverId) {
|
|
371
372
|
return path.join(serverDir(slockHome, serverId), "health.json");
|
|
@@ -388,8 +389,10 @@ function parseAttachment(raw) {
|
|
|
388
389
|
try {
|
|
389
390
|
const a = JSON.parse(raw);
|
|
390
391
|
if (a.kind === "computer-attachment" && typeof a.serverId === "string" && typeof a.serverMachineId === "string" && typeof a.apiKey === "string" && a.apiKey.length > 0 && typeof a.serverUrl === "string") {
|
|
392
|
+
const schemaVersion = typeof a.schemaVersion === "number" ? a.schemaVersion : CURRENT_SCHEMA_VERSION;
|
|
391
393
|
return {
|
|
392
394
|
kind: "computer-attachment",
|
|
395
|
+
schemaVersion,
|
|
393
396
|
serverId: a.serverId,
|
|
394
397
|
serverSlug: typeof a.serverSlug === "string" && a.serverSlug.length > 0 ? a.serverSlug : void 0,
|
|
395
398
|
serverMachineId: a.serverMachineId,
|
|
@@ -415,12 +418,42 @@ async function readServerAttachment(slockHome, serverId) {
|
|
|
415
418
|
if (!isValidServerId(serverId)) return null;
|
|
416
419
|
const current = await readAttachmentAt(serverAttachmentPath(slockHome, serverId));
|
|
417
420
|
const legacy = await readAttachmentAt(legacyServerAttachmentPath(slockHome, serverId));
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if (
|
|
421
|
-
|
|
421
|
+
let effective;
|
|
422
|
+
let decidedByLegacy;
|
|
423
|
+
if (!current) {
|
|
424
|
+
effective = legacy;
|
|
425
|
+
decidedByLegacy = legacy !== null;
|
|
426
|
+
} else if (!legacy) {
|
|
427
|
+
effective = current;
|
|
428
|
+
decidedByLegacy = false;
|
|
429
|
+
} else if (
|
|
430
|
+
// Adopted-machine-still-wins: when the legacy attachment is an adopted
|
|
431
|
+
// (working) machine and the current one is a different, not-adopted machine
|
|
432
|
+
// (e.g. a fresh attach that the server rejects), prefer the legacy creds.
|
|
433
|
+
legacy.adoptedFromLegacy === true && current.adoptedFromLegacy !== true && legacy.serverMachineId !== current.serverMachineId
|
|
434
|
+
) {
|
|
435
|
+
effective = legacy;
|
|
436
|
+
decidedByLegacy = true;
|
|
437
|
+
} else {
|
|
438
|
+
effective = current;
|
|
439
|
+
decidedByLegacy = false;
|
|
422
440
|
}
|
|
423
|
-
|
|
441
|
+
if (decidedByLegacy && effective) {
|
|
442
|
+
try {
|
|
443
|
+
await writeServerAttachment(slockHome, effective);
|
|
444
|
+
await unlink(legacyServerAttachmentPath(slockHome, serverId));
|
|
445
|
+
} catch {
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return effective;
|
|
449
|
+
}
|
|
450
|
+
async function writeServerAttachment(slockHome, attachment) {
|
|
451
|
+
if (!isValidServerId(attachment.serverId)) return;
|
|
452
|
+
const path2 = serverAttachmentPath(slockHome, attachment.serverId);
|
|
453
|
+
await mkdir(dirname(path2), { recursive: true });
|
|
454
|
+
const stamped = { ...attachment, schemaVersion: CURRENT_SCHEMA_VERSION };
|
|
455
|
+
await writeFile(path2, JSON.stringify(stamped, null, 2), { mode: 384 });
|
|
456
|
+
await chmod(path2, 384);
|
|
424
457
|
}
|
|
425
458
|
async function listAttachedServerIds(slockHome) {
|
|
426
459
|
let entries;
|
|
@@ -450,6 +483,9 @@ async function listServerAttachments(slockHome) {
|
|
|
450
483
|
import { chmod as chmod2, mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
451
484
|
import { dirname as dirname2 } from "path";
|
|
452
485
|
|
|
486
|
+
// src/login.ts
|
|
487
|
+
import { unlink as unlink2 } from "fs/promises";
|
|
488
|
+
|
|
453
489
|
// src/services/login.ts
|
|
454
490
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
455
491
|
import { dirname as dirname3 } from "path";
|
|
@@ -485,12 +521,12 @@ import { dirname as dirname10, join as joinPath } from "path";
|
|
|
485
521
|
import { fileURLToPath } from "url";
|
|
486
522
|
|
|
487
523
|
// src/cleanup.ts
|
|
488
|
-
import { readdir as readdir3, stat as stat3, unlink as
|
|
524
|
+
import { readdir as readdir3, stat as stat3, unlink as unlink4, rm, rmdir, rename, mkdir as mkdir6 } from "fs/promises";
|
|
489
525
|
import { spawn } from "child_process";
|
|
490
526
|
import { join as join3 } from "path";
|
|
491
527
|
|
|
492
528
|
// src/internal/process-primitives.ts
|
|
493
|
-
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5, unlink as
|
|
529
|
+
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5, unlink as unlink3 } from "fs/promises";
|
|
494
530
|
import { dirname as dirname5 } from "path";
|
|
495
531
|
async function readPidfileAt(pidfilePath) {
|
|
496
532
|
try {
|
|
@@ -515,7 +551,7 @@ function isProcessAlive(pid) {
|
|
|
515
551
|
var TMP_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
516
552
|
|
|
517
553
|
// src/health.ts
|
|
518
|
-
import { readFile as readFile6, writeFile as writeFile6, unlink as
|
|
554
|
+
import { readFile as readFile6, writeFile as writeFile6, unlink as unlink5, mkdir as mkdir7, appendFile as appendFile2 } from "fs/promises";
|
|
519
555
|
import { dirname as dirname6 } from "path";
|
|
520
556
|
var CRASH_WINDOW_MS = 6e4;
|
|
521
557
|
var DEGRADED_THRESHOLD = 3;
|
|
@@ -525,7 +561,9 @@ async function readHealthFile(slockHome, serverId) {
|
|
|
525
561
|
const raw = await readFile6(serverHealthPath(slockHome, serverId), "utf8");
|
|
526
562
|
const parsed = JSON.parse(raw);
|
|
527
563
|
if (parsed && typeof parsed === "object" && Array.isArray(parsed.crashes)) {
|
|
528
|
-
|
|
564
|
+
const file = parsed;
|
|
565
|
+
if (typeof file.schemaVersion !== "number") file.schemaVersion = CURRENT_SCHEMA_VERSION;
|
|
566
|
+
return file;
|
|
529
567
|
}
|
|
530
568
|
} catch {
|
|
531
569
|
}
|
|
@@ -582,7 +620,7 @@ import { fetch as fetch3 } from "undici";
|
|
|
582
620
|
|
|
583
621
|
// src/upgradeSea.ts
|
|
584
622
|
import { createHash as createHash3 } from "crypto";
|
|
585
|
-
import { chmod as chmod4, mkdir as mkdir9, readFile as readFile8, rename as rename2, rm as rm2, writeFile as writeFile8 } from "fs/promises";
|
|
623
|
+
import { access as access2, chmod as chmod4, mkdir as mkdir9, readFile as readFile8, rename as rename2, rm as rm2, writeFile as writeFile8 } from "fs/promises";
|
|
586
624
|
import { join as join4 } from "path";
|
|
587
625
|
|
|
588
626
|
// src/channel.ts
|
|
@@ -591,7 +629,7 @@ import { dirname as dirname7 } from "path";
|
|
|
591
629
|
|
|
592
630
|
// src/internal/ipc-server.ts
|
|
593
631
|
import { connect, createServer } from "net";
|
|
594
|
-
import { chmod as chmod5, mkdir as mkdir10, stat as stat4, unlink as
|
|
632
|
+
import { chmod as chmod5, mkdir as mkdir10, stat as stat4, unlink as unlink6 } from "fs/promises";
|
|
595
633
|
import { dirname as dirname8 } from "path";
|
|
596
634
|
|
|
597
635
|
// src/internal/ipc-codec.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botiverse/raft-computer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.61",
|
|
4
4
|
"description": "Canonical Raft Computer — standalone human/local-machine control-plane CLI (login + attach). Provides raft-computer plus the legacy slock-computer alias; distinct from the agent-facing @botiverse/raft CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"commander": "^12.1.0",
|
|
32
32
|
"proper-lockfile": "^4.1.2",
|
|
33
33
|
"undici": "^7.24.7",
|
|
34
|
-
"@botiverse/raft-daemon": "0.
|
|
34
|
+
"@botiverse/raft-daemon": "0.63.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^25.5.0",
|