@slock-ai/computer 0.0.16-alpha.0 → 0.0.17
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 +621 -292
- package/dist/lib/index.d.ts +173 -73
- package/dist/lib/index.js +380 -108
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5729,9 +5729,9 @@ var require_dispatcher_base = __commonJS({
|
|
|
5729
5729
|
}
|
|
5730
5730
|
close(callback) {
|
|
5731
5731
|
if (callback === void 0) {
|
|
5732
|
-
return new Promise((
|
|
5732
|
+
return new Promise((resolve2, reject) => {
|
|
5733
5733
|
this.close((err, data) => {
|
|
5734
|
-
return err ? reject(err) :
|
|
5734
|
+
return err ? reject(err) : resolve2(data);
|
|
5735
5735
|
});
|
|
5736
5736
|
});
|
|
5737
5737
|
}
|
|
@@ -5769,9 +5769,9 @@ var require_dispatcher_base = __commonJS({
|
|
|
5769
5769
|
err = null;
|
|
5770
5770
|
}
|
|
5771
5771
|
if (callback === void 0) {
|
|
5772
|
-
return new Promise((
|
|
5772
|
+
return new Promise((resolve2, reject) => {
|
|
5773
5773
|
this.destroy(err, (err2, data) => {
|
|
5774
|
-
return err2 ? reject(err2) :
|
|
5774
|
+
return err2 ? reject(err2) : resolve2(data);
|
|
5775
5775
|
});
|
|
5776
5776
|
});
|
|
5777
5777
|
}
|
|
@@ -9264,8 +9264,8 @@ var require_promise = __commonJS({
|
|
|
9264
9264
|
function createDeferredPromise() {
|
|
9265
9265
|
let res;
|
|
9266
9266
|
let rej;
|
|
9267
|
-
const promise = new Promise((
|
|
9268
|
-
res =
|
|
9267
|
+
const promise = new Promise((resolve2, reject) => {
|
|
9268
|
+
res = resolve2;
|
|
9269
9269
|
rej = reject;
|
|
9270
9270
|
});
|
|
9271
9271
|
return { promise, resolve: res, reject: rej };
|
|
@@ -10568,12 +10568,12 @@ upgrade: ${upgrade}\r
|
|
|
10568
10568
|
cb();
|
|
10569
10569
|
}
|
|
10570
10570
|
}
|
|
10571
|
-
const waitForDrain = () => new Promise((
|
|
10571
|
+
const waitForDrain = () => new Promise((resolve2, reject) => {
|
|
10572
10572
|
assert(callback === null);
|
|
10573
10573
|
if (socket[kError]) {
|
|
10574
10574
|
reject(socket[kError]);
|
|
10575
10575
|
} else {
|
|
10576
|
-
callback =
|
|
10576
|
+
callback = resolve2;
|
|
10577
10577
|
}
|
|
10578
10578
|
});
|
|
10579
10579
|
socket.on("close", onDrain).on("drain", onDrain);
|
|
@@ -11419,12 +11419,12 @@ var require_client_h2 = __commonJS({
|
|
|
11419
11419
|
cb();
|
|
11420
11420
|
}
|
|
11421
11421
|
}
|
|
11422
|
-
const waitForDrain = () => new Promise((
|
|
11422
|
+
const waitForDrain = () => new Promise((resolve2, reject) => {
|
|
11423
11423
|
assert(callback === null);
|
|
11424
11424
|
if (socket[kError]) {
|
|
11425
11425
|
reject(socket[kError]);
|
|
11426
11426
|
} else {
|
|
11427
|
-
callback =
|
|
11427
|
+
callback = resolve2;
|
|
11428
11428
|
}
|
|
11429
11429
|
});
|
|
11430
11430
|
h2stream.on("close", onDrain).on("drain", onDrain);
|
|
@@ -11736,16 +11736,16 @@ var require_client = __commonJS({
|
|
|
11736
11736
|
return this[kNeedDrain] < 2;
|
|
11737
11737
|
}
|
|
11738
11738
|
[kClose]() {
|
|
11739
|
-
return new Promise((
|
|
11739
|
+
return new Promise((resolve2) => {
|
|
11740
11740
|
if (this[kSize]) {
|
|
11741
|
-
this[kClosedResolve] =
|
|
11741
|
+
this[kClosedResolve] = resolve2;
|
|
11742
11742
|
} else {
|
|
11743
|
-
|
|
11743
|
+
resolve2(null);
|
|
11744
11744
|
}
|
|
11745
11745
|
});
|
|
11746
11746
|
}
|
|
11747
11747
|
[kDestroy](err) {
|
|
11748
|
-
return new Promise((
|
|
11748
|
+
return new Promise((resolve2) => {
|
|
11749
11749
|
const requests = this[kQueue].splice(this[kPendingIdx]);
|
|
11750
11750
|
for (let i = 0; i < requests.length; i++) {
|
|
11751
11751
|
const request = requests[i];
|
|
@@ -11756,7 +11756,7 @@ var require_client = __commonJS({
|
|
|
11756
11756
|
this[kClosedResolve]();
|
|
11757
11757
|
this[kClosedResolve] = null;
|
|
11758
11758
|
}
|
|
11759
|
-
|
|
11759
|
+
resolve2(null);
|
|
11760
11760
|
};
|
|
11761
11761
|
if (this[kHTTPContext]) {
|
|
11762
11762
|
this[kHTTPContext].destroy(err, callback);
|
|
@@ -12163,8 +12163,8 @@ var require_pool_base = __commonJS({
|
|
|
12163
12163
|
}
|
|
12164
12164
|
return Promise.all(closeAll);
|
|
12165
12165
|
} else {
|
|
12166
|
-
return new Promise((
|
|
12167
|
-
this[kClosedResolve] =
|
|
12166
|
+
return new Promise((resolve2) => {
|
|
12167
|
+
this[kClosedResolve] = resolve2;
|
|
12168
12168
|
});
|
|
12169
12169
|
}
|
|
12170
12170
|
}
|
|
@@ -13263,10 +13263,10 @@ var require_socks5_proxy_agent = __commonJS({
|
|
|
13263
13263
|
const proxyHost = this[kProxyUrl].hostname;
|
|
13264
13264
|
const proxyPort = parseInt(this[kProxyUrl].port) || 1080;
|
|
13265
13265
|
debug("creating SOCKS5 connection to", proxyHost, proxyPort);
|
|
13266
|
-
const socket = await new Promise((
|
|
13266
|
+
const socket = await new Promise((resolve2, reject) => {
|
|
13267
13267
|
const onConnect = () => {
|
|
13268
13268
|
socket2.removeListener("error", onError);
|
|
13269
|
-
|
|
13269
|
+
resolve2(socket2);
|
|
13270
13270
|
};
|
|
13271
13271
|
const onError = (err) => {
|
|
13272
13272
|
socket2.removeListener("connect", onConnect);
|
|
@@ -13285,14 +13285,14 @@ var require_socks5_proxy_agent = __commonJS({
|
|
|
13285
13285
|
socket.destroy();
|
|
13286
13286
|
});
|
|
13287
13287
|
await socks5Client.handshake();
|
|
13288
|
-
await new Promise((
|
|
13288
|
+
await new Promise((resolve2, reject) => {
|
|
13289
13289
|
const timeout = setTimeout(() => {
|
|
13290
13290
|
reject(new Error("SOCKS5 authentication timeout"));
|
|
13291
13291
|
}, 5e3);
|
|
13292
13292
|
const onAuthenticated = () => {
|
|
13293
13293
|
clearTimeout(timeout);
|
|
13294
13294
|
socks5Client.removeListener("error", onError);
|
|
13295
|
-
|
|
13295
|
+
resolve2();
|
|
13296
13296
|
};
|
|
13297
13297
|
const onError = (err) => {
|
|
13298
13298
|
clearTimeout(timeout);
|
|
@@ -13301,14 +13301,14 @@ var require_socks5_proxy_agent = __commonJS({
|
|
|
13301
13301
|
};
|
|
13302
13302
|
if (socks5Client.state === "authenticated") {
|
|
13303
13303
|
clearTimeout(timeout);
|
|
13304
|
-
|
|
13304
|
+
resolve2();
|
|
13305
13305
|
} else {
|
|
13306
13306
|
socks5Client.once("authenticated", onAuthenticated);
|
|
13307
13307
|
socks5Client.once("error", onError);
|
|
13308
13308
|
}
|
|
13309
13309
|
});
|
|
13310
13310
|
await socks5Client.connect(targetHost, targetPort);
|
|
13311
|
-
await new Promise((
|
|
13311
|
+
await new Promise((resolve2, reject) => {
|
|
13312
13312
|
const timeout = setTimeout(() => {
|
|
13313
13313
|
reject(new Error("SOCKS5 connection timeout"));
|
|
13314
13314
|
}, 5e3);
|
|
@@ -13316,7 +13316,7 @@ var require_socks5_proxy_agent = __commonJS({
|
|
|
13316
13316
|
debug("SOCKS5 tunnel established to", targetHost, targetPort, "via", info2);
|
|
13317
13317
|
clearTimeout(timeout);
|
|
13318
13318
|
socks5Client.removeListener("error", onError);
|
|
13319
|
-
|
|
13319
|
+
resolve2();
|
|
13320
13320
|
};
|
|
13321
13321
|
const onError = (err) => {
|
|
13322
13322
|
clearTimeout(timeout);
|
|
@@ -13357,8 +13357,8 @@ var require_socks5_proxy_agent = __commonJS({
|
|
|
13357
13357
|
servername: targetHost,
|
|
13358
13358
|
...connectOpts.tls || {}
|
|
13359
13359
|
});
|
|
13360
|
-
await new Promise((
|
|
13361
|
-
finalSocket.once("secureConnect",
|
|
13360
|
+
await new Promise((resolve2, reject) => {
|
|
13361
|
+
finalSocket.once("secureConnect", resolve2);
|
|
13362
13362
|
finalSocket.once("error", reject);
|
|
13363
13363
|
});
|
|
13364
13364
|
}
|
|
@@ -14389,7 +14389,7 @@ var require_readable = __commonJS({
|
|
|
14389
14389
|
if (this._readableState.closeEmitted) {
|
|
14390
14390
|
return Promise.resolve(null);
|
|
14391
14391
|
}
|
|
14392
|
-
return new Promise((
|
|
14392
|
+
return new Promise((resolve2, reject) => {
|
|
14393
14393
|
if (this[kContentLength] && this[kContentLength] > limit || this[kBytesRead] > limit) {
|
|
14394
14394
|
this.destroy(new AbortError());
|
|
14395
14395
|
}
|
|
@@ -14403,11 +14403,11 @@ var require_readable = __commonJS({
|
|
|
14403
14403
|
if (signal.aborted) {
|
|
14404
14404
|
reject(signal.reason ?? new AbortError());
|
|
14405
14405
|
} else {
|
|
14406
|
-
|
|
14406
|
+
resolve2(null);
|
|
14407
14407
|
}
|
|
14408
14408
|
});
|
|
14409
14409
|
} else {
|
|
14410
|
-
this.on("close",
|
|
14410
|
+
this.on("close", resolve2);
|
|
14411
14411
|
}
|
|
14412
14412
|
this.on("error", noop).on("data", () => {
|
|
14413
14413
|
if (this[kBytesRead] > limit) {
|
|
@@ -14435,7 +14435,7 @@ var require_readable = __commonJS({
|
|
|
14435
14435
|
}
|
|
14436
14436
|
function consume(stream, type) {
|
|
14437
14437
|
assert(!stream[kConsume]);
|
|
14438
|
-
return new Promise((
|
|
14438
|
+
return new Promise((resolve2, reject) => {
|
|
14439
14439
|
if (isUnusable(stream)) {
|
|
14440
14440
|
const rState = stream._readableState;
|
|
14441
14441
|
if (rState.destroyed && rState.closeEmitted === false) {
|
|
@@ -14450,7 +14450,7 @@ var require_readable = __commonJS({
|
|
|
14450
14450
|
stream[kConsume] = {
|
|
14451
14451
|
type,
|
|
14452
14452
|
stream,
|
|
14453
|
-
resolve,
|
|
14453
|
+
resolve: resolve2,
|
|
14454
14454
|
reject,
|
|
14455
14455
|
length: 0,
|
|
14456
14456
|
body: []
|
|
@@ -14524,18 +14524,18 @@ var require_readable = __commonJS({
|
|
|
14524
14524
|
return buffer;
|
|
14525
14525
|
}
|
|
14526
14526
|
function consumeEnd(consume2, encoding) {
|
|
14527
|
-
const { type, body, resolve, stream, length } = consume2;
|
|
14527
|
+
const { type, body, resolve: resolve2, stream, length } = consume2;
|
|
14528
14528
|
try {
|
|
14529
14529
|
if (type === "text") {
|
|
14530
|
-
|
|
14530
|
+
resolve2(chunksDecode(body, length, encoding));
|
|
14531
14531
|
} else if (type === "json") {
|
|
14532
|
-
|
|
14532
|
+
resolve2(JSON.parse(chunksDecode(body, length, encoding)));
|
|
14533
14533
|
} else if (type === "arrayBuffer") {
|
|
14534
|
-
|
|
14534
|
+
resolve2(chunksConcat(body, length).buffer);
|
|
14535
14535
|
} else if (type === "blob") {
|
|
14536
|
-
|
|
14536
|
+
resolve2(new Blob(body, { type: stream[kContentType] }));
|
|
14537
14537
|
} else if (type === "bytes") {
|
|
14538
|
-
|
|
14538
|
+
resolve2(chunksConcat(body, length));
|
|
14539
14539
|
}
|
|
14540
14540
|
consumeFinish(consume2);
|
|
14541
14541
|
} catch (err) {
|
|
@@ -14726,9 +14726,9 @@ var require_api_request = __commonJS({
|
|
|
14726
14726
|
};
|
|
14727
14727
|
function request(opts, callback) {
|
|
14728
14728
|
if (callback === void 0) {
|
|
14729
|
-
return new Promise((
|
|
14729
|
+
return new Promise((resolve2, reject) => {
|
|
14730
14730
|
request.call(this, opts, (err, data) => {
|
|
14731
|
-
return err ? reject(err) :
|
|
14731
|
+
return err ? reject(err) : resolve2(data);
|
|
14732
14732
|
});
|
|
14733
14733
|
});
|
|
14734
14734
|
}
|
|
@@ -14942,9 +14942,9 @@ var require_api_stream = __commonJS({
|
|
|
14942
14942
|
};
|
|
14943
14943
|
function stream(opts, factory, callback) {
|
|
14944
14944
|
if (callback === void 0) {
|
|
14945
|
-
return new Promise((
|
|
14945
|
+
return new Promise((resolve2, reject) => {
|
|
14946
14946
|
stream.call(this, opts, factory, (err, data) => {
|
|
14947
|
-
return err ? reject(err) :
|
|
14947
|
+
return err ? reject(err) : resolve2(data);
|
|
14948
14948
|
});
|
|
14949
14949
|
});
|
|
14950
14950
|
}
|
|
@@ -15234,9 +15234,9 @@ var require_api_upgrade = __commonJS({
|
|
|
15234
15234
|
};
|
|
15235
15235
|
function upgrade(opts, callback) {
|
|
15236
15236
|
if (callback === void 0) {
|
|
15237
|
-
return new Promise((
|
|
15237
|
+
return new Promise((resolve2, reject) => {
|
|
15238
15238
|
upgrade.call(this, opts, (err, data) => {
|
|
15239
|
-
return err ? reject(err) :
|
|
15239
|
+
return err ? reject(err) : resolve2(data);
|
|
15240
15240
|
});
|
|
15241
15241
|
});
|
|
15242
15242
|
}
|
|
@@ -15330,9 +15330,9 @@ var require_api_connect = __commonJS({
|
|
|
15330
15330
|
};
|
|
15331
15331
|
function connect(opts, callback) {
|
|
15332
15332
|
if (callback === void 0) {
|
|
15333
|
-
return new Promise((
|
|
15333
|
+
return new Promise((resolve2, reject) => {
|
|
15334
15334
|
connect.call(this, opts, (err, data) => {
|
|
15335
|
-
return err ? reject(err) :
|
|
15335
|
+
return err ? reject(err) : resolve2(data);
|
|
15336
15336
|
});
|
|
15337
15337
|
});
|
|
15338
15338
|
}
|
|
@@ -16618,7 +16618,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
16618
16618
|
"use strict";
|
|
16619
16619
|
init_esm_shims();
|
|
16620
16620
|
var { writeFile: writeFile13, readFile: readFile17, mkdir: mkdir17 } = __require("fs/promises");
|
|
16621
|
-
var { dirname: dirname14, resolve } = __require("path");
|
|
16621
|
+
var { dirname: dirname14, resolve: resolve2 } = __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 readFile17(
|
|
16822
|
+
const data = await readFile17(resolve2(path3), "utf8");
|
|
16823
16823
|
const parsed = JSON.parse(data);
|
|
16824
16824
|
if (Array.isArray(parsed)) {
|
|
16825
16825
|
this.#snapshots.clear();
|
|
@@ -16848,7 +16848,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
16848
16848
|
if (!path3) {
|
|
16849
16849
|
throw new InvalidArgumentError2("Snapshot path is required");
|
|
16850
16850
|
}
|
|
16851
|
-
const resolvedPath =
|
|
16851
|
+
const resolvedPath = resolve2(path3);
|
|
16852
16852
|
await mkdir17(dirname14(resolvedPath), { recursive: true });
|
|
16853
16853
|
const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
16854
16854
|
hash,
|
|
@@ -23714,7 +23714,7 @@ var require_fetch = __commonJS({
|
|
|
23714
23714
|
const agent = fetchParams.controller.dispatcher;
|
|
23715
23715
|
const path3 = url.pathname + url.search;
|
|
23716
23716
|
const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
|
|
23717
|
-
return new Promise((
|
|
23717
|
+
return new Promise((resolve2, reject) => agent.dispatch(
|
|
23718
23718
|
{
|
|
23719
23719
|
path: hasTrailingQuestionMark ? `${path3}?` : path3,
|
|
23720
23720
|
origin: url.origin,
|
|
@@ -23802,7 +23802,7 @@ var require_fetch = __commonJS({
|
|
|
23802
23802
|
}
|
|
23803
23803
|
}
|
|
23804
23804
|
const onError = this.onError.bind(this);
|
|
23805
|
-
|
|
23805
|
+
resolve2({
|
|
23806
23806
|
status,
|
|
23807
23807
|
statusText,
|
|
23808
23808
|
headersList,
|
|
@@ -23855,7 +23855,7 @@ var require_fetch = __commonJS({
|
|
|
23855
23855
|
headersList.append(headerName, String(value), true);
|
|
23856
23856
|
}
|
|
23857
23857
|
}
|
|
23858
|
-
|
|
23858
|
+
resolve2({
|
|
23859
23859
|
status,
|
|
23860
23860
|
statusText: STATUS_CODES[status],
|
|
23861
23861
|
headersList,
|
|
@@ -23879,7 +23879,7 @@ var require_fetch = __commonJS({
|
|
|
23879
23879
|
headersList.append(nameStr, value.toString("latin1"), true);
|
|
23880
23880
|
}
|
|
23881
23881
|
}
|
|
23882
|
-
|
|
23882
|
+
resolve2({
|
|
23883
23883
|
status,
|
|
23884
23884
|
statusText: STATUS_CODES[status],
|
|
23885
23885
|
headersList,
|
|
@@ -29193,11 +29193,11 @@ var require_mtime_precision = __commonJS({
|
|
|
29193
29193
|
function probe(file, fs, callback) {
|
|
29194
29194
|
const cachedPrecision = fs[cacheSymbol];
|
|
29195
29195
|
if (cachedPrecision) {
|
|
29196
|
-
return fs.stat(file, (err,
|
|
29196
|
+
return fs.stat(file, (err, stat5) => {
|
|
29197
29197
|
if (err) {
|
|
29198
29198
|
return callback(err);
|
|
29199
29199
|
}
|
|
29200
|
-
callback(null,
|
|
29200
|
+
callback(null, stat5.mtime, cachedPrecision);
|
|
29201
29201
|
});
|
|
29202
29202
|
}
|
|
29203
29203
|
const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
|
|
@@ -29205,13 +29205,13 @@ var require_mtime_precision = __commonJS({
|
|
|
29205
29205
|
if (err) {
|
|
29206
29206
|
return callback(err);
|
|
29207
29207
|
}
|
|
29208
|
-
fs.stat(file, (err2,
|
|
29208
|
+
fs.stat(file, (err2, stat5) => {
|
|
29209
29209
|
if (err2) {
|
|
29210
29210
|
return callback(err2);
|
|
29211
29211
|
}
|
|
29212
|
-
const precision =
|
|
29212
|
+
const precision = stat5.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
|
|
29213
29213
|
Object.defineProperty(fs, cacheSymbol, { value: precision });
|
|
29214
|
-
callback(null,
|
|
29214
|
+
callback(null, stat5.mtime, precision);
|
|
29215
29215
|
});
|
|
29216
29216
|
});
|
|
29217
29217
|
}
|
|
@@ -29266,14 +29266,14 @@ var require_lockfile = __commonJS({
|
|
|
29266
29266
|
if (options.stale <= 0) {
|
|
29267
29267
|
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
29268
29268
|
}
|
|
29269
|
-
options.fs.stat(lockfilePath, (err2,
|
|
29269
|
+
options.fs.stat(lockfilePath, (err2, stat5) => {
|
|
29270
29270
|
if (err2) {
|
|
29271
29271
|
if (err2.code === "ENOENT") {
|
|
29272
29272
|
return acquireLock(file, { ...options, stale: 0 }, callback);
|
|
29273
29273
|
}
|
|
29274
29274
|
return callback(err2);
|
|
29275
29275
|
}
|
|
29276
|
-
if (!isLockStale(
|
|
29276
|
+
if (!isLockStale(stat5, options)) {
|
|
29277
29277
|
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
29278
29278
|
}
|
|
29279
29279
|
removeLock(file, options, (err3) => {
|
|
@@ -29285,8 +29285,8 @@ var require_lockfile = __commonJS({
|
|
|
29285
29285
|
});
|
|
29286
29286
|
});
|
|
29287
29287
|
}
|
|
29288
|
-
function isLockStale(
|
|
29289
|
-
return
|
|
29288
|
+
function isLockStale(stat5, options) {
|
|
29289
|
+
return stat5.mtime.getTime() < Date.now() - options.stale;
|
|
29290
29290
|
}
|
|
29291
29291
|
function removeLock(file, options, callback) {
|
|
29292
29292
|
options.fs.rmdir(getLockFile(file, options), (err) => {
|
|
@@ -29304,7 +29304,7 @@ var require_lockfile = __commonJS({
|
|
|
29304
29304
|
lock2.updateDelay = lock2.updateDelay || options.update;
|
|
29305
29305
|
lock2.updateTimeout = setTimeout(() => {
|
|
29306
29306
|
lock2.updateTimeout = null;
|
|
29307
|
-
options.fs.stat(lock2.lockfilePath, (err,
|
|
29307
|
+
options.fs.stat(lock2.lockfilePath, (err, stat5) => {
|
|
29308
29308
|
const isOverThreshold = lock2.lastUpdate + options.stale < Date.now();
|
|
29309
29309
|
if (err) {
|
|
29310
29310
|
if (err.code === "ENOENT" || isOverThreshold) {
|
|
@@ -29313,7 +29313,7 @@ var require_lockfile = __commonJS({
|
|
|
29313
29313
|
lock2.updateDelay = 1e3;
|
|
29314
29314
|
return updateLock(file, options);
|
|
29315
29315
|
}
|
|
29316
|
-
const isMtimeOurs = lock2.mtime.getTime() ===
|
|
29316
|
+
const isMtimeOurs = lock2.mtime.getTime() === stat5.mtime.getTime();
|
|
29317
29317
|
if (!isMtimeOurs) {
|
|
29318
29318
|
return setLockAsCompromised(
|
|
29319
29319
|
file,
|
|
@@ -29438,11 +29438,11 @@ var require_lockfile = __commonJS({
|
|
|
29438
29438
|
if (err) {
|
|
29439
29439
|
return callback(err);
|
|
29440
29440
|
}
|
|
29441
|
-
options.fs.stat(getLockFile(file2, options), (err2,
|
|
29441
|
+
options.fs.stat(getLockFile(file2, options), (err2, stat5) => {
|
|
29442
29442
|
if (err2) {
|
|
29443
29443
|
return err2.code === "ENOENT" ? callback(null, false) : callback(err2);
|
|
29444
29444
|
}
|
|
29445
|
-
return callback(null, !isLockStale(
|
|
29445
|
+
return callback(null, !isLockStale(stat5, options));
|
|
29446
29446
|
});
|
|
29447
29447
|
});
|
|
29448
29448
|
}
|
|
@@ -29489,12 +29489,12 @@ var require_adapter = __commonJS({
|
|
|
29489
29489
|
return newFs;
|
|
29490
29490
|
}
|
|
29491
29491
|
function toPromise(method) {
|
|
29492
|
-
return (...args) => new Promise((
|
|
29492
|
+
return (...args) => new Promise((resolve2, reject) => {
|
|
29493
29493
|
args.push((err, result) => {
|
|
29494
29494
|
if (err) {
|
|
29495
29495
|
reject(err);
|
|
29496
29496
|
} else {
|
|
29497
|
-
|
|
29497
|
+
resolve2(result);
|
|
29498
29498
|
}
|
|
29499
29499
|
});
|
|
29500
29500
|
method(...args);
|
|
@@ -29799,6 +29799,52 @@ var ComputerAttachClient = class {
|
|
|
29799
29799
|
return { ok: false, code };
|
|
29800
29800
|
}
|
|
29801
29801
|
};
|
|
29802
|
+
var LegacyMachinesClient = class {
|
|
29803
|
+
constructor(baseUrl, accessToken) {
|
|
29804
|
+
this.baseUrl = baseUrl;
|
|
29805
|
+
this.accessToken = accessToken;
|
|
29806
|
+
}
|
|
29807
|
+
url(p) {
|
|
29808
|
+
return new URL(p, this.baseUrl).toString();
|
|
29809
|
+
}
|
|
29810
|
+
async list(serverSlug) {
|
|
29811
|
+
let res;
|
|
29812
|
+
try {
|
|
29813
|
+
res = await (0, import_undici.fetch)(
|
|
29814
|
+
this.url(`/api/computer/legacy-machines?serverSlug=${encodeURIComponent(serverSlug)}`),
|
|
29815
|
+
{
|
|
29816
|
+
method: "GET",
|
|
29817
|
+
headers: { Authorization: `Bearer ${this.accessToken}` }
|
|
29818
|
+
}
|
|
29819
|
+
);
|
|
29820
|
+
} catch {
|
|
29821
|
+
return { status: "error", code: "request_failed" };
|
|
29822
|
+
}
|
|
29823
|
+
const body = await res.json().catch(() => null);
|
|
29824
|
+
if (res.status === 200 && body && Array.isArray(body.entries)) {
|
|
29825
|
+
const entries = body.entries.map((raw) => {
|
|
29826
|
+
if (!raw || typeof raw !== "object") return null;
|
|
29827
|
+
const e = raw;
|
|
29828
|
+
if (typeof e.daemonId !== "string" || typeof e.apiKeyFingerprint !== "string" || typeof e.machineName !== "string") {
|
|
29829
|
+
return null;
|
|
29830
|
+
}
|
|
29831
|
+
return {
|
|
29832
|
+
daemonId: e.daemonId,
|
|
29833
|
+
apiKeyFingerprint: e.apiKeyFingerprint,
|
|
29834
|
+
machineName: e.machineName,
|
|
29835
|
+
hostname: typeof e.hostname === "string" ? e.hostname : null,
|
|
29836
|
+
lastSeenAt: typeof e.lastSeenAt === "string" ? e.lastSeenAt : null
|
|
29837
|
+
};
|
|
29838
|
+
}).filter((entry) => entry !== null);
|
|
29839
|
+
return { status: "success", entries };
|
|
29840
|
+
}
|
|
29841
|
+
if (res.status === 401) return { status: "auth_required" };
|
|
29842
|
+
if (res.status === 403) return { status: "not_authorized" };
|
|
29843
|
+
if (res.status === 404) return { status: "disabled" };
|
|
29844
|
+
const code = body && typeof body.code === "string" ? body.code : `http_${res.status}`;
|
|
29845
|
+
return { status: "error", code };
|
|
29846
|
+
}
|
|
29847
|
+
};
|
|
29802
29848
|
var RunnersClient = class {
|
|
29803
29849
|
constructor(baseUrl, computerApiKey) {
|
|
29804
29850
|
this.baseUrl = baseUrl;
|
|
@@ -29879,11 +29925,11 @@ function serverDir(slockHome, serverId) {
|
|
|
29879
29925
|
function serverAttachmentPath(slockHome, serverId) {
|
|
29880
29926
|
return path2.join(serverDir(slockHome, serverId), "runner.state.json");
|
|
29881
29927
|
}
|
|
29882
|
-
function
|
|
29883
|
-
return path2.join(serverDir(slockHome, serverId), "
|
|
29928
|
+
function serverRunnerPidPath(slockHome, serverId) {
|
|
29929
|
+
return path2.join(serverDir(slockHome, serverId), "server-runner.pid");
|
|
29884
29930
|
}
|
|
29885
|
-
function
|
|
29886
|
-
return path2.join(serverDir(slockHome, serverId), "
|
|
29931
|
+
function serverRunnerLogPath(slockHome, serverId) {
|
|
29932
|
+
return path2.join(serverDir(slockHome, serverId), "server-runner.log");
|
|
29887
29933
|
}
|
|
29888
29934
|
function serverManagedFlagPath(slockHome, serverId) {
|
|
29889
29935
|
return path2.join(serverDir(slockHome, serverId), "managed.flag");
|
|
@@ -29891,17 +29937,30 @@ function serverManagedFlagPath(slockHome, serverId) {
|
|
|
29891
29937
|
function serverHealthPath(slockHome, serverId) {
|
|
29892
29938
|
return path2.join(serverDir(slockHome, serverId), "health.json");
|
|
29893
29939
|
}
|
|
29940
|
+
function serviceRunDir(slockHome) {
|
|
29941
|
+
return path2.join(computerDir(slockHome), "run");
|
|
29942
|
+
}
|
|
29894
29943
|
function serviceStatePath(slockHome) {
|
|
29895
|
-
return path2.join(
|
|
29944
|
+
return path2.join(serviceRunDir(slockHome), "service.state.json");
|
|
29896
29945
|
}
|
|
29897
29946
|
function servicePidPath(slockHome) {
|
|
29947
|
+
return path2.join(serviceRunDir(slockHome), "service.pid");
|
|
29948
|
+
}
|
|
29949
|
+
function legacyServicePidPath(slockHome) {
|
|
29898
29950
|
return path2.join(computerDir(slockHome), "service.pid");
|
|
29899
29951
|
}
|
|
29900
29952
|
function legacySupervisorPidPath(slockHome) {
|
|
29901
29953
|
return path2.join(computerDir(slockHome), "supervisor.pid");
|
|
29902
29954
|
}
|
|
29955
|
+
function servicePidReadFallback(slockHome) {
|
|
29956
|
+
return [
|
|
29957
|
+
servicePidPath(slockHome),
|
|
29958
|
+
legacyServicePidPath(slockHome),
|
|
29959
|
+
legacySupervisorPidPath(slockHome)
|
|
29960
|
+
];
|
|
29961
|
+
}
|
|
29903
29962
|
function serviceLogPath(slockHome) {
|
|
29904
|
-
return path2.join(
|
|
29963
|
+
return path2.join(serviceRunDir(slockHome), "service.log");
|
|
29905
29964
|
}
|
|
29906
29965
|
function serviceVersionPath(slockHome) {
|
|
29907
29966
|
return path2.join(computerDir(slockHome), "service-version.json");
|
|
@@ -29962,14 +30021,14 @@ function resolveServerUrl(...candidates) {
|
|
|
29962
30021
|
|
|
29963
30022
|
// src/services/login.ts
|
|
29964
30023
|
function sleep(ms, signal) {
|
|
29965
|
-
return new Promise((
|
|
30024
|
+
return new Promise((resolve2, reject) => {
|
|
29966
30025
|
if (signal?.aborted) {
|
|
29967
30026
|
reject(abortError(signal));
|
|
29968
30027
|
return;
|
|
29969
30028
|
}
|
|
29970
30029
|
const t = setTimeout(() => {
|
|
29971
30030
|
signal?.removeEventListener("abort", onAbort);
|
|
29972
|
-
|
|
30031
|
+
resolve2();
|
|
29973
30032
|
}, ms);
|
|
29974
30033
|
const onAbort = () => {
|
|
29975
30034
|
clearTimeout(t);
|
|
@@ -30390,68 +30449,153 @@ import { dirname as dirname9 } from "path";
|
|
|
30390
30449
|
|
|
30391
30450
|
// src/lib/migration.ts
|
|
30392
30451
|
init_esm_shims();
|
|
30393
|
-
import { readdir as readdir2, readFile as readFile3 } from "fs/promises";
|
|
30394
|
-
import { join } from "path";
|
|
30452
|
+
import { readdir as readdir2, readFile as readFile3, stat } from "fs/promises";
|
|
30453
|
+
import { join, resolve } from "path";
|
|
30395
30454
|
var MACHINE_DIR_PREFIX = "machine-";
|
|
30396
|
-
|
|
30397
|
-
|
|
30398
|
-
|
|
30399
|
-
|
|
30400
|
-
|
|
30401
|
-
|
|
30402
|
-
|
|
30403
|
-
|
|
30455
|
+
var FINGERPRINT_HEX_RE = /^[0-9a-f]{16}$/;
|
|
30456
|
+
async function readLocalOwners(installRoot) {
|
|
30457
|
+
const machinesDir = join(installRoot, "machines");
|
|
30458
|
+
let entries;
|
|
30459
|
+
try {
|
|
30460
|
+
entries = await readdir2(machinesDir);
|
|
30461
|
+
} catch {
|
|
30462
|
+
return [];
|
|
30463
|
+
}
|
|
30464
|
+
const owners = [];
|
|
30465
|
+
for (const name of entries) {
|
|
30466
|
+
if (!name.startsWith(MACHINE_DIR_PREFIX)) continue;
|
|
30467
|
+
const ownerPath = join(machinesDir, name, "daemon.lock", "owner.json");
|
|
30468
|
+
let raw;
|
|
30469
|
+
try {
|
|
30470
|
+
raw = await readFile3(ownerPath, "utf8");
|
|
30471
|
+
} catch {
|
|
30472
|
+
continue;
|
|
30473
|
+
}
|
|
30474
|
+
let parsed;
|
|
30475
|
+
try {
|
|
30476
|
+
parsed = JSON.parse(raw);
|
|
30477
|
+
} catch {
|
|
30478
|
+
continue;
|
|
30479
|
+
}
|
|
30480
|
+
const fp = parsed.apiKeyFingerprint;
|
|
30481
|
+
if (typeof fp !== "string" || !FINGERPRINT_HEX_RE.test(fp)) continue;
|
|
30482
|
+
owners.push({ apiKeyFingerprint: fp, localPath: ownerPath });
|
|
30483
|
+
}
|
|
30484
|
+
return owners;
|
|
30485
|
+
}
|
|
30486
|
+
function indexLocalByFingerprint(owners) {
|
|
30487
|
+
const map = /* @__PURE__ */ new Map();
|
|
30488
|
+
for (const owner of owners) {
|
|
30489
|
+
if (!map.has(owner.apiKeyFingerprint)) {
|
|
30490
|
+
map.set(owner.apiKeyFingerprint, owner);
|
|
30491
|
+
}
|
|
30492
|
+
}
|
|
30493
|
+
return map;
|
|
30494
|
+
}
|
|
30495
|
+
function intersect(localByFp, roster) {
|
|
30496
|
+
const out = [];
|
|
30497
|
+
for (const entry of roster) {
|
|
30498
|
+
const local = localByFp.get(entry.apiKeyFingerprint);
|
|
30499
|
+
if (!local) continue;
|
|
30500
|
+
out.push({
|
|
30501
|
+
apiKeyFingerprint: entry.apiKeyFingerprint,
|
|
30502
|
+
daemonId: entry.daemonId,
|
|
30503
|
+
localPath: local.localPath,
|
|
30504
|
+
machineName: entry.machineName,
|
|
30505
|
+
...entry.hostname ? { hostname: entry.hostname } : {},
|
|
30506
|
+
...entry.lastSeenAt ? { lastSeenAt: entry.lastSeenAt } : {}
|
|
30507
|
+
});
|
|
30508
|
+
}
|
|
30509
|
+
out.sort((a, b) => {
|
|
30510
|
+
const aSeen = a.lastSeenAt ?? "";
|
|
30511
|
+
const bSeen = b.lastSeenAt ?? "";
|
|
30512
|
+
if (aSeen !== bSeen) {
|
|
30513
|
+
if (aSeen === "") return 1;
|
|
30514
|
+
if (bSeen === "") return -1;
|
|
30515
|
+
return aSeen < bSeen ? 1 : -1;
|
|
30516
|
+
}
|
|
30517
|
+
return a.apiKeyFingerprint < b.apiKeyFingerprint ? -1 : a.apiKeyFingerprint > b.apiKeyFingerprint ? 1 : 0;
|
|
30518
|
+
});
|
|
30519
|
+
return out;
|
|
30520
|
+
}
|
|
30521
|
+
async function detectLegacyMigration(installRoot, serverSlug, client) {
|
|
30522
|
+
const localOwners = await readLocalOwners(installRoot);
|
|
30523
|
+
if (localOwners.length === 0) {
|
|
30524
|
+
return { kind: "candidates", candidates: [] };
|
|
30525
|
+
}
|
|
30526
|
+
const result = await client.list(serverSlug);
|
|
30527
|
+
if (result.status !== "success") {
|
|
30528
|
+
return { kind: "server-unavailable" };
|
|
30529
|
+
}
|
|
30530
|
+
const localByFp = indexLocalByFingerprint(localOwners);
|
|
30531
|
+
return { kind: "candidates", candidates: intersect(localByFp, result.entries) };
|
|
30532
|
+
}
|
|
30533
|
+
async function validateManualMigratePath(inputPath, roster) {
|
|
30534
|
+
const absInput = resolve(inputPath);
|
|
30535
|
+
let stats;
|
|
30536
|
+
try {
|
|
30537
|
+
stats = await stat(absInput);
|
|
30538
|
+
} catch {
|
|
30539
|
+
return { ok: false, code: "MIGRATE_FROM_NOT_FOUND" };
|
|
30540
|
+
}
|
|
30541
|
+
const ownerPath = stats.isDirectory() ? join(absInput, "daemon.lock", "owner.json") : absInput;
|
|
30542
|
+
const candidateOwnerPath = await firstReadableOwner([
|
|
30543
|
+
ownerPath,
|
|
30544
|
+
join(absInput, "owner.json"),
|
|
30545
|
+
absInput
|
|
30546
|
+
]);
|
|
30547
|
+
if (!candidateOwnerPath) {
|
|
30548
|
+
return { ok: false, code: "MIGRATE_FROM_INVALID" };
|
|
30549
|
+
}
|
|
30404
30550
|
let raw;
|
|
30405
30551
|
try {
|
|
30406
|
-
raw = await readFile3(
|
|
30552
|
+
raw = await readFile3(candidateOwnerPath, "utf8");
|
|
30407
30553
|
} catch {
|
|
30408
|
-
return {};
|
|
30554
|
+
return { ok: false, code: "MIGRATE_FROM_INVALID" };
|
|
30409
30555
|
}
|
|
30410
30556
|
let parsed;
|
|
30411
30557
|
try {
|
|
30412
30558
|
parsed = JSON.parse(raw);
|
|
30413
30559
|
} catch {
|
|
30414
|
-
return {};
|
|
30560
|
+
return { ok: false, code: "MIGRATE_FROM_INVALID" };
|
|
30415
30561
|
}
|
|
30416
|
-
const
|
|
30417
|
-
|
|
30418
|
-
|
|
30419
|
-
}
|
|
30420
|
-
async function detectLegacyMigration(installRoot, loggedInUserId) {
|
|
30421
|
-
void loggedInUserId;
|
|
30422
|
-
const machinesDir = join(installRoot, "machines");
|
|
30423
|
-
let entries;
|
|
30424
|
-
try {
|
|
30425
|
-
entries = await readdir2(machinesDir);
|
|
30426
|
-
} catch {
|
|
30427
|
-
return { kind: "no-match" };
|
|
30562
|
+
const fp = parsed.apiKeyFingerprint;
|
|
30563
|
+
if (typeof fp !== "string" || !FINGERPRINT_HEX_RE.test(fp)) {
|
|
30564
|
+
return { ok: false, code: "MIGRATE_FROM_INVALID" };
|
|
30428
30565
|
}
|
|
30429
|
-
const
|
|
30430
|
-
|
|
30431
|
-
|
|
30432
|
-
const evidence = await readOwnerEvidence(installRoot, name);
|
|
30433
|
-
candidates.push({
|
|
30434
|
-
machineId: name,
|
|
30435
|
-
machineName: evidence.machineName,
|
|
30436
|
-
serverUrl: evidence.serverUrl
|
|
30437
|
-
});
|
|
30566
|
+
const match = roster.find((r) => r.apiKeyFingerprint === fp);
|
|
30567
|
+
if (!match) {
|
|
30568
|
+
return { ok: false, code: "MIGRATE_FROM_NOT_OWNED" };
|
|
30438
30569
|
}
|
|
30439
|
-
|
|
30440
|
-
|
|
30441
|
-
|
|
30442
|
-
|
|
30443
|
-
|
|
30444
|
-
|
|
30445
|
-
machineName:
|
|
30446
|
-
|
|
30447
|
-
|
|
30570
|
+
return {
|
|
30571
|
+
ok: true,
|
|
30572
|
+
candidate: {
|
|
30573
|
+
apiKeyFingerprint: match.apiKeyFingerprint,
|
|
30574
|
+
daemonId: match.daemonId,
|
|
30575
|
+
localPath: candidateOwnerPath,
|
|
30576
|
+
machineName: match.machineName,
|
|
30577
|
+
...match.hostname ? { hostname: match.hostname } : {},
|
|
30578
|
+
...match.lastSeenAt ? { lastSeenAt: match.lastSeenAt } : {}
|
|
30579
|
+
}
|
|
30580
|
+
};
|
|
30581
|
+
}
|
|
30582
|
+
async function firstReadableOwner(paths) {
|
|
30583
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30584
|
+
for (const p of paths) {
|
|
30585
|
+
if (seen.has(p)) continue;
|
|
30586
|
+
seen.add(p);
|
|
30587
|
+
try {
|
|
30588
|
+
const st = await stat(p);
|
|
30589
|
+
if (st.isFile()) return p;
|
|
30590
|
+
} catch {
|
|
30591
|
+
}
|
|
30448
30592
|
}
|
|
30449
|
-
return
|
|
30593
|
+
return null;
|
|
30450
30594
|
}
|
|
30451
30595
|
|
|
30452
30596
|
// src/services/adoptLegacy.ts
|
|
30453
30597
|
init_esm_shims();
|
|
30454
|
-
import { chmod as chmod3, mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4, appendFile, stat } from "fs/promises";
|
|
30598
|
+
import { chmod as chmod3, mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4, appendFile, stat as stat2 } from "fs/promises";
|
|
30455
30599
|
import { createHash as createHash2 } from "crypto";
|
|
30456
30600
|
import { dirname as dirname4, join as join2 } from "path";
|
|
30457
30601
|
import { setTimeout as delay } from "timers/promises";
|
|
@@ -30794,7 +30938,7 @@ async function appendAdoptionLog(slockHome, line) {
|
|
|
30794
30938
|
const path3 = adoptionLogPath(slockHome);
|
|
30795
30939
|
await appendFile(path3, fields.join(" ") + "\n", { mode: 384 });
|
|
30796
30940
|
try {
|
|
30797
|
-
const st = await
|
|
30941
|
+
const st = await stat2(path3);
|
|
30798
30942
|
if ((st.mode & 63) !== 0) await chmod3(path3, 384);
|
|
30799
30943
|
} catch {
|
|
30800
30944
|
}
|
|
@@ -30811,7 +30955,7 @@ import { fileURLToPath as fileURLToPath2 } from "url";
|
|
|
30811
30955
|
|
|
30812
30956
|
// src/cleanup.ts
|
|
30813
30957
|
init_esm_shims();
|
|
30814
|
-
import { readdir as readdir3, stat as
|
|
30958
|
+
import { readdir as readdir3, stat as stat3, unlink as unlink3, rm, rmdir, rename, mkdir as mkdir6 } from "fs/promises";
|
|
30815
30959
|
import { spawn } from "child_process";
|
|
30816
30960
|
import { join as join3 } from "path";
|
|
30817
30961
|
|
|
@@ -30877,7 +31021,7 @@ async function cleanupAllStalePidfiles(slockHome) {
|
|
|
30877
31021
|
}
|
|
30878
31022
|
const attached = await listAttachedServerIds(slockHome);
|
|
30879
31023
|
for (const sid of attached) {
|
|
30880
|
-
const p =
|
|
31024
|
+
const p = serverRunnerPidPath(slockHome, sid);
|
|
30881
31025
|
if (await cleanupStalePidfile(p)) cleaned.push(p);
|
|
30882
31026
|
}
|
|
30883
31027
|
return cleaned;
|
|
@@ -30905,7 +31049,7 @@ async function readPsTable(psSpawn = defaultPsSpawn) {
|
|
|
30905
31049
|
}
|
|
30906
31050
|
}
|
|
30907
31051
|
function defaultPsSpawn() {
|
|
30908
|
-
return new Promise((
|
|
31052
|
+
return new Promise((resolve2) => {
|
|
30909
31053
|
const child = spawn("ps", ["-o", "pid,ppid,comm", "-A"], {
|
|
30910
31054
|
stdio: ["ignore", "pipe", "ignore"]
|
|
30911
31055
|
});
|
|
@@ -30913,8 +31057,8 @@ function defaultPsSpawn() {
|
|
|
30913
31057
|
child.stdout.on("data", (chunk) => {
|
|
30914
31058
|
out += String(chunk);
|
|
30915
31059
|
});
|
|
30916
|
-
child.on("error", () =>
|
|
30917
|
-
child.on("close", (code) =>
|
|
31060
|
+
child.on("error", () => resolve2({ stdout: "", exitCode: 1 }));
|
|
31061
|
+
child.on("close", (code) => resolve2({ stdout: out, exitCode: code ?? 1 }));
|
|
30918
31062
|
});
|
|
30919
31063
|
}
|
|
30920
31064
|
async function cleanupOrphanProcesses(slockHome, psSpawn) {
|
|
@@ -30925,7 +31069,7 @@ async function cleanupOrphanProcesses(slockHome, psSpawn) {
|
|
|
30925
31069
|
const supPid = await readPidfileAt(servicePidPath(slockHome));
|
|
30926
31070
|
if (supPid !== null) knownPids.add(supPid);
|
|
30927
31071
|
for (const sid of managed) {
|
|
30928
|
-
const pid = await readPidfileAt(
|
|
31072
|
+
const pid = await readPidfileAt(serverRunnerPidPath(slockHome, sid));
|
|
30929
31073
|
if (pid !== null) knownPids.add(pid);
|
|
30930
31074
|
}
|
|
30931
31075
|
if (supPid === null) return signaled;
|
|
@@ -30993,7 +31137,7 @@ async function cleanupTmpFiles(slockHome) {
|
|
|
30993
31137
|
for (const v of versions) {
|
|
30994
31138
|
const vdir = join3(stagingDir, v);
|
|
30995
31139
|
try {
|
|
30996
|
-
const s = await
|
|
31140
|
+
const s = await stat3(vdir);
|
|
30997
31141
|
if (Date.now() - s.mtimeMs > TMP_MAX_AGE_MS) {
|
|
30998
31142
|
await rm(vdir, { recursive: true, force: true });
|
|
30999
31143
|
removed.push(vdir);
|
|
@@ -31010,7 +31154,7 @@ async function cleanupTmpFiles(slockHome) {
|
|
|
31010
31154
|
}
|
|
31011
31155
|
const snap = join3(cdir, "upgrade-snapshot.json");
|
|
31012
31156
|
try {
|
|
31013
|
-
const s = await
|
|
31157
|
+
const s = await stat3(snap);
|
|
31014
31158
|
if (Date.now() - s.mtimeMs > TMP_MAX_AGE_MS) {
|
|
31015
31159
|
await unlink3(snap);
|
|
31016
31160
|
removed.push(snap);
|
|
@@ -31022,7 +31166,7 @@ async function cleanupTmpFiles(slockHome) {
|
|
|
31022
31166
|
async function cleanupStaleLock(slockHome) {
|
|
31023
31167
|
const lockDir = join3(computerDir(slockHome), ".lock");
|
|
31024
31168
|
try {
|
|
31025
|
-
const s = await
|
|
31169
|
+
const s = await stat3(lockDir);
|
|
31026
31170
|
if (Date.now() - s.mtimeMs > 60 * 1e3) {
|
|
31027
31171
|
await rm(lockDir, { recursive: true, force: true });
|
|
31028
31172
|
return [lockDir];
|
|
@@ -31034,7 +31178,7 @@ async function cleanupStaleLock(slockHome) {
|
|
|
31034
31178
|
async function forceReleaseLock(slockHome) {
|
|
31035
31179
|
const lockDir = join3(computerDir(slockHome), ".lock");
|
|
31036
31180
|
try {
|
|
31037
|
-
await
|
|
31181
|
+
await stat3(lockDir);
|
|
31038
31182
|
await rm(lockDir, { recursive: true, force: true });
|
|
31039
31183
|
return [lockDir];
|
|
31040
31184
|
} catch {
|
|
@@ -31168,6 +31312,50 @@ async function emitRunnerStateTransition(slockHome, serverId, fromState, toState
|
|
|
31168
31312
|
|
|
31169
31313
|
// src/services/start.ts
|
|
31170
31314
|
init_esm_shims();
|
|
31315
|
+
|
|
31316
|
+
// src/internal/service-pid-fallback.ts
|
|
31317
|
+
init_esm_shims();
|
|
31318
|
+
async function findLiveServicePid(slockHome, deps = {}) {
|
|
31319
|
+
const readPidfile = deps.readPidfile ?? readPidfileAt;
|
|
31320
|
+
const isAlive = deps.isProcessAlive ?? isProcessAlive2;
|
|
31321
|
+
const clearStale = deps.clearPidfile ?? clearPidfileAt;
|
|
31322
|
+
return walkFallback(slockHome, readPidfile, isAlive, clearStale);
|
|
31323
|
+
}
|
|
31324
|
+
async function findLiveServicePidReadOnly(slockHome, deps = {}) {
|
|
31325
|
+
const readPidfile = deps.readPidfile ?? readPidfileAt;
|
|
31326
|
+
const isAlive = deps.isProcessAlive ?? isProcessAlive2;
|
|
31327
|
+
return walkFallback(slockHome, readPidfile, isAlive, async () => void 0);
|
|
31328
|
+
}
|
|
31329
|
+
async function walkFallback(slockHome, readPidfile, isAlive, clearStale) {
|
|
31330
|
+
const candidates = servicePidReadFallback(slockHome);
|
|
31331
|
+
let firstStalePidfile = null;
|
|
31332
|
+
let firstStalePid = null;
|
|
31333
|
+
for (const candidate of candidates) {
|
|
31334
|
+
const candidatePid = await readPidfile(candidate);
|
|
31335
|
+
if (candidatePid === null) continue;
|
|
31336
|
+
if (isAlive(candidatePid)) {
|
|
31337
|
+
return {
|
|
31338
|
+
pid: candidatePid,
|
|
31339
|
+
pidfilePath: candidate,
|
|
31340
|
+
firstStalePidfile,
|
|
31341
|
+
firstStalePid
|
|
31342
|
+
};
|
|
31343
|
+
}
|
|
31344
|
+
await clearStale(candidate);
|
|
31345
|
+
if (firstStalePidfile === null) {
|
|
31346
|
+
firstStalePidfile = candidate;
|
|
31347
|
+
firstStalePid = candidatePid;
|
|
31348
|
+
}
|
|
31349
|
+
}
|
|
31350
|
+
return {
|
|
31351
|
+
pid: null,
|
|
31352
|
+
pidfilePath: candidates[0],
|
|
31353
|
+
firstStalePidfile,
|
|
31354
|
+
firstStalePid
|
|
31355
|
+
};
|
|
31356
|
+
}
|
|
31357
|
+
|
|
31358
|
+
// src/services/start.ts
|
|
31171
31359
|
var START_ENSURE_TIMEOUT_MS = 15e3;
|
|
31172
31360
|
var START_ENSURE_POLL_INTERVAL_MS = 100;
|
|
31173
31361
|
function emit4(opts, event) {
|
|
@@ -31181,7 +31369,7 @@ function emit4(opts, event) {
|
|
|
31181
31369
|
async function waitForManagedDaemonPids(slockHome, serverIds, opts) {
|
|
31182
31370
|
const readPidfile = opts.readPidfile ?? readPidfileAt;
|
|
31183
31371
|
const isAlive = opts.isProcessAlive ?? isProcessAlive2;
|
|
31184
|
-
const sleep2 = opts.sleep ?? ((ms) => new Promise((
|
|
31372
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
|
|
31185
31373
|
const timeoutMs = opts.ensureTimeoutMs ?? START_ENSURE_TIMEOUT_MS;
|
|
31186
31374
|
const pollIntervalMs = opts.ensurePollIntervalMs ?? START_ENSURE_POLL_INTERVAL_MS;
|
|
31187
31375
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -31189,7 +31377,7 @@ async function waitForManagedDaemonPids(slockHome, serverIds, opts) {
|
|
|
31189
31377
|
while (ready.size < serverIds.length) {
|
|
31190
31378
|
for (const serverId of serverIds) {
|
|
31191
31379
|
if (ready.has(serverId)) continue;
|
|
31192
|
-
const pid = await readPidfile(
|
|
31380
|
+
const pid = await readPidfile(serverRunnerPidPath(slockHome, serverId));
|
|
31193
31381
|
if (pid && isAlive(pid)) ready.set(serverId, pid);
|
|
31194
31382
|
}
|
|
31195
31383
|
if (ready.size === serverIds.length) return ready;
|
|
@@ -31201,8 +31389,8 @@ async function waitForManagedDaemonPids(slockHome, serverIds, opts) {
|
|
|
31201
31389
|
}
|
|
31202
31390
|
function buildTimeoutMessage(slockHome, serverIds, ready, input) {
|
|
31203
31391
|
const missing = serverIds.filter((id) => !ready.has(id));
|
|
31204
|
-
const target = input.serverId && missing.length === 1 ? `${input.serverLabel ?? input.serverId}` : `${missing.length}
|
|
31205
|
-
return `Timed out waiting for ${target} to start. Run \`slock-computer status\` and inspect ${serviceLogPath(slockHome)} plus per-server
|
|
31392
|
+
const target = input.serverId && missing.length === 1 ? `${input.serverLabel ?? input.serverId}` : `${missing.length} server runner(s): ${missing.join(", ")}`;
|
|
31393
|
+
return `Timed out waiting for ${target} to start. Run \`slock-computer status\` and inspect ${serviceLogPath(slockHome)} plus per-server server-runner logs under ~/.slock/computer/servers/<serverId>/server-runner.log.`;
|
|
31206
31394
|
}
|
|
31207
31395
|
async function start(input, options = {}) {
|
|
31208
31396
|
options.signal?.throwIfAborted?.();
|
|
@@ -31230,8 +31418,11 @@ async function start(input, options = {}) {
|
|
|
31230
31418
|
for (const id of managedTargets) {
|
|
31231
31419
|
await setServerManaged(slockHome, id);
|
|
31232
31420
|
}
|
|
31233
|
-
const existing = await
|
|
31234
|
-
|
|
31421
|
+
const { pid: existing } = await findLiveServicePid(slockHome, {
|
|
31422
|
+
readPidfile: options.readPidfile,
|
|
31423
|
+
isProcessAlive: options.isProcessAlive
|
|
31424
|
+
});
|
|
31425
|
+
if (existing !== null) {
|
|
31235
31426
|
emit4(options, {
|
|
31236
31427
|
type: "already_running",
|
|
31237
31428
|
servicePid: existing,
|
|
@@ -31327,7 +31518,7 @@ async function pollReadyOnce(slockHome, serverIds, opts) {
|
|
|
31327
31518
|
const isAlive = opts.isProcessAlive ?? isProcessAlive2;
|
|
31328
31519
|
const ready = /* @__PURE__ */ new Map();
|
|
31329
31520
|
for (const serverId of serverIds) {
|
|
31330
|
-
const pid = await readPidfile(
|
|
31521
|
+
const pid = await readPidfile(serverRunnerPidPath(slockHome, serverId));
|
|
31331
31522
|
if (pid && isAlive(pid)) ready.set(serverId, pid);
|
|
31332
31523
|
}
|
|
31333
31524
|
return ready;
|
|
@@ -31354,29 +31545,26 @@ async function stop(input = {}, options = {}) {
|
|
|
31354
31545
|
const killer = options.killService ?? ((pid2) => {
|
|
31355
31546
|
process.kill(pid2, "SIGTERM");
|
|
31356
31547
|
});
|
|
31357
|
-
const sleep2 = options.sleep ?? ((ms) => new Promise((
|
|
31548
|
+
const sleep2 = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
|
|
31358
31549
|
const pollIntervalMs = options.pollIntervalMs ?? STOP_POLL_INTERVAL_MS;
|
|
31359
31550
|
const timeoutMs = options.timeoutMs ?? STOP_TIMEOUT_MS;
|
|
31360
|
-
|
|
31361
|
-
|
|
31362
|
-
|
|
31363
|
-
|
|
31364
|
-
const legacyPid = await readPidfile(legacyPidfilePath);
|
|
31365
|
-
if (legacyPid !== null) {
|
|
31366
|
-
pidfilePath = legacyPidfilePath;
|
|
31367
|
-
pid = legacyPid;
|
|
31368
|
-
}
|
|
31369
|
-
}
|
|
31551
|
+
const { pid, pidfilePath, firstStalePidfile, firstStalePid } = await findLiveServicePid(slockHome, {
|
|
31552
|
+
readPidfile,
|
|
31553
|
+
isProcessAlive: isAlive
|
|
31554
|
+
});
|
|
31370
31555
|
emit5(options, { type: "stopping", pid });
|
|
31371
31556
|
if (pid === null) {
|
|
31557
|
+
if (firstStalePidfile !== null && firstStalePid !== null) {
|
|
31558
|
+
emit5(options, { type: "stale_pidfile_cleared", pid: firstStalePid });
|
|
31559
|
+
return {
|
|
31560
|
+
status: "stale_pidfile_cleared",
|
|
31561
|
+
pid: firstStalePid,
|
|
31562
|
+
pidfilePath: firstStalePidfile
|
|
31563
|
+
};
|
|
31564
|
+
}
|
|
31372
31565
|
emit5(options, { type: "not_running" });
|
|
31373
31566
|
return { status: "not_running", pid: null, pidfilePath };
|
|
31374
31567
|
}
|
|
31375
|
-
if (!isAlive(pid)) {
|
|
31376
|
-
await clearPidfileAt(pidfilePath);
|
|
31377
|
-
emit5(options, { type: "stale_pidfile_cleared", pid });
|
|
31378
|
-
return { status: "stale_pidfile_cleared", pid, pidfilePath };
|
|
31379
|
-
}
|
|
31380
31568
|
options.signal?.throwIfAborted?.();
|
|
31381
31569
|
try {
|
|
31382
31570
|
killer(pid);
|
|
@@ -31504,8 +31692,8 @@ async function detach(input, options = {}) {
|
|
|
31504
31692
|
await clearServerManaged(slockHome, serverId);
|
|
31505
31693
|
const subtree = [
|
|
31506
31694
|
serverAttachmentPath(slockHome, serverId),
|
|
31507
|
-
|
|
31508
|
-
|
|
31695
|
+
serverRunnerPidPath(slockHome, serverId),
|
|
31696
|
+
serverRunnerLogPath(slockHome, serverId)
|
|
31509
31697
|
];
|
|
31510
31698
|
for (const p of subtree) await clearPidfileAt(p);
|
|
31511
31699
|
emit6(options, { type: "subtree_cleared", serverId, serverLabel });
|
|
@@ -31526,7 +31714,7 @@ function buildResidentSpawn(mode, serverId, selfEntry = process.argv[1] ?? "", e
|
|
|
31526
31714
|
}
|
|
31527
31715
|
var PARENT_LOCK_HELD_ENV_VAR = "SLOCK_COMPUTER_PARENT_MUTATION_LOCK_HELD";
|
|
31528
31716
|
async function spawnDetachedService(slockHome) {
|
|
31529
|
-
await mkdir8(
|
|
31717
|
+
await mkdir8(serviceRunDir(slockHome), { recursive: true });
|
|
31530
31718
|
const supLogFd = await open(serviceLogPath(slockHome), "a");
|
|
31531
31719
|
const { command, args } = buildResidentSpawn("__service", null);
|
|
31532
31720
|
const child = spawn2(command, args, {
|
|
@@ -31703,14 +31891,14 @@ async function readServiceVersionEvidence(slockHome) {
|
|
|
31703
31891
|
}
|
|
31704
31892
|
async function runService() {
|
|
31705
31893
|
const slockHome = resolveSlockHome();
|
|
31706
|
-
await mkdir8(
|
|
31894
|
+
await mkdir8(serviceRunDir(slockHome), { recursive: true });
|
|
31707
31895
|
await runServiceStartupRecovery(slockHome);
|
|
31708
31896
|
await writePidfileAt(servicePidPath(slockHome), process.pid);
|
|
31709
31897
|
await writeServiceVersionEvidence(slockHome);
|
|
31710
31898
|
const children = /* @__PURE__ */ new Map();
|
|
31711
31899
|
const { [PARENT_LOCK_HELD_ENV_VAR]: _parentLockMarker, ...childEnv } = process.env;
|
|
31712
31900
|
const spawnChild = async (serverId) => {
|
|
31713
|
-
const logPath =
|
|
31901
|
+
const logPath = serverRunnerLogPath(slockHome, serverId);
|
|
31714
31902
|
await mkdir8(dirname8(logPath), { recursive: true });
|
|
31715
31903
|
const logFd = await open(logPath, "a");
|
|
31716
31904
|
const { command, args } = buildResidentSpawn("__run", serverId);
|
|
@@ -31723,11 +31911,11 @@ async function runService() {
|
|
|
31723
31911
|
if (!child.pid) return;
|
|
31724
31912
|
const handle = { serverId, child, stopping: false };
|
|
31725
31913
|
children.set(serverId, handle);
|
|
31726
|
-
await writePidfileAt(
|
|
31914
|
+
await writePidfileAt(serverRunnerPidPath(slockHome, serverId), child.pid);
|
|
31727
31915
|
child.on("exit", (code, signal) => {
|
|
31728
31916
|
void (async () => {
|
|
31729
31917
|
children.delete(serverId);
|
|
31730
|
-
await clearPidfileAt(
|
|
31918
|
+
await clearPidfileAt(serverRunnerPidPath(slockHome, serverId));
|
|
31731
31919
|
if (handle.stopping) return;
|
|
31732
31920
|
const classification = classifyRunnerExit(code, signal);
|
|
31733
31921
|
if (classification === "config-error") {
|
|
@@ -31736,7 +31924,7 @@ async function runService() {
|
|
|
31736
31924
|
} catch {
|
|
31737
31925
|
}
|
|
31738
31926
|
process.stderr.write(
|
|
31739
|
-
`Service: server ${serverId} child exited with EX_CONFIG (${EX_CONFIG_EXIT_CODE}); marked degraded, NOT auto-restarting. See ${
|
|
31927
|
+
`Service: server ${serverId} child exited with EX_CONFIG (${EX_CONFIG_EXIT_CODE}); marked degraded, NOT auto-restarting. See ${serverRunnerLogPath(slockHome, serverId)} for the actionable error.
|
|
31740
31928
|
`
|
|
31741
31929
|
);
|
|
31742
31930
|
return;
|
|
@@ -31847,7 +32035,7 @@ async function runStart(opts = {}, deps = {}) {
|
|
|
31847
32035
|
info(
|
|
31848
32036
|
`Managing ${sb.managedCount} of ${sb.attachedCount} attached server(s). Logs: ${sb.logPath}`
|
|
31849
32037
|
);
|
|
31850
|
-
info(`Per-server
|
|
32038
|
+
info(`Per-server server-runner logs: ~/.slock/computer/servers/<serverId>/server-runner.log`);
|
|
31851
32039
|
info(`Check state with \`slock-computer status\`.`);
|
|
31852
32040
|
}
|
|
31853
32041
|
}
|
|
@@ -31910,12 +32098,15 @@ async function runDetach(serverId, serverLabel = serverId) {
|
|
|
31910
32098
|
|
|
31911
32099
|
// src/setup.ts
|
|
31912
32100
|
var USER_SESSION_EXPIRY_LEEWAY_MS = 3e4;
|
|
31913
|
-
async function
|
|
32101
|
+
async function readUserSessionAuth(slockHome) {
|
|
31914
32102
|
try {
|
|
31915
32103
|
const parsed = JSON.parse(await readFile8(userSessionPath(slockHome), "utf8"));
|
|
31916
|
-
return
|
|
32104
|
+
return {
|
|
32105
|
+
accessToken: typeof parsed.accessToken === "string" ? parsed.accessToken : "",
|
|
32106
|
+
...typeof parsed.serverUrl === "string" ? { serverUrl: parsed.serverUrl } : {}
|
|
32107
|
+
};
|
|
31917
32108
|
} catch {
|
|
31918
|
-
return "";
|
|
32109
|
+
return { accessToken: "" };
|
|
31919
32110
|
}
|
|
31920
32111
|
}
|
|
31921
32112
|
async function hasValidUserSession(slockHome) {
|
|
@@ -31985,15 +32176,60 @@ async function refreshUserSession(slockHome, serverUrl) {
|
|
|
31985
32176
|
return false;
|
|
31986
32177
|
}
|
|
31987
32178
|
}
|
|
31988
|
-
async function
|
|
31989
|
-
|
|
31990
|
-
|
|
31991
|
-
|
|
31992
|
-
|
|
32179
|
+
async function pickMigrationCandidateFromInput(candidates, read, write) {
|
|
32180
|
+
write(
|
|
32181
|
+
"Migration: detected legacy daemon(s) on this Computer that match the target server.\n"
|
|
32182
|
+
);
|
|
32183
|
+
candidates.forEach((c, i) => {
|
|
32184
|
+
const host = c.hostname ? ` (${c.hostname})` : "";
|
|
32185
|
+
const seen = c.lastSeenAt ? ` last seen ${c.lastSeenAt}` : "";
|
|
32186
|
+
write(` ${i + 1}. ${c.machineName}${host}${seen}
|
|
32187
|
+
`);
|
|
32188
|
+
write(` local: ${c.localPath}
|
|
32189
|
+
`);
|
|
32190
|
+
});
|
|
32191
|
+
write(" 0. Fresh attach (skip migration)\n");
|
|
32192
|
+
write(" m. Migrate from a different on-disk path\n");
|
|
32193
|
+
while (true) {
|
|
32194
|
+
write("Choose [1]: ");
|
|
32195
|
+
const { line, eof } = await read();
|
|
32196
|
+
if (eof) return { kind: "fresh" };
|
|
32197
|
+
const trimmed = line.trim();
|
|
32198
|
+
const norm = trimmed.toLowerCase();
|
|
32199
|
+
if (norm === "m") {
|
|
32200
|
+
write("Path to legacy machine dir or owner.json: ");
|
|
32201
|
+
const { line: pathLine } = await read();
|
|
32202
|
+
return { kind: "manual", path: pathLine.trim() };
|
|
32203
|
+
}
|
|
32204
|
+
if (norm.length === 0) return { kind: "candidate", index: 0 };
|
|
32205
|
+
if (norm === "0") return { kind: "fresh" };
|
|
32206
|
+
const n = Number.parseInt(norm, 10);
|
|
32207
|
+
if (Number.isFinite(n) && String(n) === norm && n >= 1 && n <= candidates.length) {
|
|
32208
|
+
return { kind: "candidate", index: n - 1 };
|
|
32209
|
+
}
|
|
32210
|
+
write(
|
|
32211
|
+
`Invalid selection "${trimmed}". Enter 1..${candidates.length}, 0, or m.
|
|
32212
|
+
`
|
|
32213
|
+
);
|
|
32214
|
+
}
|
|
32215
|
+
}
|
|
32216
|
+
async function defaultPickMigrationCandidate(candidates) {
|
|
32217
|
+
return pickMigrationCandidateFromInput(
|
|
32218
|
+
candidates,
|
|
32219
|
+
() => readLine(false),
|
|
32220
|
+
(s) => {
|
|
32221
|
+
process.stdout.write(s);
|
|
32222
|
+
}
|
|
32223
|
+
);
|
|
31993
32224
|
}
|
|
31994
|
-
async function
|
|
31995
|
-
process.
|
|
31996
|
-
|
|
32225
|
+
async function readLegacyApiKey(isTty) {
|
|
32226
|
+
const fromEnv = process.env.SLOCK_LEGACY_API_KEY;
|
|
32227
|
+
if (typeof fromEnv === "string" && fromEnv.length > 0) return fromEnv.trim();
|
|
32228
|
+
if (!isTty) return "";
|
|
32229
|
+
process.stdout.write(
|
|
32230
|
+
"Paste legacy api key (sk_machine_* or sk_daemon_*); input is hidden: "
|
|
32231
|
+
);
|
|
32232
|
+
const { line } = await readLine(true);
|
|
31997
32233
|
process.stdout.write("\n");
|
|
31998
32234
|
return line.trim();
|
|
31999
32235
|
}
|
|
@@ -32003,7 +32239,7 @@ async function readLine(masked) {
|
|
|
32003
32239
|
const enterRaw = masked && stdin.isTTY === true && typeof stdin.setRawMode === "function";
|
|
32004
32240
|
if (enterRaw) stdin.setRawMode(true);
|
|
32005
32241
|
stdin.resume();
|
|
32006
|
-
return await new Promise((
|
|
32242
|
+
return await new Promise((resolve2) => {
|
|
32007
32243
|
let buf = "";
|
|
32008
32244
|
const cleanup = () => {
|
|
32009
32245
|
stdin.off("data", onData);
|
|
@@ -32016,12 +32252,17 @@ async function readLine(masked) {
|
|
|
32016
32252
|
for (const ch of text) {
|
|
32017
32253
|
if (ch === "\n" || ch === "\r") {
|
|
32018
32254
|
cleanup();
|
|
32019
|
-
|
|
32255
|
+
resolve2({ line: buf, eof: false });
|
|
32256
|
+
return;
|
|
32257
|
+
}
|
|
32258
|
+
if (ch === "") {
|
|
32259
|
+
cleanup();
|
|
32260
|
+
resolve2({ line: buf, eof: true });
|
|
32020
32261
|
return;
|
|
32021
32262
|
}
|
|
32022
32263
|
if (ch === "") {
|
|
32023
32264
|
cleanup();
|
|
32024
|
-
|
|
32265
|
+
resolve2({ line: "", eof: false });
|
|
32025
32266
|
return;
|
|
32026
32267
|
}
|
|
32027
32268
|
if (ch === "\x7F" || ch === "\b") {
|
|
@@ -32033,12 +32274,88 @@ async function readLine(masked) {
|
|
|
32033
32274
|
};
|
|
32034
32275
|
const onEnd = () => {
|
|
32035
32276
|
cleanup();
|
|
32036
|
-
|
|
32277
|
+
resolve2({ line: buf, eof: true });
|
|
32037
32278
|
};
|
|
32038
32279
|
stdin.on("data", onData);
|
|
32039
32280
|
stdin.on("end", onEnd);
|
|
32040
32281
|
});
|
|
32041
32282
|
}
|
|
32283
|
+
async function runMigrateAdoption(opts, candidate, isTty, adoptLegacyImpl, readLegacyApiKeyImpl) {
|
|
32284
|
+
const where = candidate.hostname ? ` (${candidate.hostname})` : "";
|
|
32285
|
+
const seen = candidate.lastSeenAt ? ` last seen ${candidate.lastSeenAt}` : "";
|
|
32286
|
+
info(`Migration: adopting legacy daemon "${candidate.machineName}"${where}${seen}.`);
|
|
32287
|
+
info(` local owner.json: ${candidate.localPath}`);
|
|
32288
|
+
const rawKey = await readLegacyApiKeyImpl(isTty);
|
|
32289
|
+
if (rawKey.length === 0) {
|
|
32290
|
+
fail(
|
|
32291
|
+
"LEGACY_KEY_REQUIRED",
|
|
32292
|
+
"No legacy api key provided. Set `SLOCK_LEGACY_API_KEY` or paste the legacy `sk_machine_*` / `sk_daemon_*` key when prompted."
|
|
32293
|
+
);
|
|
32294
|
+
}
|
|
32295
|
+
if (!rawKey.startsWith("sk_machine_") && !rawKey.startsWith("sk_daemon_")) {
|
|
32296
|
+
fail(
|
|
32297
|
+
"LEGACY_KEY_INVALID",
|
|
32298
|
+
"Provided key does not look like a legacy machine key (expected `sk_machine_*` or `sk_daemon_*`)."
|
|
32299
|
+
);
|
|
32300
|
+
}
|
|
32301
|
+
try {
|
|
32302
|
+
await adoptLegacyImpl(
|
|
32303
|
+
{
|
|
32304
|
+
serverSlug: opts.serverSlug,
|
|
32305
|
+
...opts.serverUrl ? { serverUrl: opts.serverUrl } : {},
|
|
32306
|
+
...opts.name ? { name: opts.name } : {},
|
|
32307
|
+
rawKey,
|
|
32308
|
+
mode: "legacy_key_stdin",
|
|
32309
|
+
redactedPrefix: rawKey.slice(0, 8)
|
|
32310
|
+
},
|
|
32311
|
+
{
|
|
32312
|
+
onEvent: (event) => {
|
|
32313
|
+
if (event.type === "adopting") {
|
|
32314
|
+
info(
|
|
32315
|
+
`Adopting legacy daemon for ${formatServerSlugDisplay(event.serverSlug)} via ${event.mode}\u2026`
|
|
32316
|
+
);
|
|
32317
|
+
} else if (event.type === "preflight") {
|
|
32318
|
+
info(
|
|
32319
|
+
event.resumed ? "Adopted (resumed prior attachment); running preflight\u2026" : "Adopted; running preflight\u2026"
|
|
32320
|
+
);
|
|
32321
|
+
} else if (event.type === "adopted") {
|
|
32322
|
+
info(`Adopted. Computer state written to ${event.attachmentPath}`);
|
|
32323
|
+
info(` server: ${formatServerSlugDisplay(event.serverSlug)}`);
|
|
32324
|
+
info(` serverMachine: ${event.serverMachineId}`);
|
|
32325
|
+
info(` legacyMachine: ${event.legacyMachineId}`);
|
|
32326
|
+
switch (event.legacyStop.outcome) {
|
|
32327
|
+
case "absent":
|
|
32328
|
+
info(" legacy daemon: not detected on this Computer (no local lock file)");
|
|
32329
|
+
break;
|
|
32330
|
+
case "already_dead":
|
|
32331
|
+
info(` legacy daemon: already stopped (pid ${event.legacyStop.pid} not running)`);
|
|
32332
|
+
break;
|
|
32333
|
+
case "stopped":
|
|
32334
|
+
info(` legacy daemon: stopped (pid ${event.legacyStop.pid}, SIGTERM)`);
|
|
32335
|
+
break;
|
|
32336
|
+
}
|
|
32337
|
+
}
|
|
32338
|
+
}
|
|
32339
|
+
}
|
|
32340
|
+
);
|
|
32341
|
+
} catch (err) {
|
|
32342
|
+
if (err instanceof CliExit) throw err;
|
|
32343
|
+
if (err instanceof ComputerServiceError) {
|
|
32344
|
+
fail(err.code, err.message);
|
|
32345
|
+
}
|
|
32346
|
+
throw err;
|
|
32347
|
+
}
|
|
32348
|
+
}
|
|
32349
|
+
function manualPathErrorMessage(code, inputPath) {
|
|
32350
|
+
switch (code) {
|
|
32351
|
+
case "MIGRATE_FROM_NOT_FOUND":
|
|
32352
|
+
return `--migrate-from path not found: ${inputPath}. Pass the legacy machine directory, its daemon.lock/, or its owner.json file.`;
|
|
32353
|
+
case "MIGRATE_FROM_INVALID":
|
|
32354
|
+
return `--migrate-from path is not a valid legacy daemon install: ${inputPath}. Expected an owner.json with a 16-hex-char apiKeyFingerprint field.`;
|
|
32355
|
+
case "MIGRATE_FROM_NOT_OWNED":
|
|
32356
|
+
return `--migrate-from path's apiKeyFingerprint is not in this server's legacy machine roster for the logged-in user: ${inputPath}. Either the daemon is already migrated, the row is unowned by this user, or the fingerprint is from a different server.`;
|
|
32357
|
+
}
|
|
32358
|
+
}
|
|
32042
32359
|
async function runSetup(opts, deps = {}) {
|
|
32043
32360
|
const slockHome = resolveSlockHome();
|
|
32044
32361
|
const isTty = deps.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
@@ -32047,8 +32364,11 @@ async function runSetup(opts, deps = {}) {
|
|
|
32047
32364
|
const start2 = deps.runStart ?? runStart;
|
|
32048
32365
|
const refreshSession = deps.refreshUserSession ?? refreshUserSession;
|
|
32049
32366
|
const detectMigration = deps.detectLegacyMigration ?? detectLegacyMigration;
|
|
32050
|
-
const
|
|
32051
|
-
const
|
|
32367
|
+
const validateManualPath = deps.validateManualMigratePath ?? validateManualMigratePath;
|
|
32368
|
+
const buildRoster = deps.buildRosterClient ?? ((baseUrl, accessToken) => new LegacyMachinesClient(baseUrl, accessToken));
|
|
32369
|
+
const pickCandidate = deps.pickMigrationCandidate ?? defaultPickMigrationCandidate;
|
|
32370
|
+
const adoptLegacy2 = deps.adoptLegacy ?? adoptLegacy;
|
|
32371
|
+
const readLegacyKey = deps.readLegacyApiKey ?? readLegacyApiKey;
|
|
32052
32372
|
if (!isTty && !opts.yes) {
|
|
32053
32373
|
fail(
|
|
32054
32374
|
"NON_INTERACTIVE_SETUP_REQUIRES_FLAGS",
|
|
@@ -32077,78 +32397,85 @@ async function runSetup(opts, deps = {}) {
|
|
|
32077
32397
|
if (attachment) {
|
|
32078
32398
|
info(`Attachment: already attached to ${label}.`);
|
|
32079
32399
|
} else {
|
|
32400
|
+
const session = await readUserSessionAuth(slockHome);
|
|
32401
|
+
const baseUrl = resolveServerUrl(
|
|
32402
|
+
opts.serverUrl,
|
|
32403
|
+
session.serverUrl,
|
|
32404
|
+
process.env.SLOCK_SERVER_URL
|
|
32405
|
+
);
|
|
32406
|
+
const rosterClient = buildRoster(baseUrl, session.accessToken);
|
|
32080
32407
|
let migrated = false;
|
|
32081
|
-
if (
|
|
32082
|
-
const
|
|
32083
|
-
if (
|
|
32084
|
-
|
|
32085
|
-
|
|
32086
|
-
|
|
32087
|
-
`Migration: detected legacy daemon machine${who}${where}. Migrate it under Computer instead of creating a fresh attachment? [y/N] `
|
|
32408
|
+
if (typeof opts.migrateFrom === "string" && opts.migrateFrom.length > 0) {
|
|
32409
|
+
const rosterResult = await rosterClient.list(opts.serverSlug);
|
|
32410
|
+
if (rosterResult.status !== "success") {
|
|
32411
|
+
fail(
|
|
32412
|
+
"MIGRATE_FROM_ROSTER_UNAVAILABLE",
|
|
32413
|
+
`Cannot validate --migrate-from path: legacy machine roster unavailable (${rosterResult.status}). Retry when the server is reachable, or remove --migrate-from to fall through to fresh attach.`
|
|
32088
32414
|
);
|
|
32089
|
-
|
|
32090
|
-
|
|
32091
|
-
|
|
32092
|
-
|
|
32093
|
-
|
|
32094
|
-
|
|
32095
|
-
|
|
32096
|
-
|
|
32097
|
-
|
|
32098
|
-
|
|
32099
|
-
|
|
32100
|
-
|
|
32101
|
-
|
|
32102
|
-
|
|
32103
|
-
|
|
32104
|
-
|
|
32105
|
-
|
|
32106
|
-
|
|
32107
|
-
|
|
32108
|
-
|
|
32109
|
-
|
|
32110
|
-
|
|
32111
|
-
|
|
32112
|
-
|
|
32113
|
-
|
|
32114
|
-
|
|
32115
|
-
|
|
32116
|
-
);
|
|
32117
|
-
} else if (event.type === "preflight") {
|
|
32118
|
-
info(
|
|
32119
|
-
event.resumed ? "Adopted (resumed prior attachment); running preflight\u2026" : "Adopted; running preflight\u2026"
|
|
32120
|
-
);
|
|
32121
|
-
} else if (event.type === "adopted") {
|
|
32122
|
-
info(`Adopted. Computer state written to ${event.attachmentPath}`);
|
|
32123
|
-
info(` server: ${formatServerSlugDisplay(event.serverSlug)}`);
|
|
32124
|
-
info(` serverMachine: ${event.serverMachineId}`);
|
|
32125
|
-
info(` legacyMachine: ${event.legacyMachineId}`);
|
|
32126
|
-
switch (event.legacyStop.outcome) {
|
|
32127
|
-
case "absent":
|
|
32128
|
-
info(" legacy daemon: not detected on this Computer (no local lock file)");
|
|
32129
|
-
break;
|
|
32130
|
-
case "already_dead":
|
|
32131
|
-
info(` legacy daemon: already stopped (pid ${event.legacyStop.pid} not running)`);
|
|
32132
|
-
break;
|
|
32133
|
-
case "stopped":
|
|
32134
|
-
info(` legacy daemon: stopped (pid ${event.legacyStop.pid}, SIGTERM)`);
|
|
32135
|
-
break;
|
|
32136
|
-
}
|
|
32137
|
-
}
|
|
32138
|
-
}
|
|
32139
|
-
}
|
|
32415
|
+
}
|
|
32416
|
+
const validation = await validateManualPath(opts.migrateFrom, rosterResult.entries);
|
|
32417
|
+
if (!validation.ok) {
|
|
32418
|
+
fail(validation.code, manualPathErrorMessage(validation.code, opts.migrateFrom));
|
|
32419
|
+
}
|
|
32420
|
+
await runMigrateAdoption(opts, validation.candidate, isTty, adoptLegacy2, readLegacyKey);
|
|
32421
|
+
migrated = true;
|
|
32422
|
+
} else {
|
|
32423
|
+
const detection = await detectMigration(slockHome, opts.serverSlug, rosterClient);
|
|
32424
|
+
if (detection.kind === "server-unavailable") {
|
|
32425
|
+
info(
|
|
32426
|
+
"Migration: legacy machine roster unavailable (fresh trigger: server-unavailable); falling back to fresh attach."
|
|
32427
|
+
);
|
|
32428
|
+
} else if (detection.candidates.length === 0) {
|
|
32429
|
+
} else if (!isTty) {
|
|
32430
|
+
info(
|
|
32431
|
+
`Migration: ${detection.candidates.length} legacy daemon(s) match this server but setup is non-interactive (fresh trigger: non-tty); falling back to fresh attach. Re-run on a TTY or pass --migrate-from <path> to adopt a specific install.`
|
|
32432
|
+
);
|
|
32433
|
+
} else {
|
|
32434
|
+
pickerLoop: while (true) {
|
|
32435
|
+
const selection = await pickCandidate(detection.candidates);
|
|
32436
|
+
if (selection.kind === "candidate") {
|
|
32437
|
+
const candidate = detection.candidates[selection.index];
|
|
32438
|
+
if (!candidate) {
|
|
32439
|
+
fail(
|
|
32440
|
+
"MIGRATE_PICKER_OUT_OF_RANGE",
|
|
32441
|
+
`Picker returned candidate index ${selection.index} but only ${detection.candidates.length} candidate(s) were detected.`
|
|
32140
32442
|
);
|
|
32141
|
-
migrated = true;
|
|
32142
|
-
} catch (err) {
|
|
32143
|
-
if (err instanceof CliExit) throw err;
|
|
32144
|
-
if (err instanceof ComputerServiceError) {
|
|
32145
|
-
fail(err.code, err.message);
|
|
32146
|
-
}
|
|
32147
|
-
throw err;
|
|
32148
32443
|
}
|
|
32444
|
+
await runMigrateAdoption(opts, candidate, isTty, adoptLegacy2, readLegacyKey);
|
|
32445
|
+
migrated = true;
|
|
32446
|
+
break pickerLoop;
|
|
32447
|
+
} else if (selection.kind === "manual") {
|
|
32448
|
+
if (selection.path.length === 0) {
|
|
32449
|
+
info("Migration: no path provided; returning to picker.");
|
|
32450
|
+
continue pickerLoop;
|
|
32451
|
+
}
|
|
32452
|
+
const rosterResult = await rosterClient.list(opts.serverSlug);
|
|
32453
|
+
if (rosterResult.status !== "success") {
|
|
32454
|
+
info(
|
|
32455
|
+
`Migration: MIGRATE_FROM_ROSTER_UNAVAILABLE \u2014 legacy machine roster unavailable (${rosterResult.status}); returning to picker. Pick "0" to fall through to fresh attach if the server stays unreachable.`
|
|
32456
|
+
);
|
|
32457
|
+
continue pickerLoop;
|
|
32458
|
+
}
|
|
32459
|
+
const validation = await validateManualPath(selection.path, rosterResult.entries);
|
|
32460
|
+
if (!validation.ok) {
|
|
32461
|
+
info(
|
|
32462
|
+
`Migration: ${validation.code} \u2014 ${manualPathErrorMessage(validation.code, selection.path)} Returning to picker.`
|
|
32463
|
+
);
|
|
32464
|
+
continue pickerLoop;
|
|
32465
|
+
}
|
|
32466
|
+
await runMigrateAdoption(
|
|
32467
|
+
opts,
|
|
32468
|
+
validation.candidate,
|
|
32469
|
+
isTty,
|
|
32470
|
+
adoptLegacy2,
|
|
32471
|
+
readLegacyKey
|
|
32472
|
+
);
|
|
32473
|
+
migrated = true;
|
|
32474
|
+
break pickerLoop;
|
|
32475
|
+
} else {
|
|
32476
|
+
info("Migration: fresh attach selected.");
|
|
32477
|
+
break pickerLoop;
|
|
32149
32478
|
}
|
|
32150
|
-
} else {
|
|
32151
|
-
info("Migration: declined; falling back to fresh attach.");
|
|
32152
32479
|
}
|
|
32153
32480
|
}
|
|
32154
32481
|
}
|
|
@@ -32208,6 +32535,10 @@ async function pidStatus(pidfile) {
|
|
|
32208
32535
|
const pid = await readPidfileAt(pidfile);
|
|
32209
32536
|
return pid !== null && isProcessAlive2(pid) ? { running: true, pid } : { running: false };
|
|
32210
32537
|
}
|
|
32538
|
+
async function serviceState(slockHome) {
|
|
32539
|
+
const { pid } = await findLiveServicePidReadOnly(slockHome);
|
|
32540
|
+
return pid !== null ? { running: true, pid } : { running: false };
|
|
32541
|
+
}
|
|
32211
32542
|
async function deriveHealth(slockHome, serverId, daemon) {
|
|
32212
32543
|
if (!daemon.running) return "offline";
|
|
32213
32544
|
if (await isDegraded(slockHome, serverId)) return "degraded";
|
|
@@ -32218,19 +32549,19 @@ async function buildStatusReport(installRoot) {
|
|
|
32218
32549
|
const session = sessionRead.session;
|
|
32219
32550
|
const attachments = await listServerAttachments(installRoot);
|
|
32220
32551
|
const service = {
|
|
32221
|
-
...await
|
|
32552
|
+
...await serviceState(installRoot),
|
|
32222
32553
|
logPath: serviceLogPath(installRoot)
|
|
32223
32554
|
};
|
|
32224
32555
|
const servers = [];
|
|
32225
32556
|
for (const a of attachments) {
|
|
32226
|
-
const daemon = await pidStatus(
|
|
32557
|
+
const daemon = await pidStatus(serverRunnerPidPath(installRoot, a.serverId));
|
|
32227
32558
|
servers.push({
|
|
32228
32559
|
serverId: a.serverId,
|
|
32229
32560
|
serverSlug: a.serverSlug ?? null,
|
|
32230
32561
|
serverMachineId: a.serverMachineId,
|
|
32231
32562
|
serverUrl: a.serverUrl,
|
|
32232
32563
|
attachedAt: a.attachedAt ?? null,
|
|
32233
|
-
|
|
32564
|
+
serverRunnerLogPath: serverRunnerLogPath(installRoot, a.serverId),
|
|
32234
32565
|
daemon,
|
|
32235
32566
|
health: await deriveHealth(installRoot, a.serverId, daemon)
|
|
32236
32567
|
});
|
|
@@ -32277,7 +32608,7 @@ async function runStatus(opts) {
|
|
|
32277
32608
|
info(
|
|
32278
32609
|
` ${pad(formatServerSlugDisplay(s.serverSlug), 24)}${pad(s.health, 12)}${pad(dcol, 24)}${pad(s.serverMachineId, 38)}${s.serverUrl}`
|
|
32279
32610
|
);
|
|
32280
|
-
info(`
|
|
32611
|
+
info(` Server runner log: ${s.serverRunnerLogPath}`);
|
|
32281
32612
|
}
|
|
32282
32613
|
if (report.servers.some((s) => s.health === "degraded")) {
|
|
32283
32614
|
info("");
|
|
@@ -32618,14 +32949,14 @@ import { readFile as readFile10 } from "fs/promises";
|
|
|
32618
32949
|
var DEFAULT_LINES = 200;
|
|
32619
32950
|
async function runLogs(opts) {
|
|
32620
32951
|
const home = resolveSlockHome();
|
|
32621
|
-
const file = opts.service ? serviceLogPath(home) :
|
|
32952
|
+
const file = opts.service ? serviceLogPath(home) : serverRunnerLogPath(home, await resolveTargetServerId({ server: opts.server }));
|
|
32622
32953
|
let content;
|
|
32623
32954
|
try {
|
|
32624
32955
|
content = await readFile10(file, "utf8");
|
|
32625
32956
|
} catch {
|
|
32626
32957
|
fail(
|
|
32627
32958
|
"NO_DAEMON_LOG",
|
|
32628
|
-
opts.service ? `No service log at ${file}. Start the service first (\`slock-computer start\`).` : `No
|
|
32959
|
+
opts.service ? `No service log at ${file}. Start the service first (\`slock-computer start\`).` : `No server runner log at ${file}. Start its server runner first (\`slock-computer start\`).`
|
|
32629
32960
|
);
|
|
32630
32961
|
}
|
|
32631
32962
|
const n = Number.isInteger(opts.lines) && opts.lines > 0 ? opts.lines : DEFAULT_LINES;
|
|
@@ -33035,7 +33366,7 @@ function errMsg(e) {
|
|
|
33035
33366
|
return e instanceof Error ? e.message : String(e);
|
|
33036
33367
|
}
|
|
33037
33368
|
async function defaultReadTarballPackageJson(tarballPath) {
|
|
33038
|
-
const raw = await new Promise((
|
|
33369
|
+
const raw = await new Promise((resolve2, reject) => {
|
|
33039
33370
|
const child = spawn3("tar", ["-xzOf", tarballPath, "package/package.json"], {
|
|
33040
33371
|
stdio: ["ignore", "pipe", "pipe"]
|
|
33041
33372
|
});
|
|
@@ -33053,7 +33384,7 @@ async function defaultReadTarballPackageJson(tarballPath) {
|
|
|
33053
33384
|
reject(new Error(`tar -xzOf exited ${code}: ${stderrBuf.slice(0, 300)}`));
|
|
33054
33385
|
return;
|
|
33055
33386
|
}
|
|
33056
|
-
|
|
33387
|
+
resolve2(stdoutBuf);
|
|
33057
33388
|
});
|
|
33058
33389
|
});
|
|
33059
33390
|
return JSON.parse(raw);
|
|
@@ -33181,7 +33512,7 @@ async function stagePhase(slockHome, version, deps = {}) {
|
|
|
33181
33512
|
return { stagedPath, version, tarballSha1 };
|
|
33182
33513
|
}
|
|
33183
33514
|
function defaultNpmPack(cwd, packageRef) {
|
|
33184
|
-
return new Promise((
|
|
33515
|
+
return new Promise((resolve2) => {
|
|
33185
33516
|
const child = spawn4("npm", ["pack", packageRef, "--json"], {
|
|
33186
33517
|
cwd,
|
|
33187
33518
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -33195,23 +33526,23 @@ function defaultNpmPack(cwd, packageRef) {
|
|
|
33195
33526
|
stderrBuf += String(chunk);
|
|
33196
33527
|
});
|
|
33197
33528
|
child.on("error", (err) => {
|
|
33198
|
-
|
|
33529
|
+
resolve2({ tarballPath: "", exitCode: 1, stderr: String(err) });
|
|
33199
33530
|
});
|
|
33200
33531
|
child.on("close", (code) => {
|
|
33201
33532
|
if (code !== 0) {
|
|
33202
|
-
|
|
33533
|
+
resolve2({ tarballPath: "", exitCode: code ?? 1, stderr: stderrBuf });
|
|
33203
33534
|
return;
|
|
33204
33535
|
}
|
|
33205
33536
|
try {
|
|
33206
33537
|
const parsed = JSON.parse(stdoutBuf);
|
|
33207
33538
|
const filename = parsed[0]?.filename;
|
|
33208
33539
|
if (!filename) {
|
|
33209
|
-
|
|
33540
|
+
resolve2({ tarballPath: "", exitCode: 1, stderr: "npm pack returned no filename" });
|
|
33210
33541
|
return;
|
|
33211
33542
|
}
|
|
33212
|
-
|
|
33543
|
+
resolve2({ tarballPath: join6(cwd, filename), exitCode: 0, stderr: stderrBuf });
|
|
33213
33544
|
} catch (e) {
|
|
33214
|
-
|
|
33545
|
+
resolve2({ tarballPath: "", exitCode: 1, stderr: `parse npm pack output: ${e}` });
|
|
33215
33546
|
}
|
|
33216
33547
|
});
|
|
33217
33548
|
});
|
|
@@ -33291,7 +33622,7 @@ async function extractTarball(tarballPath, destDir, deps = {}) {
|
|
|
33291
33622
|
return { extractedPackageDir: join6(destDir, "package") };
|
|
33292
33623
|
}
|
|
33293
33624
|
function defaultTarSpawn(tarballPath, destDir) {
|
|
33294
|
-
return new Promise((
|
|
33625
|
+
return new Promise((resolve2) => {
|
|
33295
33626
|
const child = spawn4("tar", ["-xzf", tarballPath, "-C", destDir], {
|
|
33296
33627
|
stdio: ["ignore", "ignore", "pipe"]
|
|
33297
33628
|
});
|
|
@@ -33300,10 +33631,10 @@ function defaultTarSpawn(tarballPath, destDir) {
|
|
|
33300
33631
|
stderrBuf += String(chunk);
|
|
33301
33632
|
});
|
|
33302
33633
|
child.on("error", (err) => {
|
|
33303
|
-
|
|
33634
|
+
resolve2({ exitCode: 1, stderr: String(err) });
|
|
33304
33635
|
});
|
|
33305
33636
|
child.on("close", (code) => {
|
|
33306
|
-
|
|
33637
|
+
resolve2({ exitCode: code ?? 1, stderr: stderrBuf });
|
|
33307
33638
|
});
|
|
33308
33639
|
});
|
|
33309
33640
|
}
|
|
@@ -33319,7 +33650,7 @@ async function hydrateStagedDependencies(extractedPackageDir, deps = {}) {
|
|
|
33319
33650
|
}
|
|
33320
33651
|
}
|
|
33321
33652
|
function defaultNpmInstallProductionDeps(cwd) {
|
|
33322
|
-
return new Promise((
|
|
33653
|
+
return new Promise((resolve2) => {
|
|
33323
33654
|
const child = spawn4(
|
|
33324
33655
|
"npm",
|
|
33325
33656
|
[
|
|
@@ -33340,10 +33671,10 @@ function defaultNpmInstallProductionDeps(cwd) {
|
|
|
33340
33671
|
stderrBuf += String(chunk);
|
|
33341
33672
|
});
|
|
33342
33673
|
child.on("error", (err) => {
|
|
33343
|
-
|
|
33674
|
+
resolve2({ exitCode: 1, stderr: String(err) });
|
|
33344
33675
|
});
|
|
33345
33676
|
child.on("close", (code) => {
|
|
33346
|
-
|
|
33677
|
+
resolve2({ exitCode: code ?? 1, stderr: stderrBuf });
|
|
33347
33678
|
});
|
|
33348
33679
|
});
|
|
33349
33680
|
}
|
|
@@ -33537,13 +33868,8 @@ async function restartPhase(slockHome, deps = {}) {
|
|
|
33537
33868
|
return { ok: false, reason: "health_check_timeout" };
|
|
33538
33869
|
}
|
|
33539
33870
|
async function defaultReadServicePid(slockHome) {
|
|
33540
|
-
|
|
33541
|
-
|
|
33542
|
-
const pid = Number.parseInt(raw, 10);
|
|
33543
|
-
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
33544
|
-
} catch {
|
|
33545
|
-
return null;
|
|
33546
|
-
}
|
|
33871
|
+
const { pid } = await findLiveServicePid(slockHome);
|
|
33872
|
+
return pid;
|
|
33547
33873
|
}
|
|
33548
33874
|
async function defaultKillService(pid) {
|
|
33549
33875
|
try {
|
|
@@ -33861,7 +34187,7 @@ async function rollingDaemonHealthCheck(slockHome, deps = {}) {
|
|
|
33861
34187
|
}
|
|
33862
34188
|
async function defaultReadDaemonPid(slockHome, serverId) {
|
|
33863
34189
|
try {
|
|
33864
|
-
const raw = (await readFile14(
|
|
34190
|
+
const raw = (await readFile14(serverRunnerPidPath(slockHome, serverId), "utf8")).trim();
|
|
33865
34191
|
const pid = Number.parseInt(raw, 10);
|
|
33866
34192
|
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
33867
34193
|
} catch {
|
|
@@ -34067,6 +34393,8 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
|
34067
34393
|
if (drainMode !== void 0 && drainMode !== "drain") {
|
|
34068
34394
|
info(`Drain mode: ${drainMode}${drainMode === "force" ? " (in-flight turns will be dropped)" : ""}.`);
|
|
34069
34395
|
}
|
|
34396
|
+
const readBundledFn = deps.readBundledDaemonVersion ?? readBundledDaemonVersion;
|
|
34397
|
+
const fromBundledDaemonVersion = await readBundledFn(currentBinaryDir);
|
|
34070
34398
|
const runUpgradeFn = deps.runUpgradeFn ?? runUpgrade;
|
|
34071
34399
|
const spawnFreshService = deps.spawnFreshService ?? defaultSpawnFreshService;
|
|
34072
34400
|
const outcome = await runUpgradeFn(slockHome, {
|
|
@@ -34084,17 +34412,18 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
|
34084
34412
|
spawnFreshService: () => spawnFreshService(slockHome)
|
|
34085
34413
|
}
|
|
34086
34414
|
});
|
|
34087
|
-
const
|
|
34088
|
-
const
|
|
34089
|
-
const
|
|
34415
|
+
const toBundledDaemonVersion = await readBundledFn(currentBinaryDir);
|
|
34416
|
+
const bundle = (version, bundledDaemonVersion) => bundledDaemonVersion !== null ? { computerVersion: version, bundledDaemonVersion } : { computerVersion: version };
|
|
34417
|
+
const fromBundle = bundle(fromVersion, fromBundledDaemonVersion);
|
|
34418
|
+
const toBundle = bundle(targetVersion, toBundledDaemonVersion);
|
|
34090
34419
|
const logTrigger = opts.trigger ?? "cli";
|
|
34091
34420
|
if (outcome.ok) {
|
|
34092
34421
|
info(
|
|
34093
34422
|
`Upgrade ${fromVersion} \u2192 ${targetVersion} succeeded (health-OK in ${outcome.restart?.healthAfterMs ?? 0}ms).`
|
|
34094
34423
|
);
|
|
34095
34424
|
await appendUpgradeLogEntry(slockHome, {
|
|
34096
|
-
fromBundle
|
|
34097
|
-
toBundle
|
|
34425
|
+
fromBundle,
|
|
34426
|
+
toBundle,
|
|
34098
34427
|
channel: channel2,
|
|
34099
34428
|
trigger: logTrigger,
|
|
34100
34429
|
outcome: "ok"
|
|
@@ -34114,8 +34443,8 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
|
34114
34443
|
`Upgrade ${fromVersion} \u2192 ${targetVersion} succeeded; cleanup phase reported a non-fatal issue: ${outcome.reason ?? "unknown"}. Active layout + service are healthy.`
|
|
34115
34444
|
);
|
|
34116
34445
|
await appendUpgradeLogEntry(slockHome, {
|
|
34117
|
-
fromBundle
|
|
34118
|
-
toBundle
|
|
34446
|
+
fromBundle,
|
|
34447
|
+
toBundle,
|
|
34119
34448
|
channel: channel2,
|
|
34120
34449
|
trigger: logTrigger,
|
|
34121
34450
|
outcome: "ok"
|
|
@@ -34125,8 +34454,8 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
|
34125
34454
|
}
|
|
34126
34455
|
const code = mapFailurePhaseToCode(outcome);
|
|
34127
34456
|
await appendUpgradeLogEntry(slockHome, {
|
|
34128
|
-
fromBundle
|
|
34129
|
-
toBundle
|
|
34457
|
+
fromBundle,
|
|
34458
|
+
toBundle,
|
|
34130
34459
|
channel: channel2,
|
|
34131
34460
|
trigger: logTrigger,
|
|
34132
34461
|
outcome: "err",
|
|
@@ -34205,7 +34534,7 @@ async function defaultCurrentVersion() {
|
|
|
34205
34534
|
|
|
34206
34535
|
// src/upgradeTestHarness.ts
|
|
34207
34536
|
init_esm_shims();
|
|
34208
|
-
import { mkdir as mkdir15, readdir as readdir4, stat as
|
|
34537
|
+
import { mkdir as mkdir15, readdir as readdir4, stat as stat4, writeFile as writeFile12 } from "fs/promises";
|
|
34209
34538
|
import { join as join8 } from "path";
|
|
34210
34539
|
import { createHash as createHash4 } from "crypto";
|
|
34211
34540
|
var PHASES = /* @__PURE__ */ new Set([
|
|
@@ -34342,7 +34671,7 @@ async function arrangeSnapshotFailure(slockHome) {
|
|
|
34342
34671
|
}
|
|
34343
34672
|
async function pathInfo(path3) {
|
|
34344
34673
|
try {
|
|
34345
|
-
const s = await
|
|
34674
|
+
const s = await stat4(path3);
|
|
34346
34675
|
if (s.isDirectory()) return { kind: "dir", size: 0 };
|
|
34347
34676
|
if (s.isFile()) return { kind: "file", size: s.size };
|
|
34348
34677
|
return null;
|
|
@@ -34499,10 +34828,10 @@ async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
|
34499
34828
|
const activeVersion = await readServiceVersionEvidence(slockHome);
|
|
34500
34829
|
return { outcome, activeVersion };
|
|
34501
34830
|
}
|
|
34502
|
-
async function runUpgradeInstallSmokeCli(slockHome, opts, writer = (s) => process.stdout.write(s)) {
|
|
34831
|
+
async function runUpgradeInstallSmokeCli(slockHome, opts, writer = (s) => process.stdout.write(s), deps = {}) {
|
|
34503
34832
|
let report;
|
|
34504
34833
|
try {
|
|
34505
|
-
report = await runUpgradeInstallSmoke(slockHome, opts);
|
|
34834
|
+
report = await runUpgradeInstallSmoke(slockHome, opts, deps);
|
|
34506
34835
|
} catch (e) {
|
|
34507
34836
|
const msg = e instanceof Error ? e.message : String(e);
|
|
34508
34837
|
writer(
|
|
@@ -34589,10 +34918,10 @@ program2.command("setup").argument("<serverSlug>", "target Slock server slug (ca
|
|
|
34589
34918
|
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) => {
|
|
34590
34919
|
await withMutationLock(async () => runDetach(await resolveTargetServerId({ server: serverSlug }), serverSlug));
|
|
34591
34920
|
}));
|
|
34592
|
-
program2.command("status").description("Show this Computer's aggregate state (login + service + per-server
|
|
34921
|
+
program2.command("status").description("Show this Computer's aggregate state (login + service + per-server server-runners).").option("--json", "emit the machine-readable report").action(withCliExit(async (opts) => {
|
|
34593
34922
|
await runStatus({ json: opts.json });
|
|
34594
34923
|
}));
|
|
34595
|
-
program2.command("start").argument("[serverSlug]", "optional: verify this server is attached and ensure its
|
|
34924
|
+
program2.command("start").argument("[serverSlug]", "optional: verify this server is attached and ensure its server-runner is reconciled (default: ensure all attached)").description("Start/ensure the Computer service (manages all per-server server-runners).").option("--foreground", "stay in this terminal instead of detaching").action(withCliExit(async (serverSlug, opts) => {
|
|
34596
34925
|
await withMutationLock(
|
|
34597
34926
|
async () => runStart({
|
|
34598
34927
|
foreground: opts.foreground,
|
|
@@ -34601,7 +34930,7 @@ program2.command("start").argument("[serverSlug]", "optional: verify this server
|
|
|
34601
34930
|
})
|
|
34602
34931
|
);
|
|
34603
34932
|
}));
|
|
34604
|
-
program2.command("stop").description("Stop the Computer service (and all managed per-server
|
|
34933
|
+
program2.command("stop").description("Stop the Computer service (and all managed per-server server-runners).").action(withCliExit(async () => {
|
|
34605
34934
|
await withMutationLock(() => runStop());
|
|
34606
34935
|
}));
|
|
34607
34936
|
program2.command("doctor").argument("[serverSlug]", "optional: scope detail (recent crashes) to one server").description("Diagnose login + per-server attachments + per-server preflight (no secrets).").option("--json", "emit the machine-readable report").option("--cleanup", "after diagnosis, run the local residue cleanup pass").option("--fix", "alias for --cleanup (same behavior)").option("--reset-health", "clear <serverSlug>'s crash history so service resumes auto-restart").action(
|
|
@@ -34631,7 +34960,7 @@ program2.command("reset").description("Clear a degraded state and resume the ser
|
|
|
34631
34960
|
);
|
|
34632
34961
|
})
|
|
34633
34962
|
);
|
|
34634
|
-
program2.command("logs").description("Tail one server's
|
|
34963
|
+
program2.command("logs").description("Tail one server's server-runner log (or the service 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("--service", "tail the global service log instead of a per-server server-runner log").action(withCliExit(async (opts) => {
|
|
34635
34964
|
await runLogs({ lines: opts.lines, server: opts.server ?? null, service: !!opts.service });
|
|
34636
34965
|
}));
|
|
34637
34966
|
var runners = program2.command("runners").description("Computer runner control plane (per-server scoped; \xA712 whitelist server-side).");
|