@slock-ai/computer 0.0.14 → 0.0.15
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 +631 -366
- package/dist/lib/index.d.ts +340 -36
- package/dist/lib/index.js +407 -9
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -16617,8 +16617,8 @@ var require_snapshot_recorder = __commonJS({
|
|
|
16617
16617
|
"../../node_modules/.pnpm/undici@7.24.8/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
|
|
16618
16618
|
"use strict";
|
|
16619
16619
|
init_esm_shims();
|
|
16620
|
-
var { writeFile:
|
|
16621
|
-
var { dirname:
|
|
16620
|
+
var { writeFile: writeFile13, readFile: readFile17, mkdir: mkdir17 } = __require("fs/promises");
|
|
16621
|
+
var { dirname: dirname14, resolve } = __require("path");
|
|
16622
16622
|
var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("timers");
|
|
16623
16623
|
var { InvalidArgumentError: InvalidArgumentError2, UndiciError } = require_errors();
|
|
16624
16624
|
var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
|
|
@@ -16819,7 +16819,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
16819
16819
|
throw new InvalidArgumentError2("Snapshot path is required");
|
|
16820
16820
|
}
|
|
16821
16821
|
try {
|
|
16822
|
-
const data = await
|
|
16822
|
+
const data = await readFile17(resolve(path3), "utf8");
|
|
16823
16823
|
const parsed = JSON.parse(data);
|
|
16824
16824
|
if (Array.isArray(parsed)) {
|
|
16825
16825
|
this.#snapshots.clear();
|
|
@@ -16849,12 +16849,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
16849
16849
|
throw new InvalidArgumentError2("Snapshot path is required");
|
|
16850
16850
|
}
|
|
16851
16851
|
const resolvedPath = resolve(path3);
|
|
16852
|
-
await
|
|
16852
|
+
await mkdir17(dirname14(resolvedPath), { recursive: true });
|
|
16853
16853
|
const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
16854
16854
|
hash,
|
|
16855
16855
|
snapshot
|
|
16856
16856
|
}));
|
|
16857
|
-
await
|
|
16857
|
+
await writeFile13(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
|
|
16858
16858
|
}
|
|
16859
16859
|
/**
|
|
16860
16860
|
* Clears all recorded snapshots
|
|
@@ -28469,8 +28469,8 @@ var require_graceful_fs = __commonJS({
|
|
|
28469
28469
|
fs2.createReadStream = createReadStream;
|
|
28470
28470
|
fs2.createWriteStream = createWriteStream;
|
|
28471
28471
|
var fs$readFile = fs2.readFile;
|
|
28472
|
-
fs2.readFile =
|
|
28473
|
-
function
|
|
28472
|
+
fs2.readFile = readFile17;
|
|
28473
|
+
function readFile17(path3, options, cb) {
|
|
28474
28474
|
if (typeof options === "function")
|
|
28475
28475
|
cb = options, options = null;
|
|
28476
28476
|
return go$readFile(path3, options, cb);
|
|
@@ -28486,8 +28486,8 @@ var require_graceful_fs = __commonJS({
|
|
|
28486
28486
|
}
|
|
28487
28487
|
}
|
|
28488
28488
|
var fs$writeFile = fs2.writeFile;
|
|
28489
|
-
fs2.writeFile =
|
|
28490
|
-
function
|
|
28489
|
+
fs2.writeFile = writeFile13;
|
|
28490
|
+
function writeFile13(path3, data, options, cb) {
|
|
28491
28491
|
if (typeof options === "function")
|
|
28492
28492
|
cb = options, options = null;
|
|
28493
28493
|
return go$writeFile(path3, data, options, cb);
|
|
@@ -28504,8 +28504,8 @@ var require_graceful_fs = __commonJS({
|
|
|
28504
28504
|
}
|
|
28505
28505
|
var fs$appendFile = fs2.appendFile;
|
|
28506
28506
|
if (fs$appendFile)
|
|
28507
|
-
fs2.appendFile =
|
|
28508
|
-
function
|
|
28507
|
+
fs2.appendFile = appendFile4;
|
|
28508
|
+
function appendFile4(path3, data, options, cb) {
|
|
28509
28509
|
if (typeof options === "function")
|
|
28510
28510
|
cb = options, options = null;
|
|
28511
28511
|
return go$appendFile(path3, data, options, cb);
|
|
@@ -29891,6 +29891,9 @@ function serverManagedFlagPath(slockHome, serverId) {
|
|
|
29891
29891
|
function serverHealthPath(slockHome, serverId) {
|
|
29892
29892
|
return path2.join(serverDir(slockHome, serverId), "health.json");
|
|
29893
29893
|
}
|
|
29894
|
+
function serviceStatePath(slockHome) {
|
|
29895
|
+
return path2.join(computerDir(slockHome), "service.state.json");
|
|
29896
|
+
}
|
|
29894
29897
|
function supervisorPidPath(slockHome) {
|
|
29895
29898
|
return path2.join(computerDir(slockHome), "supervisor.pid");
|
|
29896
29899
|
}
|
|
@@ -30376,15 +30379,78 @@ async function runAttach(opts) {
|
|
|
30376
30379
|
}
|
|
30377
30380
|
}
|
|
30378
30381
|
|
|
30379
|
-
// src/
|
|
30382
|
+
// src/setup.ts
|
|
30380
30383
|
init_esm_shims();
|
|
30381
|
-
|
|
30384
|
+
var import_undici3 = __toESM(require_undici(), 1);
|
|
30385
|
+
import { chmod as chmod4, mkdir as mkdir9, readFile as readFile8, rename as rename3, rm as rm2, writeFile as writeFile8 } from "fs/promises";
|
|
30386
|
+
import { dirname as dirname9 } from "path";
|
|
30387
|
+
|
|
30388
|
+
// src/lib/migration.ts
|
|
30389
|
+
init_esm_shims();
|
|
30390
|
+
import { readdir as readdir2, readFile as readFile3 } from "fs/promises";
|
|
30391
|
+
import { join } from "path";
|
|
30392
|
+
var MACHINE_DIR_PREFIX = "machine-";
|
|
30393
|
+
async function readOwnerEvidence(installRoot, machineDirName) {
|
|
30394
|
+
const ownerFile = join(
|
|
30395
|
+
installRoot,
|
|
30396
|
+
"machines",
|
|
30397
|
+
machineDirName,
|
|
30398
|
+
"daemon.lock",
|
|
30399
|
+
"owner.json"
|
|
30400
|
+
);
|
|
30401
|
+
let raw;
|
|
30402
|
+
try {
|
|
30403
|
+
raw = await readFile3(ownerFile, "utf8");
|
|
30404
|
+
} catch {
|
|
30405
|
+
return {};
|
|
30406
|
+
}
|
|
30407
|
+
let parsed;
|
|
30408
|
+
try {
|
|
30409
|
+
parsed = JSON.parse(raw);
|
|
30410
|
+
} catch {
|
|
30411
|
+
return {};
|
|
30412
|
+
}
|
|
30413
|
+
const machineName = typeof parsed.hostname === "string" && parsed.hostname.length > 0 ? parsed.hostname : void 0;
|
|
30414
|
+
const serverUrl = typeof parsed.serverUrl === "string" && parsed.serverUrl.length > 0 ? parsed.serverUrl : void 0;
|
|
30415
|
+
return { machineName, serverUrl };
|
|
30416
|
+
}
|
|
30417
|
+
async function detectLegacyMigration(installRoot, loggedInUserId) {
|
|
30418
|
+
void loggedInUserId;
|
|
30419
|
+
const machinesDir = join(installRoot, "machines");
|
|
30420
|
+
let entries;
|
|
30421
|
+
try {
|
|
30422
|
+
entries = await readdir2(machinesDir);
|
|
30423
|
+
} catch {
|
|
30424
|
+
return { kind: "no-match" };
|
|
30425
|
+
}
|
|
30426
|
+
const candidates = [];
|
|
30427
|
+
for (const name of entries) {
|
|
30428
|
+
if (!name.startsWith(MACHINE_DIR_PREFIX)) continue;
|
|
30429
|
+
const evidence = await readOwnerEvidence(installRoot, name);
|
|
30430
|
+
candidates.push({
|
|
30431
|
+
machineId: name,
|
|
30432
|
+
machineName: evidence.machineName,
|
|
30433
|
+
serverUrl: evidence.serverUrl
|
|
30434
|
+
});
|
|
30435
|
+
}
|
|
30436
|
+
if (candidates.length === 0) return { kind: "no-match" };
|
|
30437
|
+
if (candidates.length === 1) {
|
|
30438
|
+
const only = candidates[0];
|
|
30439
|
+
return {
|
|
30440
|
+
kind: "match",
|
|
30441
|
+
machineId: only.machineId,
|
|
30442
|
+
machineName: only.machineName,
|
|
30443
|
+
serverUrl: only.serverUrl
|
|
30444
|
+
};
|
|
30445
|
+
}
|
|
30446
|
+
return { kind: "ambiguous", candidates };
|
|
30447
|
+
}
|
|
30382
30448
|
|
|
30383
30449
|
// src/services/adoptLegacy.ts
|
|
30384
30450
|
init_esm_shims();
|
|
30385
|
-
import { chmod as chmod3, mkdir as mkdir4, readFile as
|
|
30451
|
+
import { chmod as chmod3, mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4, appendFile, stat } from "fs/promises";
|
|
30386
30452
|
import { createHash as createHash2 } from "crypto";
|
|
30387
|
-
import { dirname as dirname4, join } from "path";
|
|
30453
|
+
import { dirname as dirname4, join as join2 } from "path";
|
|
30388
30454
|
import { setTimeout as delay } from "timers/promises";
|
|
30389
30455
|
function emit3(opts, event) {
|
|
30390
30456
|
const cb = opts?.onEvent;
|
|
@@ -30398,7 +30464,7 @@ var LEGACY_STOP_WAIT_MS = 1e4;
|
|
|
30398
30464
|
var LEGACY_STOP_POLL_MS = 200;
|
|
30399
30465
|
function legacyLockOwnerPath(slockHome, rawKey) {
|
|
30400
30466
|
const fingerprint = createHash2("sha256").update(rawKey).digest("hex").slice(0, 16);
|
|
30401
|
-
return
|
|
30467
|
+
return join2(slockHome, "machines", `machine-${fingerprint}`, "daemon.lock", "owner.json");
|
|
30402
30468
|
}
|
|
30403
30469
|
function isProcessAlive(pid) {
|
|
30404
30470
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
@@ -30413,7 +30479,7 @@ function isProcessAlive(pid) {
|
|
|
30413
30479
|
async function stopLegacyDaemonByOwnerFile(ownerFile) {
|
|
30414
30480
|
let raw;
|
|
30415
30481
|
try {
|
|
30416
|
-
raw = await
|
|
30482
|
+
raw = await readFile4(ownerFile, "utf8");
|
|
30417
30483
|
} catch {
|
|
30418
30484
|
return { attempted: false, outcome: "absent" };
|
|
30419
30485
|
}
|
|
@@ -30447,7 +30513,7 @@ async function stopLegacyDaemonByOwnerFile(ownerFile) {
|
|
|
30447
30513
|
async function readLegacyOwnerEvidence(ownerFile) {
|
|
30448
30514
|
let raw;
|
|
30449
30515
|
try {
|
|
30450
|
-
raw = await
|
|
30516
|
+
raw = await readFile4(ownerFile, "utf8");
|
|
30451
30517
|
} catch {
|
|
30452
30518
|
return { ownerFile, reason: "owner_file_absent" };
|
|
30453
30519
|
}
|
|
@@ -30487,7 +30553,7 @@ async function adoptLegacy(input, options = {}) {
|
|
|
30487
30553
|
const sessionFile = userSessionPath(slockHome);
|
|
30488
30554
|
let session;
|
|
30489
30555
|
try {
|
|
30490
|
-
session = JSON.parse(await
|
|
30556
|
+
session = JSON.parse(await readFile4(sessionFile, "utf8"));
|
|
30491
30557
|
} catch (err) {
|
|
30492
30558
|
throw new ComputerServiceError(
|
|
30493
30559
|
"NO_USER_SESSION",
|
|
@@ -30733,134 +30799,18 @@ async function appendAdoptionLog(slockHome, line) {
|
|
|
30733
30799
|
}
|
|
30734
30800
|
}
|
|
30735
30801
|
|
|
30736
|
-
// src/
|
|
30737
|
-
|
|
30738
|
-
|
|
30739
|
-
|
|
30740
|
-
|
|
30741
|
-
|
|
30742
|
-
load: async () => inputs.legacyApiKey.trim()
|
|
30743
|
-
});
|
|
30744
|
-
}
|
|
30745
|
-
if (typeof inputs.legacyApiKeyFile === "string" && inputs.legacyApiKeyFile.length > 0) {
|
|
30746
|
-
sources.push({
|
|
30747
|
-
mode: "legacy_key_file",
|
|
30748
|
-
load: async () => {
|
|
30749
|
-
const contents = await readFile4(inputs.legacyApiKeyFile, "utf8");
|
|
30750
|
-
return contents.trim();
|
|
30751
|
-
}
|
|
30752
|
-
});
|
|
30753
|
-
}
|
|
30754
|
-
if (inputs.legacyApiKeyStdin) {
|
|
30755
|
-
sources.push({
|
|
30756
|
-
mode: "legacy_key_stdin",
|
|
30757
|
-
load: async () => readAllStdin()
|
|
30758
|
-
});
|
|
30759
|
-
}
|
|
30760
|
-
const envKey = env.SLOCK_LEGACY_API_KEY;
|
|
30761
|
-
if (typeof envKey === "string" && envKey.trim().length > 0) {
|
|
30762
|
-
sources.push({
|
|
30763
|
-
mode: "legacy_key_env",
|
|
30764
|
-
load: async () => envKey.trim()
|
|
30765
|
-
});
|
|
30766
|
-
}
|
|
30767
|
-
if (sources.length === 0) {
|
|
30768
|
-
fail(
|
|
30769
|
-
"LEGACY_KEY_REQUIRED",
|
|
30770
|
-
"No legacy api key provided. Pass exactly one of: --legacy-api-key <key>, --legacy-api-key-file <path>, --legacy-api-key-stdin, or SLOCK_LEGACY_API_KEY."
|
|
30771
|
-
);
|
|
30772
|
-
}
|
|
30773
|
-
if (sources.length > 1) {
|
|
30774
|
-
const modes = sources.map((s) => s.mode).join(", ");
|
|
30775
|
-
fail(
|
|
30776
|
-
"LEGACY_KEY_MULTIPLE_SOURCES",
|
|
30777
|
-
`Multiple legacy api key sources provided (${modes}). Choose exactly one.`
|
|
30778
|
-
);
|
|
30779
|
-
}
|
|
30780
|
-
const chosen = sources[0];
|
|
30781
|
-
const rawKey = await chosen.load();
|
|
30782
|
-
if (chosen.mode === "legacy_key_env") {
|
|
30783
|
-
delete env.SLOCK_LEGACY_API_KEY;
|
|
30784
|
-
}
|
|
30785
|
-
if (!rawKey.startsWith("sk_machine_") && !rawKey.startsWith("sk_daemon_")) {
|
|
30786
|
-
fail(
|
|
30787
|
-
"LEGACY_KEY_INVALID",
|
|
30788
|
-
"Provided key does not look like a legacy machine key (expected `sk_machine_*` or `sk_daemon_*`)."
|
|
30789
|
-
);
|
|
30790
|
-
}
|
|
30791
|
-
return {
|
|
30792
|
-
rawKey,
|
|
30793
|
-
mode: chosen.mode,
|
|
30794
|
-
redactedPrefix: rawKey.slice(0, 8)
|
|
30795
|
-
};
|
|
30796
|
-
}
|
|
30797
|
-
async function readAllStdin() {
|
|
30798
|
-
return new Promise((resolve, reject) => {
|
|
30799
|
-
const chunks = [];
|
|
30800
|
-
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
30801
|
-
process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8").trim()));
|
|
30802
|
-
process.stdin.on("error", reject);
|
|
30803
|
-
});
|
|
30804
|
-
}
|
|
30805
|
-
async function runAdoptLegacy(inputs) {
|
|
30806
|
-
const legacy = await resolveLegacyKey(inputs, process.env);
|
|
30807
|
-
try {
|
|
30808
|
-
await adoptLegacy(
|
|
30809
|
-
{
|
|
30810
|
-
serverSlug: inputs.serverSlug,
|
|
30811
|
-
serverUrl: inputs.serverUrl,
|
|
30812
|
-
name: inputs.name,
|
|
30813
|
-
rawKey: legacy.rawKey,
|
|
30814
|
-
mode: legacy.mode,
|
|
30815
|
-
redactedPrefix: legacy.redactedPrefix
|
|
30816
|
-
},
|
|
30817
|
-
{
|
|
30818
|
-
onEvent: (event) => {
|
|
30819
|
-
if (event.type === "adopting") {
|
|
30820
|
-
info(
|
|
30821
|
-
`Adopting legacy daemon for ${formatServerSlugDisplay(event.serverSlug)} via ${event.mode}\u2026`
|
|
30822
|
-
);
|
|
30823
|
-
} else if (event.type === "preflight") {
|
|
30824
|
-
info(event.resumed ? "Adopted (resumed prior attachment); running preflight\u2026" : "Adopted; running preflight\u2026");
|
|
30825
|
-
} else if (event.type === "adopted") {
|
|
30826
|
-
info(`Adopted. Computer state written to ${event.attachmentPath}`);
|
|
30827
|
-
info(` server: ${formatServerSlugDisplay(event.serverSlug)}`);
|
|
30828
|
-
info(` serverMachine: ${event.serverMachineId}`);
|
|
30829
|
-
info(` legacyMachine: ${event.legacyMachineId}`);
|
|
30830
|
-
switch (event.legacyStop.outcome) {
|
|
30831
|
-
case "absent":
|
|
30832
|
-
info(" legacy daemon: not detected on this Computer (no local lock file)");
|
|
30833
|
-
break;
|
|
30834
|
-
case "already_dead":
|
|
30835
|
-
info(` legacy daemon: already stopped (pid ${event.legacyStop.pid} not running)`);
|
|
30836
|
-
break;
|
|
30837
|
-
case "stopped":
|
|
30838
|
-
info(` legacy daemon: stopped (pid ${event.legacyStop.pid}, SIGTERM)`);
|
|
30839
|
-
break;
|
|
30840
|
-
}
|
|
30841
|
-
}
|
|
30842
|
-
}
|
|
30843
|
-
}
|
|
30844
|
-
);
|
|
30845
|
-
} catch (err) {
|
|
30846
|
-
if (err instanceof CliExit) throw err;
|
|
30847
|
-
if (err instanceof ComputerServiceError) {
|
|
30848
|
-
fail(err.code, err.message);
|
|
30849
|
-
}
|
|
30850
|
-
throw err;
|
|
30851
|
-
} finally {
|
|
30852
|
-
legacy.rawKey = void 0;
|
|
30853
|
-
}
|
|
30854
|
-
if (!inputs.orchestrated) {
|
|
30855
|
-
info(`Next: run \`slock-computer start\` to bring this server online under the Computer supervisor.`);
|
|
30856
|
-
}
|
|
30857
|
-
}
|
|
30802
|
+
// src/supervisor.ts
|
|
30803
|
+
init_esm_shims();
|
|
30804
|
+
import { spawn as spawn2 } from "child_process";
|
|
30805
|
+
import { mkdir as mkdir8, readFile as readFile7, writeFile as writeFile7, open, rename as rename2 } from "fs/promises";
|
|
30806
|
+
import { dirname as dirname8, join as joinPath } from "path";
|
|
30807
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
30858
30808
|
|
|
30859
|
-
// src/
|
|
30809
|
+
// src/cleanup.ts
|
|
30860
30810
|
init_esm_shims();
|
|
30861
|
-
|
|
30862
|
-
import {
|
|
30863
|
-
import {
|
|
30811
|
+
import { readdir as readdir3, stat as stat2, unlink as unlink3, rm, rmdir, rename, mkdir as mkdir6 } from "fs/promises";
|
|
30812
|
+
import { spawn } from "child_process";
|
|
30813
|
+
import { join as join3 } from "path";
|
|
30864
30814
|
|
|
30865
30815
|
// src/internal/process-primitives.ts
|
|
30866
30816
|
init_esm_shims();
|
|
@@ -30895,18 +30845,7 @@ async function clearPidfileAt(pidfilePath) {
|
|
|
30895
30845
|
}
|
|
30896
30846
|
}
|
|
30897
30847
|
|
|
30898
|
-
// src/supervisor.ts
|
|
30899
|
-
init_esm_shims();
|
|
30900
|
-
import { spawn as spawn2 } from "child_process";
|
|
30901
|
-
import { mkdir as mkdir8, readFile as readFile7, writeFile as writeFile7, open, rename as rename2 } from "fs/promises";
|
|
30902
|
-
import { dirname as dirname8, join as joinPath } from "path";
|
|
30903
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
30904
|
-
|
|
30905
30848
|
// src/cleanup.ts
|
|
30906
|
-
init_esm_shims();
|
|
30907
|
-
import { readdir as readdir2, stat as stat2, unlink as unlink3, rm, rmdir, rename, mkdir as mkdir6 } from "fs/promises";
|
|
30908
|
-
import { spawn } from "child_process";
|
|
30909
|
-
import { join as join2 } from "path";
|
|
30910
30849
|
function emptyCleanupReport() {
|
|
30911
30850
|
return {
|
|
30912
30851
|
stalePidfiles: [],
|
|
@@ -31001,12 +30940,12 @@ async function cleanupOrphanProcesses(slockHome, psSpawn) {
|
|
|
31001
30940
|
return signaled;
|
|
31002
30941
|
}
|
|
31003
30942
|
function quarantineDir(slockHome) {
|
|
31004
|
-
return
|
|
30943
|
+
return join3(computerDir(slockHome), ".quarantine");
|
|
31005
30944
|
}
|
|
31006
30945
|
async function quarantineServerSubtree(slockHome, serverId) {
|
|
31007
|
-
const src =
|
|
30946
|
+
const src = join3(serversDir(slockHome), serverId);
|
|
31008
30947
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
31009
|
-
const dest =
|
|
30948
|
+
const dest = join3(quarantineDir(slockHome), `${stamp}-${serverId}`);
|
|
31010
30949
|
await mkdir6(dirname6(dest), { recursive: true });
|
|
31011
30950
|
await rename(src, dest);
|
|
31012
30951
|
return dest;
|
|
@@ -31018,7 +30957,7 @@ function dirname6(p) {
|
|
|
31018
30957
|
async function cleanupPowerLossPartialState(slockHome) {
|
|
31019
30958
|
let entries;
|
|
31020
30959
|
try {
|
|
31021
|
-
entries = await
|
|
30960
|
+
entries = await readdir3(serversDir(slockHome));
|
|
31022
30961
|
} catch {
|
|
31023
30962
|
return [];
|
|
31024
30963
|
}
|
|
@@ -31045,11 +30984,11 @@ var TMP_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
|
31045
30984
|
async function cleanupTmpFiles(slockHome) {
|
|
31046
30985
|
const removed = [];
|
|
31047
30986
|
const cdir = computerDir(slockHome);
|
|
31048
|
-
const stagingDir =
|
|
30987
|
+
const stagingDir = join3(cdir, "upgrade-staging");
|
|
31049
30988
|
try {
|
|
31050
|
-
const versions = await
|
|
30989
|
+
const versions = await readdir3(stagingDir);
|
|
31051
30990
|
for (const v of versions) {
|
|
31052
|
-
const vdir =
|
|
30991
|
+
const vdir = join3(stagingDir, v);
|
|
31053
30992
|
try {
|
|
31054
30993
|
const s = await stat2(vdir);
|
|
31055
30994
|
if (Date.now() - s.mtimeMs > TMP_MAX_AGE_MS) {
|
|
@@ -31060,13 +30999,13 @@ async function cleanupTmpFiles(slockHome) {
|
|
|
31060
30999
|
}
|
|
31061
31000
|
}
|
|
31062
31001
|
try {
|
|
31063
|
-
const remaining = await
|
|
31002
|
+
const remaining = await readdir3(stagingDir);
|
|
31064
31003
|
if (remaining.length === 0) await rmdir(stagingDir);
|
|
31065
31004
|
} catch {
|
|
31066
31005
|
}
|
|
31067
31006
|
} catch {
|
|
31068
31007
|
}
|
|
31069
|
-
const snap =
|
|
31008
|
+
const snap = join3(cdir, "upgrade-snapshot.json");
|
|
31070
31009
|
try {
|
|
31071
31010
|
const s = await stat2(snap);
|
|
31072
31011
|
if (Date.now() - s.mtimeMs > TMP_MAX_AGE_MS) {
|
|
@@ -31078,7 +31017,7 @@ async function cleanupTmpFiles(slockHome) {
|
|
|
31078
31017
|
return removed;
|
|
31079
31018
|
}
|
|
31080
31019
|
async function cleanupStaleLock(slockHome) {
|
|
31081
|
-
const lockDir =
|
|
31020
|
+
const lockDir = join3(computerDir(slockHome), ".lock");
|
|
31082
31021
|
try {
|
|
31083
31022
|
const s = await stat2(lockDir);
|
|
31084
31023
|
if (Date.now() - s.mtimeMs > 60 * 1e3) {
|
|
@@ -31090,7 +31029,7 @@ async function cleanupStaleLock(slockHome) {
|
|
|
31090
31029
|
return [];
|
|
31091
31030
|
}
|
|
31092
31031
|
async function forceReleaseLock(slockHome) {
|
|
31093
|
-
const lockDir =
|
|
31032
|
+
const lockDir = join3(computerDir(slockHome), ".lock");
|
|
31094
31033
|
try {
|
|
31095
31034
|
await stat2(lockDir);
|
|
31096
31035
|
await rm(lockDir, { recursive: true, force: true });
|
|
@@ -31114,7 +31053,7 @@ async function runFullCleanup(slockHome, options = {}) {
|
|
|
31114
31053
|
|
|
31115
31054
|
// src/health.ts
|
|
31116
31055
|
init_esm_shims();
|
|
31117
|
-
import { readFile as readFile6, writeFile as writeFile6, unlink as unlink4, mkdir as mkdir7 } from "fs/promises";
|
|
31056
|
+
import { readFile as readFile6, writeFile as writeFile6, unlink as unlink4, mkdir as mkdir7, appendFile as appendFile2 } from "fs/promises";
|
|
31118
31057
|
import { dirname as dirname7 } from "path";
|
|
31119
31058
|
var CRASH_WINDOW_MS = 6e4;
|
|
31120
31059
|
var DEGRADED_THRESHOLD = 3;
|
|
@@ -31186,6 +31125,43 @@ async function resetHealth(slockHome, serverId) {
|
|
|
31186
31125
|
} catch {
|
|
31187
31126
|
}
|
|
31188
31127
|
}
|
|
31128
|
+
async function resetRunnerHealth(slockHome, serverId, nowMs = Date.now()) {
|
|
31129
|
+
if (!isValidServerId(serverId)) {
|
|
31130
|
+
return { status: "not-found" };
|
|
31131
|
+
}
|
|
31132
|
+
const wasDegraded = await isDegraded(slockHome, serverId, nowMs);
|
|
31133
|
+
const recent = await readCrashHistory(slockHome, serverId, nowMs);
|
|
31134
|
+
const previousState = wasDegraded ? "degraded" : "running";
|
|
31135
|
+
await resetHealth(slockHome, serverId);
|
|
31136
|
+
await emitRunnerStateTransition(
|
|
31137
|
+
slockHome,
|
|
31138
|
+
serverId,
|
|
31139
|
+
previousState,
|
|
31140
|
+
"running",
|
|
31141
|
+
"reset-runner"
|
|
31142
|
+
);
|
|
31143
|
+
return {
|
|
31144
|
+
status: "ok",
|
|
31145
|
+
previousState,
|
|
31146
|
+
clearedCrashCount: recent.length
|
|
31147
|
+
};
|
|
31148
|
+
}
|
|
31149
|
+
async function emitRunnerStateTransition(slockHome, serverId, fromState, toState, trigger) {
|
|
31150
|
+
const entry = {
|
|
31151
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
31152
|
+
kind: "runner-state-changed",
|
|
31153
|
+
serverId,
|
|
31154
|
+
fromState,
|
|
31155
|
+
toState,
|
|
31156
|
+
trigger
|
|
31157
|
+
};
|
|
31158
|
+
try {
|
|
31159
|
+
const path3 = supervisorLogPath(slockHome);
|
|
31160
|
+
await mkdir7(dirname7(path3), { recursive: true });
|
|
31161
|
+
await appendFile2(path3, JSON.stringify(entry) + "\n");
|
|
31162
|
+
} catch {
|
|
31163
|
+
}
|
|
31164
|
+
}
|
|
31189
31165
|
|
|
31190
31166
|
// src/services/start.ts
|
|
31191
31167
|
init_esm_shims();
|
|
@@ -31283,7 +31259,14 @@ async function start(input, options = {}) {
|
|
|
31283
31259
|
attachedCount: attached.length
|
|
31284
31260
|
});
|
|
31285
31261
|
const supervise = options.runSupervise ?? runSupervise;
|
|
31286
|
-
|
|
31262
|
+
const previousParentLockMarker = process.env[PARENT_LOCK_HELD_ENV_VAR];
|
|
31263
|
+
process.env[PARENT_LOCK_HELD_ENV_VAR] = "1";
|
|
31264
|
+
try {
|
|
31265
|
+
await supervise();
|
|
31266
|
+
} finally {
|
|
31267
|
+
if (previousParentLockMarker === void 0) delete process.env[PARENT_LOCK_HELD_ENV_VAR];
|
|
31268
|
+
else process.env[PARENT_LOCK_HELD_ENV_VAR] = previousParentLockMarker;
|
|
31269
|
+
}
|
|
31287
31270
|
return {
|
|
31288
31271
|
status: "running",
|
|
31289
31272
|
managedTargets,
|
|
@@ -31916,6 +31899,14 @@ async function runDetach(serverId, serverLabel = serverId) {
|
|
|
31916
31899
|
|
|
31917
31900
|
// src/setup.ts
|
|
31918
31901
|
var USER_SESSION_EXPIRY_LEEWAY_MS = 3e4;
|
|
31902
|
+
async function readUserSessionUserId(slockHome) {
|
|
31903
|
+
try {
|
|
31904
|
+
const parsed = JSON.parse(await readFile8(userSessionPath(slockHome), "utf8"));
|
|
31905
|
+
return typeof parsed.userId === "string" ? parsed.userId : "";
|
|
31906
|
+
} catch {
|
|
31907
|
+
return "";
|
|
31908
|
+
}
|
|
31909
|
+
}
|
|
31919
31910
|
async function hasValidUserSession(slockHome) {
|
|
31920
31911
|
try {
|
|
31921
31912
|
const parsed = JSON.parse(await readFile8(userSessionPath(slockHome), "utf8"));
|
|
@@ -31983,49 +31974,74 @@ async function refreshUserSession(slockHome, serverUrl) {
|
|
|
31983
31974
|
return false;
|
|
31984
31975
|
}
|
|
31985
31976
|
}
|
|
31986
|
-
async function
|
|
31987
|
-
|
|
31988
|
-
|
|
31989
|
-
|
|
31990
|
-
|
|
31991
|
-
return false;
|
|
31992
|
-
}
|
|
31993
|
-
for (const name of machineDirs) {
|
|
31994
|
-
if (!name.startsWith("machine-")) continue;
|
|
31995
|
-
try {
|
|
31996
|
-
const raw = await readFile8(join3(slockHome, "machines", name, "daemon.lock", "owner.json"), "utf8");
|
|
31997
|
-
const owner = JSON.parse(raw);
|
|
31998
|
-
if (typeof owner.pid === "number" && isProcessAlive2(owner.pid)) return true;
|
|
31999
|
-
} catch {
|
|
32000
|
-
}
|
|
32001
|
-
}
|
|
32002
|
-
return false;
|
|
31977
|
+
async function defaultConfirmMigrate(prompt) {
|
|
31978
|
+
process.stdout.write(prompt);
|
|
31979
|
+
const line = await readLine(false);
|
|
31980
|
+
const norm = line.trim().toLowerCase();
|
|
31981
|
+
return norm === "y" || norm === "yes";
|
|
32003
31982
|
}
|
|
32004
|
-
function
|
|
32005
|
-
|
|
31983
|
+
async function defaultReadMigrateSecret(prompt) {
|
|
31984
|
+
process.stdout.write(prompt);
|
|
31985
|
+
const line = await readLine(true);
|
|
31986
|
+
process.stdout.write("\n");
|
|
31987
|
+
return line.trim();
|
|
32006
31988
|
}
|
|
32007
|
-
function
|
|
32008
|
-
|
|
31989
|
+
async function readLine(masked) {
|
|
31990
|
+
const stdin = process.stdin;
|
|
31991
|
+
const wasRaw = stdin.isTTY === true && stdin.isRaw === true;
|
|
31992
|
+
const enterRaw = masked && stdin.isTTY === true && typeof stdin.setRawMode === "function";
|
|
31993
|
+
if (enterRaw) stdin.setRawMode(true);
|
|
31994
|
+
stdin.resume();
|
|
31995
|
+
return await new Promise((resolve) => {
|
|
31996
|
+
let buf = "";
|
|
31997
|
+
const cleanup = () => {
|
|
31998
|
+
stdin.off("data", onData);
|
|
31999
|
+
stdin.off("end", onEnd);
|
|
32000
|
+
stdin.pause();
|
|
32001
|
+
if (enterRaw) stdin.setRawMode(wasRaw);
|
|
32002
|
+
};
|
|
32003
|
+
const onData = (chunk) => {
|
|
32004
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
32005
|
+
for (const ch of text) {
|
|
32006
|
+
if (ch === "\n" || ch === "\r") {
|
|
32007
|
+
cleanup();
|
|
32008
|
+
resolve(buf);
|
|
32009
|
+
return;
|
|
32010
|
+
}
|
|
32011
|
+
if (ch === "") {
|
|
32012
|
+
cleanup();
|
|
32013
|
+
resolve("");
|
|
32014
|
+
return;
|
|
32015
|
+
}
|
|
32016
|
+
if (ch === "\x7F" || ch === "\b") {
|
|
32017
|
+
buf = buf.slice(0, -1);
|
|
32018
|
+
continue;
|
|
32019
|
+
}
|
|
32020
|
+
buf += ch;
|
|
32021
|
+
}
|
|
32022
|
+
};
|
|
32023
|
+
const onEnd = () => {
|
|
32024
|
+
cleanup();
|
|
32025
|
+
resolve(buf);
|
|
32026
|
+
};
|
|
32027
|
+
stdin.on("data", onData);
|
|
32028
|
+
stdin.on("end", onEnd);
|
|
32029
|
+
});
|
|
32009
32030
|
}
|
|
32010
32031
|
async function runSetup(opts, deps = {}) {
|
|
32011
32032
|
const slockHome = resolveSlockHome();
|
|
32012
32033
|
const isTty = deps.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
32013
32034
|
const login2 = deps.runLogin ?? runLogin;
|
|
32014
32035
|
const attach2 = deps.runAttach ?? runAttach;
|
|
32015
|
-
const adopt = deps.runAdoptLegacy ?? runAdoptLegacy;
|
|
32016
32036
|
const start2 = deps.runStart ?? runStart;
|
|
32017
32037
|
const refreshSession = deps.refreshUserSession ?? refreshUserSession;
|
|
32018
|
-
const
|
|
32038
|
+
const detectMigration = deps.detectLegacyMigration ?? detectLegacyMigration;
|
|
32039
|
+
const confirmMigrate = deps.confirmMigrate ?? defaultConfirmMigrate;
|
|
32040
|
+
const readMigrateSecret = deps.readMigrateSecret ?? defaultReadMigrateSecret;
|
|
32019
32041
|
if (!isTty && !opts.yes) {
|
|
32020
32042
|
fail(
|
|
32021
32043
|
"NON_INTERACTIVE_SETUP_REQUIRES_FLAGS",
|
|
32022
|
-
"Non-interactive setup requires --yes after you have confirmed the login/attach/
|
|
32023
|
-
);
|
|
32024
|
-
}
|
|
32025
|
-
if (!opts.adoptLegacy && hasExplicitLegacyKeyInput(opts)) {
|
|
32026
|
-
fail(
|
|
32027
|
-
"LEGACY_KEY_OUTSIDE_ADOPT",
|
|
32028
|
-
"`--legacy-api-key*` options are only accepted with `slock-computer setup --adopt-legacy` or `slock-computer adopt-legacy`."
|
|
32044
|
+
"Non-interactive setup requires --yes after you have confirmed the login/attach/start actions. Run `slock-computer login`, `slock-computer attach`, and `slock-computer start` separately for fully explicit automation."
|
|
32029
32045
|
);
|
|
32030
32046
|
}
|
|
32031
32047
|
const label = formatServerSlugDisplay(opts.serverSlug);
|
|
@@ -32050,34 +32066,82 @@ async function runSetup(opts, deps = {}) {
|
|
|
32050
32066
|
if (attachment) {
|
|
32051
32067
|
info(`Attachment: already attached to ${label}.`);
|
|
32052
32068
|
} else {
|
|
32053
|
-
|
|
32054
|
-
|
|
32055
|
-
|
|
32056
|
-
|
|
32057
|
-
|
|
32058
|
-
"
|
|
32059
|
-
|
|
32060
|
-
|
|
32061
|
-
|
|
32062
|
-
|
|
32063
|
-
|
|
32064
|
-
|
|
32065
|
-
|
|
32066
|
-
|
|
32067
|
-
|
|
32068
|
-
|
|
32069
|
-
|
|
32070
|
-
|
|
32071
|
-
|
|
32072
|
-
|
|
32073
|
-
|
|
32074
|
-
|
|
32075
|
-
|
|
32076
|
-
|
|
32077
|
-
|
|
32078
|
-
|
|
32079
|
-
|
|
32069
|
+
let migrated = false;
|
|
32070
|
+
if (isTty) {
|
|
32071
|
+
const detection = await detectMigration(slockHome, await readUserSessionUserId(slockHome));
|
|
32072
|
+
if (detection.kind === "match") {
|
|
32073
|
+
const where = detection.serverUrl ? ` attached to ${detection.serverUrl}` : "";
|
|
32074
|
+
const who = detection.machineName ? ` "${detection.machineName}"` : "";
|
|
32075
|
+
const accepted = await confirmMigrate(
|
|
32076
|
+
`Migration: detected legacy daemon machine${who}${where}. Migrate it under Computer instead of creating a fresh attachment? [y/N] `
|
|
32077
|
+
);
|
|
32078
|
+
if (accepted) {
|
|
32079
|
+
const rawKey = await readMigrateSecret(
|
|
32080
|
+
"Paste legacy api key (sk_machine_* or sk_daemon_*); input is hidden: "
|
|
32081
|
+
);
|
|
32082
|
+
if (rawKey.length === 0) {
|
|
32083
|
+
info("Migration: no key provided; falling back to fresh attach.");
|
|
32084
|
+
} else if (!rawKey.startsWith("sk_machine_") && !rawKey.startsWith("sk_daemon_")) {
|
|
32085
|
+
fail(
|
|
32086
|
+
"LEGACY_KEY_INVALID",
|
|
32087
|
+
"Provided key does not look like a legacy machine key (expected `sk_machine_*` or `sk_daemon_*`)."
|
|
32088
|
+
);
|
|
32089
|
+
} else {
|
|
32090
|
+
try {
|
|
32091
|
+
await adoptLegacy(
|
|
32092
|
+
{
|
|
32093
|
+
serverSlug: opts.serverSlug,
|
|
32094
|
+
serverUrl: opts.serverUrl,
|
|
32095
|
+
name: opts.name,
|
|
32096
|
+
rawKey,
|
|
32097
|
+
mode: "legacy_key_stdin",
|
|
32098
|
+
redactedPrefix: rawKey.slice(0, 8)
|
|
32099
|
+
},
|
|
32100
|
+
{
|
|
32101
|
+
onEvent: (event) => {
|
|
32102
|
+
if (event.type === "adopting") {
|
|
32103
|
+
info(
|
|
32104
|
+
`Adopting legacy daemon for ${formatServerSlugDisplay(event.serverSlug)} via ${event.mode}\u2026`
|
|
32105
|
+
);
|
|
32106
|
+
} else if (event.type === "preflight") {
|
|
32107
|
+
info(
|
|
32108
|
+
event.resumed ? "Adopted (resumed prior attachment); running preflight\u2026" : "Adopted; running preflight\u2026"
|
|
32109
|
+
);
|
|
32110
|
+
} else if (event.type === "adopted") {
|
|
32111
|
+
info(`Adopted. Computer state written to ${event.attachmentPath}`);
|
|
32112
|
+
info(` server: ${formatServerSlugDisplay(event.serverSlug)}`);
|
|
32113
|
+
info(` serverMachine: ${event.serverMachineId}`);
|
|
32114
|
+
info(` legacyMachine: ${event.legacyMachineId}`);
|
|
32115
|
+
switch (event.legacyStop.outcome) {
|
|
32116
|
+
case "absent":
|
|
32117
|
+
info(" legacy daemon: not detected on this Computer (no local lock file)");
|
|
32118
|
+
break;
|
|
32119
|
+
case "already_dead":
|
|
32120
|
+
info(` legacy daemon: already stopped (pid ${event.legacyStop.pid} not running)`);
|
|
32121
|
+
break;
|
|
32122
|
+
case "stopped":
|
|
32123
|
+
info(` legacy daemon: stopped (pid ${event.legacyStop.pid}, SIGTERM)`);
|
|
32124
|
+
break;
|
|
32125
|
+
}
|
|
32126
|
+
}
|
|
32127
|
+
}
|
|
32128
|
+
}
|
|
32129
|
+
);
|
|
32130
|
+
migrated = true;
|
|
32131
|
+
} catch (err) {
|
|
32132
|
+
if (err instanceof CliExit) throw err;
|
|
32133
|
+
if (err instanceof ComputerServiceError) {
|
|
32134
|
+
fail(err.code, err.message);
|
|
32135
|
+
}
|
|
32136
|
+
throw err;
|
|
32137
|
+
}
|
|
32138
|
+
}
|
|
32139
|
+
} else {
|
|
32140
|
+
info("Migration: declined; falling back to fresh attach.");
|
|
32141
|
+
}
|
|
32080
32142
|
}
|
|
32143
|
+
}
|
|
32144
|
+
if (!migrated) {
|
|
32081
32145
|
await attach2({
|
|
32082
32146
|
serverSlug: opts.serverSlug,
|
|
32083
32147
|
serverUrl: opts.serverUrl,
|
|
@@ -32090,7 +32154,7 @@ async function runSetup(opts, deps = {}) {
|
|
|
32090
32154
|
if (!attachment) {
|
|
32091
32155
|
fail(
|
|
32092
32156
|
"SETUP_ATTACHMENT_MISSING",
|
|
32093
|
-
`Setup did not produce a local attachment for ${label}. Re-run \`slock-computer attach ${label}
|
|
32157
|
+
`Setup did not produce a local attachment for ${label}. Re-run \`slock-computer attach ${label}\`.`
|
|
32094
32158
|
);
|
|
32095
32159
|
}
|
|
32096
32160
|
}
|
|
@@ -32138,32 +32202,31 @@ async function deriveHealth(slockHome, serverId, daemon) {
|
|
|
32138
32202
|
if (await isDegraded(slockHome, serverId)) return "degraded";
|
|
32139
32203
|
return "ok";
|
|
32140
32204
|
}
|
|
32141
|
-
async function buildStatusReport() {
|
|
32142
|
-
const
|
|
32143
|
-
const sessionRead = await readUserSession(userSessionPath(slockHome));
|
|
32205
|
+
async function buildStatusReport(installRoot) {
|
|
32206
|
+
const sessionRead = await readUserSession(userSessionPath(installRoot));
|
|
32144
32207
|
const session = sessionRead.session;
|
|
32145
|
-
const attachments = await listServerAttachments(
|
|
32208
|
+
const attachments = await listServerAttachments(installRoot);
|
|
32146
32209
|
const supervisor = {
|
|
32147
|
-
...await pidStatus(supervisorPidPath(
|
|
32148
|
-
logPath: supervisorLogPath(
|
|
32210
|
+
...await pidStatus(supervisorPidPath(installRoot)),
|
|
32211
|
+
logPath: supervisorLogPath(installRoot)
|
|
32149
32212
|
};
|
|
32150
32213
|
const servers = [];
|
|
32151
32214
|
for (const a of attachments) {
|
|
32152
|
-
const daemon = await pidStatus(serverDaemonPidPath(
|
|
32215
|
+
const daemon = await pidStatus(serverDaemonPidPath(installRoot, a.serverId));
|
|
32153
32216
|
servers.push({
|
|
32154
32217
|
serverId: a.serverId,
|
|
32155
32218
|
serverSlug: a.serverSlug ?? null,
|
|
32156
32219
|
serverMachineId: a.serverMachineId,
|
|
32157
32220
|
serverUrl: a.serverUrl,
|
|
32158
32221
|
attachedAt: a.attachedAt ?? null,
|
|
32159
|
-
daemonLogPath: serverDaemonLogPath(
|
|
32222
|
+
daemonLogPath: serverDaemonLogPath(installRoot, a.serverId),
|
|
32160
32223
|
daemon,
|
|
32161
|
-
health: await deriveHealth(
|
|
32224
|
+
health: await deriveHealth(installRoot, a.serverId, daemon)
|
|
32162
32225
|
});
|
|
32163
32226
|
}
|
|
32164
32227
|
const loggedIn = session?.kind === "user-session" && typeof session.accessToken === "string" && session.accessToken.length > 0;
|
|
32165
32228
|
return {
|
|
32166
|
-
slockHome,
|
|
32229
|
+
slockHome: installRoot,
|
|
32167
32230
|
loggedIn,
|
|
32168
32231
|
userId: session ? str(session.userId) : null,
|
|
32169
32232
|
loginServerUrl: session ? str(session.serverUrl) : null,
|
|
@@ -32176,7 +32239,7 @@ function pad(s, n) {
|
|
|
32176
32239
|
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
32177
32240
|
}
|
|
32178
32241
|
async function runStatus(opts) {
|
|
32179
|
-
const report = await buildStatusReport();
|
|
32242
|
+
const report = await buildStatusReport(resolveSlockHome());
|
|
32180
32243
|
if (opts.json) {
|
|
32181
32244
|
info(JSON.stringify(report, null, 2));
|
|
32182
32245
|
return;
|
|
@@ -32281,42 +32344,92 @@ async function resolveTargetAttachment(opts) {
|
|
|
32281
32344
|
return a;
|
|
32282
32345
|
}
|
|
32283
32346
|
|
|
32347
|
+
// src/lib/readers.ts
|
|
32348
|
+
init_esm_shims();
|
|
32349
|
+
|
|
32350
|
+
// src/lib/types.ts
|
|
32351
|
+
init_esm_shims();
|
|
32352
|
+
var StateReaderError = class extends Error {
|
|
32353
|
+
code;
|
|
32354
|
+
constructor(code, message) {
|
|
32355
|
+
super(message);
|
|
32356
|
+
this.name = "StateReaderError";
|
|
32357
|
+
this.code = code;
|
|
32358
|
+
}
|
|
32359
|
+
};
|
|
32360
|
+
|
|
32361
|
+
// src/lib/readers.ts
|
|
32362
|
+
async function listRunners(installRoot, opts = {}) {
|
|
32363
|
+
const all = await listServerAttachments(installRoot);
|
|
32364
|
+
let subset = all;
|
|
32365
|
+
if (opts.serverId !== void 0) {
|
|
32366
|
+
const found = all.find((a) => a.serverId === opts.serverId);
|
|
32367
|
+
if (!found) {
|
|
32368
|
+
throw new StateReaderError(
|
|
32369
|
+
"NOT_ATTACHED",
|
|
32370
|
+
`Server ${opts.serverId} is not attached to this Computer.`
|
|
32371
|
+
);
|
|
32372
|
+
}
|
|
32373
|
+
subset = [found];
|
|
32374
|
+
}
|
|
32375
|
+
const servers = [];
|
|
32376
|
+
for (const a of subset) {
|
|
32377
|
+
const client = new RunnersClient(a.serverUrl, a.apiKey);
|
|
32378
|
+
const result = await client.list();
|
|
32379
|
+
const idCols = { serverId: a.serverId, serverSlug: a.serverSlug ?? null };
|
|
32380
|
+
if (result.status === "success") {
|
|
32381
|
+
servers.push({
|
|
32382
|
+
...idCols,
|
|
32383
|
+
status: "ok",
|
|
32384
|
+
whitelist: result.whitelist,
|
|
32385
|
+
runners: result.runners
|
|
32386
|
+
});
|
|
32387
|
+
} else if (result.status === "unauthorized") {
|
|
32388
|
+
servers.push({ ...idCols, status: "unauthorized" });
|
|
32389
|
+
} else {
|
|
32390
|
+
servers.push({ ...idCols, status: "error", code: result.code });
|
|
32391
|
+
}
|
|
32392
|
+
}
|
|
32393
|
+
return { servers };
|
|
32394
|
+
}
|
|
32395
|
+
|
|
32284
32396
|
// src/runners.ts
|
|
32285
32397
|
async function runRunnersList(opts) {
|
|
32286
|
-
const
|
|
32287
|
-
const
|
|
32288
|
-
const
|
|
32289
|
-
const
|
|
32290
|
-
|
|
32398
|
+
const serverId = await resolveTargetServerId({ server: opts.server });
|
|
32399
|
+
const installRoot = resolveSlockHome();
|
|
32400
|
+
const { servers } = await listRunners(installRoot, { serverId });
|
|
32401
|
+
const block = servers[0];
|
|
32402
|
+
const label = block.serverSlug ? formatServerSlugDisplay(block.serverSlug) : block.serverId;
|
|
32403
|
+
if (block.status === "unauthorized") {
|
|
32291
32404
|
fail(
|
|
32292
32405
|
"RUNNERS_UNAUTHORIZED",
|
|
32293
32406
|
`The Computer credential for ${label} was rejected. Re-run \`slock-computer attach ${label}\`.`
|
|
32294
32407
|
);
|
|
32295
32408
|
}
|
|
32296
|
-
if (
|
|
32409
|
+
if (block.status === "error") {
|
|
32297
32410
|
fail(
|
|
32298
32411
|
"RUNNERS_LIST_FAILED",
|
|
32299
|
-
`Could not list runners on ${label} (${
|
|
32412
|
+
`Could not list runners on ${label} (${block.code}). Check --server-url / server version.`
|
|
32300
32413
|
);
|
|
32301
32414
|
}
|
|
32302
32415
|
if (opts.json) {
|
|
32303
32416
|
info(
|
|
32304
32417
|
JSON.stringify(
|
|
32305
|
-
{ server: label, serverId:
|
|
32418
|
+
{ server: label, serverId: block.serverId, whitelist: block.whitelist, runners: block.runners },
|
|
32306
32419
|
null,
|
|
32307
32420
|
2
|
|
32308
32421
|
)
|
|
32309
32422
|
);
|
|
32310
32423
|
return;
|
|
32311
32424
|
}
|
|
32312
|
-
if (
|
|
32425
|
+
if (block.runners.length === 0) {
|
|
32313
32426
|
info(`No runners on server ${label}.`);
|
|
32314
32427
|
return;
|
|
32315
32428
|
}
|
|
32316
32429
|
info("");
|
|
32317
32430
|
info(`Server ${label}:`);
|
|
32318
32431
|
info(" AGENT STATUS RUNTIME MODEL NAME");
|
|
32319
|
-
for (const r of
|
|
32432
|
+
for (const r of block.runners) {
|
|
32320
32433
|
info(
|
|
32321
32434
|
` ${r.agentId.padEnd(38)}${(r.status ?? "").padEnd(11)}${(r.runtime ?? "").padEnd(10)}${(r.model ?? "").padEnd(15)}${r.name ?? ""}`
|
|
32322
32435
|
);
|
|
@@ -32365,7 +32478,8 @@ function redactSecrets(line) {
|
|
|
32365
32478
|
return out;
|
|
32366
32479
|
}
|
|
32367
32480
|
async function runDoctorChecks() {
|
|
32368
|
-
const
|
|
32481
|
+
const slockHome = resolveSlockHome();
|
|
32482
|
+
const report = await buildStatusReport(slockHome);
|
|
32369
32483
|
const checks = [];
|
|
32370
32484
|
checks.push({ name: "SLOCK_HOME", ok: true, detail: report.slockHome });
|
|
32371
32485
|
checks.push(
|
|
@@ -32378,7 +32492,6 @@ async function runDoctorChecks() {
|
|
|
32378
32492
|
detail: "stopped (run `slock-computer start` when you want background)"
|
|
32379
32493
|
}
|
|
32380
32494
|
);
|
|
32381
|
-
const slockHome = resolveSlockHome();
|
|
32382
32495
|
const attachments = await listServerAttachments(slockHome);
|
|
32383
32496
|
if (attachments.length === 0) {
|
|
32384
32497
|
checks.push({
|
|
@@ -32511,16 +32624,166 @@ async function runLogs(opts) {
|
|
|
32511
32624
|
for (const line of tail) info(redactSecrets(line));
|
|
32512
32625
|
}
|
|
32513
32626
|
|
|
32627
|
+
// src/reset.ts
|
|
32628
|
+
init_esm_shims();
|
|
32629
|
+
|
|
32630
|
+
// src/serviceState.ts
|
|
32631
|
+
init_esm_shims();
|
|
32632
|
+
import { mkdir as mkdir10, readFile as readFile11, writeFile as writeFile9, appendFile as appendFile3 } from "fs/promises";
|
|
32633
|
+
import { dirname as dirname10 } from "path";
|
|
32634
|
+
|
|
32635
|
+
// src/lib/state.ts
|
|
32636
|
+
init_esm_shims();
|
|
32637
|
+
var SERVICE_STATE_VALUES = [
|
|
32638
|
+
"starting",
|
|
32639
|
+
"running",
|
|
32640
|
+
"degraded",
|
|
32641
|
+
"stopping",
|
|
32642
|
+
"stopped"
|
|
32643
|
+
];
|
|
32644
|
+
function isServiceState(value) {
|
|
32645
|
+
return typeof value === "string" && SERVICE_STATE_VALUES.includes(value);
|
|
32646
|
+
}
|
|
32647
|
+
|
|
32648
|
+
// src/serviceState.ts
|
|
32649
|
+
var DEFAULT_STATE = {
|
|
32650
|
+
state: "running",
|
|
32651
|
+
crashHistory: []
|
|
32652
|
+
};
|
|
32653
|
+
async function readServiceState(slockHome) {
|
|
32654
|
+
try {
|
|
32655
|
+
const raw = await readFile11(serviceStatePath(slockHome), "utf8");
|
|
32656
|
+
const parsed = JSON.parse(raw);
|
|
32657
|
+
if (!parsed || typeof parsed !== "object") return { ...DEFAULT_STATE };
|
|
32658
|
+
const obj = parsed;
|
|
32659
|
+
const state = isServiceState(obj.state) ? obj.state : "running";
|
|
32660
|
+
const crashHistory = Array.isArray(obj.crashHistory) ? obj.crashHistory.filter(isCrashEntry) : [];
|
|
32661
|
+
return { state, crashHistory };
|
|
32662
|
+
} catch {
|
|
32663
|
+
return { ...DEFAULT_STATE };
|
|
32664
|
+
}
|
|
32665
|
+
}
|
|
32666
|
+
async function writeServiceState(slockHome, file) {
|
|
32667
|
+
const path3 = serviceStatePath(slockHome);
|
|
32668
|
+
await mkdir10(dirname10(path3), { recursive: true });
|
|
32669
|
+
await writeFile9(path3, JSON.stringify(file), { mode: 384 });
|
|
32670
|
+
}
|
|
32671
|
+
function isCrashEntry(value) {
|
|
32672
|
+
if (!value || typeof value !== "object") return false;
|
|
32673
|
+
const obj = value;
|
|
32674
|
+
return typeof obj.at === "string";
|
|
32675
|
+
}
|
|
32676
|
+
async function emitServiceStateTransition(slockHome, fromState, toState, trigger) {
|
|
32677
|
+
const entry = {
|
|
32678
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32679
|
+
kind: "service-state-changed",
|
|
32680
|
+
fromState,
|
|
32681
|
+
toState,
|
|
32682
|
+
trigger
|
|
32683
|
+
};
|
|
32684
|
+
try {
|
|
32685
|
+
const path3 = supervisorLogPath(slockHome);
|
|
32686
|
+
await mkdir10(dirname10(path3), { recursive: true });
|
|
32687
|
+
await appendFile3(path3, JSON.stringify(entry) + "\n");
|
|
32688
|
+
} catch {
|
|
32689
|
+
}
|
|
32690
|
+
}
|
|
32691
|
+
async function clearServiceCrashHistory(slockHome) {
|
|
32692
|
+
const current = await readServiceState(slockHome);
|
|
32693
|
+
const previousState = current.state;
|
|
32694
|
+
const clearedCrashCount = current.crashHistory.length;
|
|
32695
|
+
const next = { state: "running", crashHistory: [] };
|
|
32696
|
+
await writeServiceState(slockHome, next);
|
|
32697
|
+
await emitServiceStateTransition(
|
|
32698
|
+
slockHome,
|
|
32699
|
+
previousState,
|
|
32700
|
+
"running",
|
|
32701
|
+
"reset-service"
|
|
32702
|
+
);
|
|
32703
|
+
return { previousState, clearedCrashCount };
|
|
32704
|
+
}
|
|
32705
|
+
|
|
32706
|
+
// src/reset.ts
|
|
32707
|
+
async function resetService(installRoot) {
|
|
32708
|
+
const { previousState, clearedCrashCount } = await clearServiceCrashHistory(installRoot);
|
|
32709
|
+
return {
|
|
32710
|
+
status: "ok",
|
|
32711
|
+
previousState,
|
|
32712
|
+
clearedCrashCount
|
|
32713
|
+
};
|
|
32714
|
+
}
|
|
32715
|
+
async function resetRunner(installRoot, serverId) {
|
|
32716
|
+
const attachment = await readServerAttachment(installRoot, serverId);
|
|
32717
|
+
if (!attachment) {
|
|
32718
|
+
return { status: "not-found", serverId };
|
|
32719
|
+
}
|
|
32720
|
+
const outcome = await resetRunnerHealth(installRoot, serverId);
|
|
32721
|
+
if (outcome.status === "not-found") {
|
|
32722
|
+
return { status: "not-found", serverId };
|
|
32723
|
+
}
|
|
32724
|
+
return {
|
|
32725
|
+
status: "ok",
|
|
32726
|
+
serverId,
|
|
32727
|
+
previousState: outcome.previousState ?? "running",
|
|
32728
|
+
clearedCrashCount: outcome.clearedCrashCount ?? 0
|
|
32729
|
+
};
|
|
32730
|
+
}
|
|
32731
|
+
async function runReset(opts) {
|
|
32732
|
+
const wantsService = opts.service === true;
|
|
32733
|
+
const wantsRunner = opts.runner === true;
|
|
32734
|
+
if (wantsService && wantsRunner) {
|
|
32735
|
+
fail(
|
|
32736
|
+
"RESET_SCOPE_AMBIGUOUS",
|
|
32737
|
+
"`--service` and `--runner` are mutually exclusive. Pass exactly one."
|
|
32738
|
+
);
|
|
32739
|
+
}
|
|
32740
|
+
if (!wantsService && !wantsRunner) {
|
|
32741
|
+
fail(
|
|
32742
|
+
"RESET_SCOPE_MISSING",
|
|
32743
|
+
"Pass `--service` to clear the service-level crash history, or `--runner` to clear a per-runner crash history."
|
|
32744
|
+
);
|
|
32745
|
+
}
|
|
32746
|
+
const slockHome = resolveSlockHome();
|
|
32747
|
+
if (wantsService) {
|
|
32748
|
+
const result2 = await resetService(slockHome);
|
|
32749
|
+
if (opts.json) {
|
|
32750
|
+
info(JSON.stringify(result2));
|
|
32751
|
+
return;
|
|
32752
|
+
}
|
|
32753
|
+
info(
|
|
32754
|
+
`Reset service crash history (previous state: ${result2.previousState}; cleared ${result2.clearedCrashCount} entr${result2.clearedCrashCount === 1 ? "y" : "ies"}).`
|
|
32755
|
+
);
|
|
32756
|
+
info("Service state transitioned to `running`. Runners were not touched.");
|
|
32757
|
+
return;
|
|
32758
|
+
}
|
|
32759
|
+
const serverId = await resolveTargetServerId({ server: opts.server });
|
|
32760
|
+
const result = await resetRunner(slockHome, serverId);
|
|
32761
|
+
if (result.status === "not-found") {
|
|
32762
|
+
fail(
|
|
32763
|
+
"RESET_RUNNER_NOT_FOUND",
|
|
32764
|
+
`Runner for server ${serverId} was not found.`
|
|
32765
|
+
);
|
|
32766
|
+
}
|
|
32767
|
+
if (opts.json) {
|
|
32768
|
+
info(JSON.stringify(result));
|
|
32769
|
+
return;
|
|
32770
|
+
}
|
|
32771
|
+
info(
|
|
32772
|
+
`Reset runner crash history for server ${result.serverId} (previous state: ${result.previousState}; cleared ${result.clearedCrashCount} entr${result.clearedCrashCount === 1 ? "y" : "ies"}).`
|
|
32773
|
+
);
|
|
32774
|
+
info("Runner state transitioned to `running`. Process was not respawned.");
|
|
32775
|
+
}
|
|
32776
|
+
|
|
32514
32777
|
// src/concurrency.ts
|
|
32515
32778
|
init_esm_shims();
|
|
32516
32779
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
32517
|
-
import { mkdir as
|
|
32780
|
+
import { mkdir as mkdir11 } from "fs/promises";
|
|
32518
32781
|
import { join as join4 } from "path";
|
|
32519
32782
|
var STALE_LOCK_THRESHOLD_MS = 6e4;
|
|
32520
32783
|
async function withMutationLock(fn) {
|
|
32521
32784
|
const slockHome = resolveSlockHome();
|
|
32522
32785
|
const lockTarget = computerDir(slockHome);
|
|
32523
|
-
await
|
|
32786
|
+
await mkdir11(lockTarget, { recursive: true });
|
|
32524
32787
|
const lockfilePath = join4(lockTarget, ".lock");
|
|
32525
32788
|
let release = null;
|
|
32526
32789
|
try {
|
|
@@ -32559,8 +32822,8 @@ async function withMutationLock(fn) {
|
|
|
32559
32822
|
|
|
32560
32823
|
// src/channel.ts
|
|
32561
32824
|
init_esm_shims();
|
|
32562
|
-
import { readFile as
|
|
32563
|
-
import { dirname as
|
|
32825
|
+
import { readFile as readFile12, writeFile as writeFile10, mkdir as mkdir12 } from "fs/promises";
|
|
32826
|
+
import { dirname as dirname11 } from "path";
|
|
32564
32827
|
var DEFAULT_CHANNEL = "latest";
|
|
32565
32828
|
var SEMVER_RE = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
|
|
32566
32829
|
function parseChannel(raw) {
|
|
@@ -32575,7 +32838,7 @@ function parseChannel(raw) {
|
|
|
32575
32838
|
}
|
|
32576
32839
|
async function readChannel(slockHome) {
|
|
32577
32840
|
try {
|
|
32578
|
-
const raw = await
|
|
32841
|
+
const raw = await readFile12(channelPath(slockHome), "utf8");
|
|
32579
32842
|
const parsed = parseChannel(raw);
|
|
32580
32843
|
if (parsed !== null) return parsed;
|
|
32581
32844
|
} catch {
|
|
@@ -32584,8 +32847,8 @@ async function readChannel(slockHome) {
|
|
|
32584
32847
|
}
|
|
32585
32848
|
async function writeChannel(slockHome, channel2) {
|
|
32586
32849
|
const p = channelPath(slockHome);
|
|
32587
|
-
await
|
|
32588
|
-
await
|
|
32850
|
+
await mkdir12(dirname11(p), { recursive: true });
|
|
32851
|
+
await writeFile10(p, `${channel2}
|
|
32589
32852
|
`, { mode: 384 });
|
|
32590
32853
|
}
|
|
32591
32854
|
async function runChannelShow(slockHome) {
|
|
@@ -32608,20 +32871,20 @@ async function runChannelSet(slockHome, raw) {
|
|
|
32608
32871
|
|
|
32609
32872
|
// src/upgradeCli.ts
|
|
32610
32873
|
init_esm_shims();
|
|
32611
|
-
import { readFile as
|
|
32874
|
+
import { readFile as readFile15 } from "fs/promises";
|
|
32612
32875
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
32613
|
-
import { dirname as
|
|
32876
|
+
import { dirname as dirname12, join as join7 } from "path";
|
|
32614
32877
|
|
|
32615
32878
|
// src/upgrade.ts
|
|
32616
32879
|
init_esm_shims();
|
|
32617
32880
|
import { spawn as spawn4 } from "child_process";
|
|
32618
|
-
import { mkdir as
|
|
32881
|
+
import { mkdir as mkdir13, readFile as readFile14, writeFile as writeFile11, rm as rm3, rename as rename4 } from "fs/promises";
|
|
32619
32882
|
import { join as join6 } from "path";
|
|
32620
32883
|
import { createHash as createHash3 } from "crypto";
|
|
32621
32884
|
|
|
32622
32885
|
// src/preflightDepDrift.ts
|
|
32623
32886
|
init_esm_shims();
|
|
32624
|
-
import { readFile as
|
|
32887
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
32625
32888
|
import { spawn as spawn3 } from "child_process";
|
|
32626
32889
|
import { createRequire } from "module";
|
|
32627
32890
|
import { join as join5 } from "path";
|
|
@@ -32630,12 +32893,10 @@ var DAEMON_PACKAGE_NAME = "@slock-ai/daemon";
|
|
|
32630
32893
|
async function preflightDepDriftCheck(currentBinaryDir, stagedTarballPath, deps = {}) {
|
|
32631
32894
|
const readTarball = deps.readTarballPackageJson ?? defaultReadTarballPackageJson;
|
|
32632
32895
|
const readCurrent = deps.readCurrentPackageJson ?? defaultReadCurrentPackageJson;
|
|
32633
|
-
const readInstalled = deps.readInstalledDaemonVersion ?? defaultReadInstalledDaemonVersion;
|
|
32634
32896
|
const satisfies = deps.semverSatisfies ?? defaultSemverSatisfies;
|
|
32635
32897
|
const allowUnsafe = deps.allowUnsafeSpec === true;
|
|
32636
32898
|
let targetPkg;
|
|
32637
32899
|
let currentPkg;
|
|
32638
|
-
let installedVersion;
|
|
32639
32900
|
try {
|
|
32640
32901
|
targetPkg = await readTarball(stagedTarballPath);
|
|
32641
32902
|
} catch (e) {
|
|
@@ -32654,15 +32915,6 @@ async function preflightDepDriftCheck(currentBinaryDir, stagedTarballPath, deps
|
|
|
32654
32915
|
detail: `cannot read current binary package.json: ${errMsg(e)}`
|
|
32655
32916
|
};
|
|
32656
32917
|
}
|
|
32657
|
-
try {
|
|
32658
|
-
installedVersion = await readInstalled(currentBinaryDir);
|
|
32659
|
-
} catch (e) {
|
|
32660
|
-
return {
|
|
32661
|
-
ok: false,
|
|
32662
|
-
reason: "read_failed",
|
|
32663
|
-
detail: `cannot read installed ${DAEMON_PACKAGE_NAME} version: ${errMsg(e)}`
|
|
32664
|
-
};
|
|
32665
|
-
}
|
|
32666
32918
|
const targetSpec = targetPkg.dependencies?.[DAEMON_PACKAGE_NAME];
|
|
32667
32919
|
const currentSpec = currentPkg.dependencies?.[DAEMON_PACKAGE_NAME];
|
|
32668
32920
|
if (typeof targetSpec !== "string" || targetSpec.length === 0) {
|
|
@@ -32673,60 +32925,64 @@ async function preflightDepDriftCheck(currentBinaryDir, stagedTarballPath, deps
|
|
|
32673
32925
|
currentSpec
|
|
32674
32926
|
};
|
|
32675
32927
|
}
|
|
32676
|
-
|
|
32928
|
+
const unsafeTarget = isUnsafeSpec(targetSpec) || isUnparseableRange(targetSpec);
|
|
32929
|
+
if (!allowUnsafe && unsafeTarget) {
|
|
32677
32930
|
return {
|
|
32678
32931
|
ok: false,
|
|
32679
|
-
reason: "
|
|
32680
|
-
detail:
|
|
32932
|
+
reason: "unsafe_spec",
|
|
32933
|
+
detail: `${DAEMON_PACKAGE_NAME} target spec is not a safe semver range (target="${targetSpec}"). Auto-upgrade only supports target semver ranges that can be hydrated and verified before swap.`,
|
|
32934
|
+
currentSpec,
|
|
32681
32935
|
targetSpec
|
|
32682
32936
|
};
|
|
32683
32937
|
}
|
|
32684
|
-
|
|
32938
|
+
void satisfies;
|
|
32939
|
+
return { ok: true, currentSpec, targetSpec };
|
|
32940
|
+
}
|
|
32941
|
+
async function verifyHydratedDaemonDependency(extractedPackageDir, targetSpec, deps = {}) {
|
|
32942
|
+
const readInstalled = deps.readInstalledDaemonVersion ?? defaultReadInstalledDaemonVersion;
|
|
32943
|
+
const satisfies = deps.semverSatisfies ?? defaultSemverSatisfies;
|
|
32944
|
+
const allowUnsafe = deps.allowUnsafeSpec === true;
|
|
32945
|
+
const unsafeTarget = isUnsafeSpec(targetSpec) || isUnparseableRange(targetSpec);
|
|
32946
|
+
if (!allowUnsafe && unsafeTarget) {
|
|
32685
32947
|
return {
|
|
32686
32948
|
ok: false,
|
|
32687
|
-
reason: "
|
|
32688
|
-
detail: `${DAEMON_PACKAGE_NAME} is not
|
|
32689
|
-
currentSpec,
|
|
32949
|
+
reason: "unsafe_spec",
|
|
32950
|
+
detail: `${DAEMON_PACKAGE_NAME} target spec is not a safe semver range (target="${targetSpec}").`,
|
|
32690
32951
|
targetSpec
|
|
32691
32952
|
};
|
|
32692
32953
|
}
|
|
32693
|
-
|
|
32694
|
-
|
|
32695
|
-
|
|
32696
|
-
|
|
32954
|
+
let installedVersion;
|
|
32955
|
+
try {
|
|
32956
|
+
installedVersion = await readInstalled(extractedPackageDir);
|
|
32957
|
+
} catch (e) {
|
|
32697
32958
|
return {
|
|
32698
32959
|
ok: false,
|
|
32699
|
-
reason: "
|
|
32700
|
-
detail:
|
|
32701
|
-
|
|
32702
|
-
targetSpec,
|
|
32703
|
-
installedVersion
|
|
32960
|
+
reason: "read_failed",
|
|
32961
|
+
detail: `cannot read hydrated ${DAEMON_PACKAGE_NAME} version: ${errMsg(e)}`,
|
|
32962
|
+
targetSpec
|
|
32704
32963
|
};
|
|
32705
32964
|
}
|
|
32706
|
-
if (
|
|
32965
|
+
if (installedVersion === null || installedVersion.length === 0) {
|
|
32707
32966
|
return {
|
|
32708
32967
|
ok: false,
|
|
32709
|
-
reason: "
|
|
32710
|
-
detail: `${DAEMON_PACKAGE_NAME}
|
|
32711
|
-
|
|
32712
|
-
targetSpec,
|
|
32713
|
-
installedVersion
|
|
32968
|
+
reason: "read_failed",
|
|
32969
|
+
detail: `${DAEMON_PACKAGE_NAME} is not installed in the hydrated staged package`,
|
|
32970
|
+
targetSpec
|
|
32714
32971
|
};
|
|
32715
32972
|
}
|
|
32716
|
-
if (allowUnsafe &&
|
|
32717
|
-
return { ok: true,
|
|
32973
|
+
if (allowUnsafe && unsafeTarget) {
|
|
32974
|
+
return { ok: true, targetSpec, installedVersion };
|
|
32718
32975
|
}
|
|
32719
32976
|
if (!satisfies(installedVersion, targetSpec)) {
|
|
32720
32977
|
return {
|
|
32721
32978
|
ok: false,
|
|
32722
32979
|
reason: "installed_unsatisfied",
|
|
32723
|
-
detail: `
|
|
32724
|
-
currentSpec,
|
|
32980
|
+
detail: `hydrated ${DAEMON_PACKAGE_NAME}@${installedVersion} does not satisfy target spec "${targetSpec}".`,
|
|
32725
32981
|
targetSpec,
|
|
32726
32982
|
installedVersion
|
|
32727
32983
|
};
|
|
32728
32984
|
}
|
|
32729
|
-
return { ok: true,
|
|
32985
|
+
return { ok: true, targetSpec, installedVersion };
|
|
32730
32986
|
}
|
|
32731
32987
|
function isUnparseableRange(spec) {
|
|
32732
32988
|
const s = spec.trim();
|
|
@@ -32792,7 +33048,7 @@ async function defaultReadTarballPackageJson(tarballPath) {
|
|
|
32792
33048
|
return JSON.parse(raw);
|
|
32793
33049
|
}
|
|
32794
33050
|
async function defaultReadCurrentPackageJson(currentBinaryDir) {
|
|
32795
|
-
const raw = await
|
|
33051
|
+
const raw = await readFile13(join5(currentBinaryDir, "package.json"), "utf8");
|
|
32796
33052
|
return JSON.parse(raw);
|
|
32797
33053
|
}
|
|
32798
33054
|
async function defaultReadInstalledDaemonVersion(currentBinaryDir) {
|
|
@@ -32809,7 +33065,7 @@ async function defaultReadInstalledDaemonVersion(currentBinaryDir) {
|
|
|
32809
33065
|
for (const base of searchPaths) {
|
|
32810
33066
|
const candidate = join5(base, ...subPath, "package.json");
|
|
32811
33067
|
try {
|
|
32812
|
-
const raw = await
|
|
33068
|
+
const raw = await readFile13(candidate, "utf8");
|
|
32813
33069
|
const parsed = JSON.parse(raw);
|
|
32814
33070
|
if (parsed.name !== DAEMON_PACKAGE_NAME) continue;
|
|
32815
33071
|
if (typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
@@ -32889,9 +33145,9 @@ function satisfiesTilde(ver, base) {
|
|
|
32889
33145
|
// src/upgrade.ts
|
|
32890
33146
|
async function stagePhase(slockHome, version, deps = {}) {
|
|
32891
33147
|
const npmPack = deps.npmPack ?? defaultNpmPack;
|
|
32892
|
-
const fsReadFile = deps.fsReadFile ??
|
|
33148
|
+
const fsReadFile = deps.fsReadFile ?? readFile14;
|
|
32893
33149
|
const stagedPath = upgradeStagingDir(slockHome, version);
|
|
32894
|
-
await
|
|
33150
|
+
await mkdir13(stagedPath, { recursive: true });
|
|
32895
33151
|
const packageRef = `@slock-ai/computer@${version}`;
|
|
32896
33152
|
const result = await npmPack(stagedPath, packageRef);
|
|
32897
33153
|
if (result.exitCode !== 0) {
|
|
@@ -32999,8 +33255,8 @@ async function cleanupStaged(slockHome, version) {
|
|
|
32999
33255
|
async function snapshotPhase(slockHome, snap) {
|
|
33000
33256
|
const path3 = upgradeSnapshotPath(slockHome);
|
|
33001
33257
|
const tmp = `${path3}.tmp`;
|
|
33002
|
-
await
|
|
33003
|
-
await
|
|
33258
|
+
await mkdir13(computerDir(slockHome), { recursive: true });
|
|
33259
|
+
await writeFile11(tmp, JSON.stringify(snap, null, 2), { mode: 384 });
|
|
33004
33260
|
await rename4(tmp, path3);
|
|
33005
33261
|
}
|
|
33006
33262
|
async function clearUpgradeSnapshot(slockHome) {
|
|
@@ -33012,7 +33268,7 @@ async function clearUpgradeSnapshot(slockHome) {
|
|
|
33012
33268
|
}
|
|
33013
33269
|
async function extractTarball(tarballPath, destDir, deps = {}) {
|
|
33014
33270
|
const tarSpawn = deps.tarSpawn ?? defaultTarSpawn;
|
|
33015
|
-
await
|
|
33271
|
+
await mkdir13(destDir, { recursive: true });
|
|
33016
33272
|
const result = await tarSpawn(tarballPath, destDir);
|
|
33017
33273
|
if (result.exitCode !== 0) {
|
|
33018
33274
|
const err = new Error(
|
|
@@ -33271,7 +33527,7 @@ async function restartPhase(slockHome, deps = {}) {
|
|
|
33271
33527
|
}
|
|
33272
33528
|
async function defaultReadSupervisorPid(slockHome) {
|
|
33273
33529
|
try {
|
|
33274
|
-
const raw = (await
|
|
33530
|
+
const raw = (await readFile14(supervisorPidPath(slockHome), "utf8")).trim();
|
|
33275
33531
|
const pid = Number.parseInt(raw, 10);
|
|
33276
33532
|
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
33277
33533
|
} catch {
|
|
@@ -33390,6 +33646,18 @@ async function runUpgrade(slockHome, opts) {
|
|
|
33390
33646
|
preflight
|
|
33391
33647
|
};
|
|
33392
33648
|
}
|
|
33649
|
+
const targetDaemonSpec = preflight.targetSpec;
|
|
33650
|
+
if (typeof targetDaemonSpec !== "string" || targetDaemonSpec.length === 0) {
|
|
33651
|
+
await cleanupStaged(slockHome, opts.targetVersion);
|
|
33652
|
+
return {
|
|
33653
|
+
ok: false,
|
|
33654
|
+
phase: "preflight",
|
|
33655
|
+
reason: `${preflight.detail ?? preflight.reason ?? "dep_drift"}: missing target ${DAEMON_PACKAGE_NAME} spec`,
|
|
33656
|
+
staged,
|
|
33657
|
+
verify,
|
|
33658
|
+
preflight
|
|
33659
|
+
};
|
|
33660
|
+
}
|
|
33393
33661
|
const snap = {
|
|
33394
33662
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33395
33663
|
fromVersion: opts.fromVersion,
|
|
@@ -33440,6 +33708,24 @@ async function runUpgrade(slockHome, opts) {
|
|
|
33440
33708
|
verify
|
|
33441
33709
|
};
|
|
33442
33710
|
}
|
|
33711
|
+
const hydratedDaemon = await verifyHydratedDaemonDependency(
|
|
33712
|
+
extractedPackageDir,
|
|
33713
|
+
targetDaemonSpec,
|
|
33714
|
+
deps.preflight ?? {}
|
|
33715
|
+
);
|
|
33716
|
+
if (!hydratedDaemon.ok) {
|
|
33717
|
+
await cleanupStaged(slockHome, opts.targetVersion);
|
|
33718
|
+
await clearUpgradeSnapshot(slockHome);
|
|
33719
|
+
return {
|
|
33720
|
+
ok: false,
|
|
33721
|
+
phase: "hydrate",
|
|
33722
|
+
reason: `staged dependency tree verification failed: ${hydratedDaemon.detail ?? hydratedDaemon.reason ?? "hydrated dependency verification failed"}`,
|
|
33723
|
+
staged,
|
|
33724
|
+
verify,
|
|
33725
|
+
preflight,
|
|
33726
|
+
hydratedDaemon
|
|
33727
|
+
};
|
|
33728
|
+
}
|
|
33443
33729
|
let swap;
|
|
33444
33730
|
try {
|
|
33445
33731
|
swap = await swapPhase(opts.currentBinaryDir, extractedPackageDir, {
|
|
@@ -33528,7 +33814,7 @@ async function runUpgrade(slockHome, opts) {
|
|
|
33528
33814
|
};
|
|
33529
33815
|
}
|
|
33530
33816
|
await cleanupSuccessPhase(slockHome, opts.targetVersion, swap.prevBinaryDir);
|
|
33531
|
-
return { ok: true, phase: "cleanup", staged, verify, swap, restart, rolling };
|
|
33817
|
+
return { ok: true, phase: "cleanup", staged, verify, preflight, hydratedDaemon, swap, restart, rolling };
|
|
33532
33818
|
}
|
|
33533
33819
|
async function rollingDaemonHealthCheck(slockHome, deps = {}) {
|
|
33534
33820
|
const list = deps.listManagedServerIds ?? listManagedServerIds;
|
|
@@ -33564,7 +33850,7 @@ async function rollingDaemonHealthCheck(slockHome, deps = {}) {
|
|
|
33564
33850
|
}
|
|
33565
33851
|
async function defaultReadDaemonPid(slockHome, serverId) {
|
|
33566
33852
|
try {
|
|
33567
|
-
const raw = (await
|
|
33853
|
+
const raw = (await readFile14(serverDaemonPidPath(slockHome, serverId), "utf8")).trim();
|
|
33568
33854
|
const pid = Number.parseInt(raw, 10);
|
|
33569
33855
|
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
33570
33856
|
} catch {
|
|
@@ -33592,7 +33878,7 @@ async function locateStagedTarball(stagedPath) {
|
|
|
33592
33878
|
|
|
33593
33879
|
// src/upgradeLog.ts
|
|
33594
33880
|
init_esm_shims();
|
|
33595
|
-
import { chmod as chmod5, mkdir as
|
|
33881
|
+
import { chmod as chmod5, mkdir as mkdir14, open as open2 } from "fs/promises";
|
|
33596
33882
|
var FILE_MODE = 384;
|
|
33597
33883
|
var UPGRADE_ERROR_CODES = [
|
|
33598
33884
|
"UPGRADE_DEPS_CHANGED",
|
|
@@ -33637,7 +33923,7 @@ function assertUpgradeLogEntry(entry) {
|
|
|
33637
33923
|
}
|
|
33638
33924
|
async function appendUpgradeLogEntry(slockHome, entry) {
|
|
33639
33925
|
assertUpgradeLogEntry(entry);
|
|
33640
|
-
await
|
|
33926
|
+
await mkdir14(computerDir(slockHome), { recursive: true });
|
|
33641
33927
|
const path3 = upgradeLogPath(slockHome);
|
|
33642
33928
|
const at = entry.at ?? formatUpgradeLogTimestamp();
|
|
33643
33929
|
const fullEntry = { ...entry, at };
|
|
@@ -33660,7 +33946,7 @@ function isEphemeralNpxContext(binaryDir) {
|
|
|
33660
33946
|
async function readBundledDaemonVersion(binaryDir) {
|
|
33661
33947
|
try {
|
|
33662
33948
|
const pkgPath = join7(binaryDir, "package.json");
|
|
33663
|
-
const raw = await
|
|
33949
|
+
const raw = await readFile15(pkgPath, "utf8");
|
|
33664
33950
|
const parsed = JSON.parse(raw);
|
|
33665
33951
|
const pinned = parsed.dependencies?.["@slock-ai/daemon"];
|
|
33666
33952
|
if (typeof pinned !== "string" || pinned.length === 0) return null;
|
|
@@ -33854,6 +34140,9 @@ function mapFailurePhaseToCode(outcome) {
|
|
|
33854
34140
|
case "extract":
|
|
33855
34141
|
return "UPGRADE_INTEGRITY_FAILED";
|
|
33856
34142
|
case "hydrate":
|
|
34143
|
+
if (outcome.hydratedDaemon?.ok === false) {
|
|
34144
|
+
return "UPGRADE_INTEGRITY_FAILED";
|
|
34145
|
+
}
|
|
33857
34146
|
return "UPGRADE_NETWORK_FAILED";
|
|
33858
34147
|
case "swap":
|
|
33859
34148
|
return "UPGRADE_SWAP_FAILED";
|
|
@@ -33888,12 +34177,12 @@ async function defaultFetchDistTags() {
|
|
|
33888
34177
|
}
|
|
33889
34178
|
function defaultCurrentBinaryDir() {
|
|
33890
34179
|
const here = fileURLToPath3(import.meta.url);
|
|
33891
|
-
return
|
|
34180
|
+
return dirname12(dirname12(here));
|
|
33892
34181
|
}
|
|
33893
34182
|
async function defaultCurrentVersion() {
|
|
33894
34183
|
const pkgPath = join7(defaultCurrentBinaryDir(), "package.json");
|
|
33895
34184
|
try {
|
|
33896
|
-
const raw = await
|
|
34185
|
+
const raw = await readFile15(pkgPath, "utf8");
|
|
33897
34186
|
const parsed = JSON.parse(raw);
|
|
33898
34187
|
if (typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
33899
34188
|
return parsed.version;
|
|
@@ -33905,7 +34194,7 @@ async function defaultCurrentVersion() {
|
|
|
33905
34194
|
|
|
33906
34195
|
// src/upgradeTestHarness.ts
|
|
33907
34196
|
init_esm_shims();
|
|
33908
|
-
import { mkdir as
|
|
34197
|
+
import { mkdir as mkdir15, readdir as readdir4, stat as stat3, writeFile as writeFile12 } from "fs/promises";
|
|
33909
34198
|
import { join as join8 } from "path";
|
|
33910
34199
|
import { createHash as createHash4 } from "crypto";
|
|
33911
34200
|
var PHASES = /* @__PURE__ */ new Set([
|
|
@@ -33964,7 +34253,7 @@ function buildSimulatedDeps(slockHome, opts) {
|
|
|
33964
34253
|
return { tarballPath: "", exitCode: 1, stderr: "simulated stage failure" };
|
|
33965
34254
|
}
|
|
33966
34255
|
const filename = `slock-ai-computer-${targetVersion}.tgz`;
|
|
33967
|
-
await
|
|
34256
|
+
await writeFile12(join8(cwd, filename), tarballBytes);
|
|
33968
34257
|
return { tarballPath: join8(cwd, filename), exitCode: 0, stderr: "" };
|
|
33969
34258
|
},
|
|
33970
34259
|
fetchAdvertisedHash: async () => {
|
|
@@ -33976,8 +34265,8 @@ function buildSimulatedDeps(slockHome, opts) {
|
|
|
33976
34265
|
if (opts.simulateFail === "extract") {
|
|
33977
34266
|
return { exitCode: 1, stderr: "simulated extract failure" };
|
|
33978
34267
|
}
|
|
33979
|
-
await
|
|
33980
|
-
await
|
|
34268
|
+
await mkdir15(join8(destDir, "package"), { recursive: true });
|
|
34269
|
+
await writeFile12(join8(destDir, "package", "marker.txt"), `NEW@${targetVersion}`);
|
|
33981
34270
|
return { exitCode: 0, stderr: "" };
|
|
33982
34271
|
},
|
|
33983
34272
|
npmInstall: async () => ({ exitCode: 0, stderr: "" }),
|
|
@@ -34038,7 +34327,7 @@ function buildSimulatedDeps(slockHome, opts) {
|
|
|
34038
34327
|
}
|
|
34039
34328
|
async function arrangeSnapshotFailure(slockHome) {
|
|
34040
34329
|
const snapshotPath = join8(slockHome, "computer", "upgrade-snapshot.json");
|
|
34041
|
-
await
|
|
34330
|
+
await mkdir15(snapshotPath, { recursive: true });
|
|
34042
34331
|
}
|
|
34043
34332
|
async function pathInfo(path3) {
|
|
34044
34333
|
try {
|
|
@@ -34093,12 +34382,12 @@ async function runUpgradeTestHarness(slockHome, opts, writer = (s) => process.st
|
|
|
34093
34382
|
process.exitCode = 1;
|
|
34094
34383
|
return;
|
|
34095
34384
|
}
|
|
34096
|
-
await
|
|
34385
|
+
await mkdir15(slockHome, { recursive: true });
|
|
34097
34386
|
if (opts.simulateFail === "snapshot") {
|
|
34098
34387
|
await arrangeSnapshotFailure(slockHome);
|
|
34099
34388
|
}
|
|
34100
34389
|
const { opts: upgradeOpts } = buildSimulatedDeps(slockHome, opts);
|
|
34101
|
-
await
|
|
34390
|
+
await mkdir15(upgradeOpts.currentBinaryDir, { recursive: true });
|
|
34102
34391
|
let outcome;
|
|
34103
34392
|
try {
|
|
34104
34393
|
outcome = await runUpgrade(slockHome, upgradeOpts);
|
|
@@ -34136,9 +34425,9 @@ async function runUpgradeTestHarness(slockHome, opts, writer = (s) => process.st
|
|
|
34136
34425
|
|
|
34137
34426
|
// src/upgradeInstallSmoke.ts
|
|
34138
34427
|
init_esm_shims();
|
|
34139
|
-
import { copyFile, mkdir as
|
|
34428
|
+
import { copyFile, mkdir as mkdir16, readFile as readFile16 } from "fs/promises";
|
|
34140
34429
|
import { createHash as createHash5 } from "crypto";
|
|
34141
|
-
import { dirname as
|
|
34430
|
+
import { dirname as dirname13, isAbsolute, join as join9, resolve as pathResolve } from "path";
|
|
34142
34431
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
34143
34432
|
async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
34144
34433
|
if (typeof opts.packageTarball !== "string" || opts.packageTarball.trim().length === 0) {
|
|
@@ -34147,7 +34436,7 @@ async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
|
34147
34436
|
const tarballPath = isAbsolute(opts.packageTarball) ? opts.packageTarball : pathResolve(opts.packageTarball);
|
|
34148
34437
|
let tarballBytes;
|
|
34149
34438
|
try {
|
|
34150
|
-
tarballBytes = await
|
|
34439
|
+
tarballBytes = await readFile16(tarballPath);
|
|
34151
34440
|
} catch (e) {
|
|
34152
34441
|
const msg = e instanceof Error ? e.message : String(e);
|
|
34153
34442
|
throw new Error(`__upgrade-install-smoke: cannot read --package-tarball ${tarballPath}: ${msg}`);
|
|
@@ -34159,7 +34448,7 @@ async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
|
34159
34448
|
const spawnFreshSupervisor = deps.spawnFreshSupervisor ?? (async (h) => {
|
|
34160
34449
|
await spawnDetachedSupervisor(h);
|
|
34161
34450
|
});
|
|
34162
|
-
await
|
|
34451
|
+
await mkdir16(slockHome, { recursive: true });
|
|
34163
34452
|
const outcome = await runUpgrade(slockHome, {
|
|
34164
34453
|
targetVersion: opts.targetVersion,
|
|
34165
34454
|
fromVersion,
|
|
@@ -34217,12 +34506,12 @@ async function runUpgradeInstallSmokeCli(slockHome, opts, writer = (s) => proces
|
|
|
34217
34506
|
}
|
|
34218
34507
|
function defaultCurrentBinaryDirLocal() {
|
|
34219
34508
|
const here = fileURLToPath4(import.meta.url);
|
|
34220
|
-
return
|
|
34509
|
+
return dirname13(dirname13(here));
|
|
34221
34510
|
}
|
|
34222
34511
|
async function defaultCurrentVersionLocal() {
|
|
34223
34512
|
const pkgPath = join9(defaultCurrentBinaryDirLocal(), "package.json");
|
|
34224
34513
|
try {
|
|
34225
|
-
const raw = await
|
|
34514
|
+
const raw = await readFile16(pkgPath, "utf8");
|
|
34226
34515
|
const parsed = JSON.parse(raw);
|
|
34227
34516
|
if (typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
34228
34517
|
return parsed.version;
|
|
@@ -34272,17 +34561,13 @@ program2.command("attach").argument("<serverSlug>", "target Slock server slug (c
|
|
|
34272
34561
|
() => runAttach({ serverSlug, serverUrl: opts.serverUrl, name: opts.name, run: opts.run, foreground: opts.foreground })
|
|
34273
34562
|
);
|
|
34274
34563
|
}));
|
|
34275
|
-
program2.command("setup").argument("<serverSlug>", "target Slock server slug (canonical form `/myserver`; bare `myserver` accepted)").description("Set up this Computer for one server: login if needed, attach
|
|
34564
|
+
program2.command("setup").argument("<serverSlug>", "target Slock server slug (canonical form `/myserver`; bare `myserver` accepted)").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 supervisor").option("--foreground", "run the supervisor in this terminal instead of the background").option("-y, --yes", "allow non-interactive setup after confirming the planned actions").action(
|
|
34276
34565
|
withCliExit(async (serverSlug, opts) => {
|
|
34277
34566
|
await withMutationLock(
|
|
34278
34567
|
() => runSetup({
|
|
34279
34568
|
serverSlug,
|
|
34280
34569
|
serverUrl: opts.serverUrl,
|
|
34281
34570
|
name: opts.name,
|
|
34282
|
-
adoptLegacy: opts.adoptLegacy,
|
|
34283
|
-
legacyApiKey: opts.legacyApiKey,
|
|
34284
|
-
legacyApiKeyFile: opts.legacyApiKeyFile,
|
|
34285
|
-
legacyApiKeyStdin: opts.legacyApiKeyStdin,
|
|
34286
34571
|
start: opts.start,
|
|
34287
34572
|
foreground: opts.foreground,
|
|
34288
34573
|
yes: opts.yes
|
|
@@ -34290,22 +34575,6 @@ program2.command("setup").argument("<serverSlug>", "target Slock server slug (ca
|
|
|
34290
34575
|
);
|
|
34291
34576
|
})
|
|
34292
34577
|
);
|
|
34293
|
-
program2.command("adopt-legacy").argument("<serverSlug>", "target Slock server slug (the legacy machine's server)").description(
|
|
34294
|
-
"One-time migration: trade a legacy sk_machine_* / sk_daemon_* key for a fresh Computer attachment (sk_computer_*)."
|
|
34295
|
-
).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>", "name to record on the new Computer attachment (default: existing machine name)").option("--legacy-api-key <key>", "raw legacy key on argv (insecure on shared shells; prefer --legacy-api-key-file or stdin)").option("--legacy-api-key-file <path>", "path to a 0600 file containing the legacy key (one line)").option("--legacy-api-key-stdin", "read the legacy key from stdin").action(
|
|
34296
|
-
withCliExit(async (serverSlug, opts) => {
|
|
34297
|
-
await withMutationLock(
|
|
34298
|
-
() => runAdoptLegacy({
|
|
34299
|
-
serverSlug,
|
|
34300
|
-
serverUrl: opts.serverUrl,
|
|
34301
|
-
name: opts.name,
|
|
34302
|
-
legacyApiKey: opts.legacyApiKey,
|
|
34303
|
-
legacyApiKeyFile: opts.legacyApiKeyFile,
|
|
34304
|
-
legacyApiKeyStdin: opts.legacyApiKeyStdin
|
|
34305
|
-
})
|
|
34306
|
-
);
|
|
34307
|
-
})
|
|
34308
|
-
);
|
|
34309
34578
|
program2.command("detach").argument("<serverSlug>", "server slug to detach from this Computer (canonical form `/myserver`)").description("Remove ONE server's local attachment; never touches user-session or other servers.").action(withCliExit(async (serverSlug) => {
|
|
34310
34579
|
await withMutationLock(async () => runDetach(await resolveTargetServerId({ server: serverSlug }), serverSlug));
|
|
34311
34580
|
}));
|
|
@@ -34339,6 +34608,18 @@ program2.command("doctor").argument("[serverSlug]", "optional: scope detail (rec
|
|
|
34339
34608
|
}
|
|
34340
34609
|
)
|
|
34341
34610
|
);
|
|
34611
|
+
program2.command("reset").description("Clear a degraded state and resume the supervisor's auto-restart loop.").option("--service", "clear the service-level crash history (cascade record)").option("--runner", "clear a runner's crash history (selected by `--server`)").option("--server <slug>", "with `--runner`, select target server slug (required when \u22652 attached)").option("--json", "emit the machine-readable result").action(
|
|
34612
|
+
withCliExit(async (opts) => {
|
|
34613
|
+
await withMutationLock(
|
|
34614
|
+
() => runReset({
|
|
34615
|
+
service: opts.service,
|
|
34616
|
+
runner: opts.runner,
|
|
34617
|
+
server: opts.server,
|
|
34618
|
+
json: opts.json
|
|
34619
|
+
})
|
|
34620
|
+
);
|
|
34621
|
+
})
|
|
34622
|
+
);
|
|
34342
34623
|
program2.command("logs").description("Tail one server's daemon log (or the supervisor log); secrets redacted.").option("--lines <n>", "trailing lines to show (default 200)", (v) => Number.parseInt(v, 10)).option("--server <slug>", "select target server slug (required when \u22652 attached)").option("--supervisor", "tail the global supervisor log instead of a per-server daemon log").action(withCliExit(async (opts) => {
|
|
34343
34624
|
await runLogs({ lines: opts.lines, server: opts.server ?? null, supervisor: !!opts.supervisor });
|
|
34344
34625
|
}));
|
|
@@ -34364,9 +34645,8 @@ program2.command("upgrade").description(
|
|
|
34364
34645
|
[
|
|
34365
34646
|
"Auto-upgrade this Computer to the latest version in its channel (or --target-version <semver>).",
|
|
34366
34647
|
"",
|
|
34367
|
-
"
|
|
34368
|
-
"
|
|
34369
|
-
"UPGRADE_DEPS_CHANGED and require manual `npm install -g @slock-ai/computer@<version>`."
|
|
34648
|
+
"Stages the target package, hydrates production dependencies, verifies the",
|
|
34649
|
+
"hydrated @slock-ai/daemon version, then swaps the Computer package root."
|
|
34370
34650
|
].join("\n")
|
|
34371
34651
|
).option("--dry-run", "stage + 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("--drain <mode>", "\xA72.7 drain mode: drain (default) | defer (abort if daemon busy) | force (SIGKILL, drop in-flight)").option("--force", "alias for --drain force (stuck-daemon recovery; drops in-flight turns)").action(
|
|
34372
34652
|
withCliExit(
|
|
@@ -34459,21 +34739,6 @@ program2.command("__upgrade-install-smoke", { hidden: true }).requiredOption("--
|
|
|
34459
34739
|
);
|
|
34460
34740
|
})
|
|
34461
34741
|
);
|
|
34462
|
-
{
|
|
34463
|
-
const argv = process.argv.slice(2);
|
|
34464
|
-
const isAdopt = argv[0] === "adopt-legacy";
|
|
34465
|
-
const isSetup = argv[0] === "setup";
|
|
34466
|
-
const strayLegacyFlag = argv.find(
|
|
34467
|
-
(a) => a === "--legacy-api-key" || a.startsWith("--legacy-api-key=") || a === "--legacy-api-key-file" || a.startsWith("--legacy-api-key-file=") || a === "--legacy-api-key-stdin"
|
|
34468
|
-
);
|
|
34469
|
-
if (strayLegacyFlag && !isAdopt && !isSetup) {
|
|
34470
|
-
process.stderr.write(
|
|
34471
|
-
`slock-computer: LEGACY_KEY_OUTSIDE_ADOPT: ${strayLegacyFlag} is only accepted by \`slock-computer adopt-legacy\` or \`slock-computer setup --adopt-legacy\`. Remove it or run an adopt flow.
|
|
34472
|
-
`
|
|
34473
|
-
);
|
|
34474
|
-
process.exit(2);
|
|
34475
|
-
}
|
|
34476
|
-
}
|
|
34477
34742
|
program2.parseAsync(process.argv).catch((err) => {
|
|
34478
34743
|
process.stderr.write(`slock-computer: ${err instanceof Error ? err.message : String(err)}
|
|
34479
34744
|
`);
|