@slock-ai/computer 0.0.15 → 0.0.16-alpha.0
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 +187 -176
- package/dist/lib/index.d.ts +4 -4
- package/dist/lib/index.js +9 -9
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -29737,7 +29737,7 @@ var ComputerAttachClient = class {
|
|
|
29737
29737
|
* over the machine. On success the server marks the machine row migrated
|
|
29738
29738
|
* and mints a fresh `sk_computer_*`. The raw legacy key MUST NOT be
|
|
29739
29739
|
* persisted by the caller — only the freshly-minted sk_computer_* lands
|
|
29740
|
-
* in
|
|
29740
|
+
* in runner.state.json.
|
|
29741
29741
|
*/
|
|
29742
29742
|
async adoptLegacy(legacyApiKey, name) {
|
|
29743
29743
|
const res = await (0, import_undici.fetch)(this.url("/api/computer/adopt-legacy"), {
|
|
@@ -29877,7 +29877,7 @@ function serverDir(slockHome, serverId) {
|
|
|
29877
29877
|
return path2.join(serversDir(slockHome), assertValidServerId(serverId));
|
|
29878
29878
|
}
|
|
29879
29879
|
function serverAttachmentPath(slockHome, serverId) {
|
|
29880
|
-
return path2.join(serverDir(slockHome, serverId), "
|
|
29880
|
+
return path2.join(serverDir(slockHome, serverId), "runner.state.json");
|
|
29881
29881
|
}
|
|
29882
29882
|
function serverDaemonPidPath(slockHome, serverId) {
|
|
29883
29883
|
return path2.join(serverDir(slockHome, serverId), "daemon.pid");
|
|
@@ -29894,14 +29894,17 @@ function serverHealthPath(slockHome, serverId) {
|
|
|
29894
29894
|
function serviceStatePath(slockHome) {
|
|
29895
29895
|
return path2.join(computerDir(slockHome), "service.state.json");
|
|
29896
29896
|
}
|
|
29897
|
-
function
|
|
29897
|
+
function servicePidPath(slockHome) {
|
|
29898
|
+
return path2.join(computerDir(slockHome), "service.pid");
|
|
29899
|
+
}
|
|
29900
|
+
function legacySupervisorPidPath(slockHome) {
|
|
29898
29901
|
return path2.join(computerDir(slockHome), "supervisor.pid");
|
|
29899
29902
|
}
|
|
29900
|
-
function
|
|
29901
|
-
return path2.join(computerDir(slockHome), "
|
|
29903
|
+
function serviceLogPath(slockHome) {
|
|
29904
|
+
return path2.join(computerDir(slockHome), "service.log");
|
|
29902
29905
|
}
|
|
29903
|
-
function
|
|
29904
|
-
return path2.join(computerDir(slockHome), "
|
|
29906
|
+
function serviceVersionPath(slockHome) {
|
|
29907
|
+
return path2.join(computerDir(slockHome), "service-version.json");
|
|
29905
29908
|
}
|
|
29906
29909
|
var HOSTNAME_SUFFIXES = [
|
|
29907
29910
|
".fritz.box",
|
|
@@ -30799,7 +30802,7 @@ async function appendAdoptionLog(slockHome, line) {
|
|
|
30799
30802
|
}
|
|
30800
30803
|
}
|
|
30801
30804
|
|
|
30802
|
-
// src/
|
|
30805
|
+
// src/service.ts
|
|
30803
30806
|
init_esm_shims();
|
|
30804
30807
|
import { spawn as spawn2 } from "child_process";
|
|
30805
30808
|
import { mkdir as mkdir8, readFile as readFile7, writeFile as writeFile7, open, rename as rename2 } from "fs/promises";
|
|
@@ -30869,8 +30872,8 @@ async function cleanupStalePidfile(pidfilePath) {
|
|
|
30869
30872
|
}
|
|
30870
30873
|
async function cleanupAllStalePidfiles(slockHome) {
|
|
30871
30874
|
const cleaned = [];
|
|
30872
|
-
if (await cleanupStalePidfile(
|
|
30873
|
-
cleaned.push(
|
|
30875
|
+
if (await cleanupStalePidfile(servicePidPath(slockHome))) {
|
|
30876
|
+
cleaned.push(servicePidPath(slockHome));
|
|
30874
30877
|
}
|
|
30875
30878
|
const attached = await listAttachedServerIds(slockHome);
|
|
30876
30879
|
for (const sid of attached) {
|
|
@@ -30919,7 +30922,7 @@ async function cleanupOrphanProcesses(slockHome, psSpawn) {
|
|
|
30919
30922
|
const managed = new Set(await listManagedServerIds(slockHome));
|
|
30920
30923
|
const signaled = [];
|
|
30921
30924
|
const knownPids = /* @__PURE__ */ new Set();
|
|
30922
|
-
const supPid = await readPidfileAt(
|
|
30925
|
+
const supPid = await readPidfileAt(servicePidPath(slockHome));
|
|
30923
30926
|
if (supPid !== null) knownPids.add(supPid);
|
|
30924
30927
|
for (const sid of managed) {
|
|
30925
30928
|
const pid = await readPidfileAt(serverDaemonPidPath(slockHome, sid));
|
|
@@ -31156,7 +31159,7 @@ async function emitRunnerStateTransition(slockHome, serverId, fromState, toState
|
|
|
31156
31159
|
trigger
|
|
31157
31160
|
};
|
|
31158
31161
|
try {
|
|
31159
|
-
const path3 =
|
|
31162
|
+
const path3 = serviceLogPath(slockHome);
|
|
31160
31163
|
await mkdir7(dirname7(path3), { recursive: true });
|
|
31161
31164
|
await appendFile2(path3, JSON.stringify(entry) + "\n");
|
|
31162
31165
|
} catch {
|
|
@@ -31199,7 +31202,7 @@ async function waitForManagedDaemonPids(slockHome, serverIds, opts) {
|
|
|
31199
31202
|
function buildTimeoutMessage(slockHome, serverIds, ready, input) {
|
|
31200
31203
|
const missing = serverIds.filter((id) => !ready.has(id));
|
|
31201
31204
|
const target = input.serverId && missing.length === 1 ? `${input.serverLabel ?? input.serverId}` : `${missing.length} daemon(s): ${missing.join(", ")}`;
|
|
31202
|
-
return `Timed out waiting for ${target} to start. Run \`slock-computer status\` and inspect ${
|
|
31205
|
+
return `Timed out waiting for ${target} to start. Run \`slock-computer status\` and inspect ${serviceLogPath(slockHome)} plus per-server daemon logs under ~/.slock/computer/servers/<serverId>/daemon.log.`;
|
|
31203
31206
|
}
|
|
31204
31207
|
async function start(input, options = {}) {
|
|
31205
31208
|
options.signal?.throwIfAborted?.();
|
|
@@ -31227,11 +31230,11 @@ async function start(input, options = {}) {
|
|
|
31227
31230
|
for (const id of managedTargets) {
|
|
31228
31231
|
await setServerManaged(slockHome, id);
|
|
31229
31232
|
}
|
|
31230
|
-
const existing = await readPidfileAt(
|
|
31233
|
+
const existing = await readPidfileAt(servicePidPath(slockHome));
|
|
31231
31234
|
if (existing && isProcessAlive2(existing)) {
|
|
31232
31235
|
emit4(options, {
|
|
31233
31236
|
type: "already_running",
|
|
31234
|
-
|
|
31237
|
+
servicePid: existing,
|
|
31235
31238
|
managedTargets,
|
|
31236
31239
|
attachedCount: attached.length
|
|
31237
31240
|
});
|
|
@@ -31248,8 +31251,8 @@ async function start(input, options = {}) {
|
|
|
31248
31251
|
managedTargets,
|
|
31249
31252
|
attachedCount: attached.length,
|
|
31250
31253
|
ready: ready2,
|
|
31251
|
-
|
|
31252
|
-
|
|
31254
|
+
servicePid: existing,
|
|
31255
|
+
serviceLogPath: serviceLogPath(slockHome)
|
|
31253
31256
|
};
|
|
31254
31257
|
}
|
|
31255
31258
|
if (input.foreground) {
|
|
@@ -31258,11 +31261,11 @@ async function start(input, options = {}) {
|
|
|
31258
31261
|
managedTargets,
|
|
31259
31262
|
attachedCount: attached.length
|
|
31260
31263
|
});
|
|
31261
|
-
const
|
|
31264
|
+
const service = options.runService ?? runService;
|
|
31262
31265
|
const previousParentLockMarker = process.env[PARENT_LOCK_HELD_ENV_VAR];
|
|
31263
31266
|
process.env[PARENT_LOCK_HELD_ENV_VAR] = "1";
|
|
31264
31267
|
try {
|
|
31265
|
-
await
|
|
31268
|
+
await service();
|
|
31266
31269
|
} finally {
|
|
31267
31270
|
if (previousParentLockMarker === void 0) delete process.env[PARENT_LOCK_HELD_ENV_VAR];
|
|
31268
31271
|
else process.env[PARENT_LOCK_HELD_ENV_VAR] = previousParentLockMarker;
|
|
@@ -31272,34 +31275,34 @@ async function start(input, options = {}) {
|
|
|
31272
31275
|
managedTargets,
|
|
31273
31276
|
attachedCount: attached.length,
|
|
31274
31277
|
ready: /* @__PURE__ */ new Map(),
|
|
31275
|
-
|
|
31276
|
-
|
|
31278
|
+
servicePid: null,
|
|
31279
|
+
serviceLogPath: serviceLogPath(slockHome)
|
|
31277
31280
|
};
|
|
31278
31281
|
}
|
|
31279
31282
|
options.signal?.throwIfAborted?.();
|
|
31280
31283
|
let pid;
|
|
31281
31284
|
try {
|
|
31282
|
-
pid = await (options.
|
|
31285
|
+
pid = await (options.spawnDetachedService ?? spawnDetachedService)(slockHome);
|
|
31283
31286
|
} catch (err) {
|
|
31284
31287
|
const msg = err instanceof Error ? err.message : String(err);
|
|
31285
31288
|
throw new ComputerServiceError("SUPERVISOR_SPAWN_FAILED", msg, err);
|
|
31286
31289
|
}
|
|
31287
31290
|
emit4(options, {
|
|
31288
31291
|
type: "spawned",
|
|
31289
|
-
|
|
31292
|
+
servicePid: pid,
|
|
31290
31293
|
managedTargets,
|
|
31291
31294
|
attachedCount: attached.length
|
|
31292
31295
|
});
|
|
31293
31296
|
if (options.signal?.aborted) {
|
|
31294
31297
|
const ready2 = await pollReadyOnce(slockHome, managedTargets, options);
|
|
31295
|
-
emit4(options, { type: "aborted",
|
|
31298
|
+
emit4(options, { type: "aborted", servicePid: pid, managedTargets, ready: ready2 });
|
|
31296
31299
|
return {
|
|
31297
31300
|
status: "aborted",
|
|
31298
31301
|
managedTargets,
|
|
31299
31302
|
attachedCount: attached.length,
|
|
31300
31303
|
ready: ready2,
|
|
31301
|
-
|
|
31302
|
-
|
|
31304
|
+
servicePid: pid,
|
|
31305
|
+
serviceLogPath: serviceLogPath(slockHome)
|
|
31303
31306
|
};
|
|
31304
31307
|
}
|
|
31305
31308
|
const ready = await waitForManagedDaemonPids(slockHome, managedTargets, options);
|
|
@@ -31315,8 +31318,8 @@ async function start(input, options = {}) {
|
|
|
31315
31318
|
managedTargets,
|
|
31316
31319
|
attachedCount: attached.length,
|
|
31317
31320
|
ready,
|
|
31318
|
-
|
|
31319
|
-
|
|
31321
|
+
servicePid: pid,
|
|
31322
|
+
serviceLogPath: serviceLogPath(slockHome)
|
|
31320
31323
|
};
|
|
31321
31324
|
}
|
|
31322
31325
|
async function pollReadyOnce(slockHome, serverIds, opts) {
|
|
@@ -31348,14 +31351,22 @@ async function stop(input = {}, options = {}) {
|
|
|
31348
31351
|
const slockHome = resolveSlockHome();
|
|
31349
31352
|
const readPidfile = options.readPidfile ?? readPidfileAt;
|
|
31350
31353
|
const isAlive = options.isProcessAlive ?? isProcessAlive2;
|
|
31351
|
-
const killer = options.
|
|
31354
|
+
const killer = options.killService ?? ((pid2) => {
|
|
31352
31355
|
process.kill(pid2, "SIGTERM");
|
|
31353
31356
|
});
|
|
31354
31357
|
const sleep2 = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
31355
31358
|
const pollIntervalMs = options.pollIntervalMs ?? STOP_POLL_INTERVAL_MS;
|
|
31356
31359
|
const timeoutMs = options.timeoutMs ?? STOP_TIMEOUT_MS;
|
|
31357
|
-
|
|
31358
|
-
|
|
31360
|
+
let pidfilePath = servicePidPath(slockHome);
|
|
31361
|
+
let pid = await readPidfile(pidfilePath);
|
|
31362
|
+
if (pid === null) {
|
|
31363
|
+
const legacyPidfilePath = legacySupervisorPidPath(slockHome);
|
|
31364
|
+
const legacyPid = await readPidfile(legacyPidfilePath);
|
|
31365
|
+
if (legacyPid !== null) {
|
|
31366
|
+
pidfilePath = legacyPidfilePath;
|
|
31367
|
+
pid = legacyPid;
|
|
31368
|
+
}
|
|
31369
|
+
}
|
|
31359
31370
|
emit5(options, { type: "stopping", pid });
|
|
31360
31371
|
if (pid === null) {
|
|
31361
31372
|
emit5(options, { type: "not_running" });
|
|
@@ -31373,7 +31384,7 @@ async function stop(input = {}, options = {}) {
|
|
|
31373
31384
|
const cause = err instanceof Error ? err : new Error(String(err));
|
|
31374
31385
|
throw new ComputerServiceError(
|
|
31375
31386
|
"STOP_SIGNAL_FAILED",
|
|
31376
|
-
`Failed to send SIGTERM to
|
|
31387
|
+
`Failed to send SIGTERM to service (pid ${pid}): ${cause.message}. Check process permissions or run: kill ${pid}`,
|
|
31377
31388
|
err
|
|
31378
31389
|
);
|
|
31379
31390
|
}
|
|
@@ -31392,7 +31403,7 @@ async function stop(input = {}, options = {}) {
|
|
|
31392
31403
|
}
|
|
31393
31404
|
throw new ComputerServiceError(
|
|
31394
31405
|
"STOP_TIMEOUT",
|
|
31395
|
-
`
|
|
31406
|
+
`Service (pid ${pid}) did not exit within ${timeoutMs}ms after SIGTERM. Force-kill with: kill -9 ${pid}`
|
|
31396
31407
|
);
|
|
31397
31408
|
}
|
|
31398
31409
|
|
|
@@ -31508,16 +31519,16 @@ async function detach(input, options = {}) {
|
|
|
31508
31519
|
};
|
|
31509
31520
|
}
|
|
31510
31521
|
|
|
31511
|
-
// src/
|
|
31522
|
+
// src/service.ts
|
|
31512
31523
|
function buildResidentSpawn(mode, serverId, selfEntry = process.argv[1] ?? "", execArgv = process.execArgv) {
|
|
31513
31524
|
const tail = serverId ? [mode, serverId] : [mode];
|
|
31514
31525
|
return { command: process.execPath, args: [...execArgv, selfEntry, ...tail] };
|
|
31515
31526
|
}
|
|
31516
31527
|
var PARENT_LOCK_HELD_ENV_VAR = "SLOCK_COMPUTER_PARENT_MUTATION_LOCK_HELD";
|
|
31517
|
-
async function
|
|
31528
|
+
async function spawnDetachedService(slockHome) {
|
|
31518
31529
|
await mkdir8(computerDir(slockHome), { recursive: true });
|
|
31519
|
-
const supLogFd = await open(
|
|
31520
|
-
const { command, args } = buildResidentSpawn("
|
|
31530
|
+
const supLogFd = await open(serviceLogPath(slockHome), "a");
|
|
31531
|
+
const { command, args } = buildResidentSpawn("__service", null);
|
|
31521
31532
|
const child = spawn2(command, args, {
|
|
31522
31533
|
detached: true,
|
|
31523
31534
|
stdio: ["ignore", supLogFd.fd, supLogFd.fd],
|
|
@@ -31534,9 +31545,9 @@ async function spawnDetachedSupervisor(slockHome) {
|
|
|
31534
31545
|
child.unref();
|
|
31535
31546
|
await supLogFd.close();
|
|
31536
31547
|
if (!pid) {
|
|
31537
|
-
throw new Error("SUPERVISOR_SPAWN_FAILED: could not spawn the
|
|
31548
|
+
throw new Error("SUPERVISOR_SPAWN_FAILED: could not spawn the service process");
|
|
31538
31549
|
}
|
|
31539
|
-
await writePidfileAt(
|
|
31550
|
+
await writePidfileAt(servicePidPath(slockHome), pid);
|
|
31540
31551
|
return pid;
|
|
31541
31552
|
}
|
|
31542
31553
|
var EX_CONFIG_EXIT_CODE = 78;
|
|
@@ -31562,7 +31573,7 @@ var defaultCoreFactory = async (creds) => {
|
|
|
31562
31573
|
}
|
|
31563
31574
|
return new coreMod.DaemonCore({ serverUrl: creds.serverUrl, apiKey: creds.apiKey, localTrace: true });
|
|
31564
31575
|
};
|
|
31565
|
-
function
|
|
31576
|
+
function classifyRunnerExit(code, signal) {
|
|
31566
31577
|
if (code === EX_CONFIG_EXIT_CODE) return "config-error";
|
|
31567
31578
|
if (signal === "SIGTERM" || signal === "SIGINT") return "graceful";
|
|
31568
31579
|
if (code === 0) return "graceful";
|
|
@@ -31607,18 +31618,18 @@ function formatReadySummary(ready, serverIds, opts) {
|
|
|
31607
31618
|
}
|
|
31608
31619
|
return `Daemons for ${serverIds.length} managed server(s) are running.`;
|
|
31609
31620
|
}
|
|
31610
|
-
async function
|
|
31621
|
+
async function runServiceStartupRecovery(slockHome) {
|
|
31611
31622
|
const parentHoldsLock = process.env[PARENT_LOCK_HELD_ENV_VAR] === "1";
|
|
31612
31623
|
try {
|
|
31613
31624
|
if (parentHoldsLock) {
|
|
31614
31625
|
process.stderr.write(
|
|
31615
|
-
"
|
|
31626
|
+
"Service startup: parent CLI holds mutation lock \u2014 skipping lock cleanup.\n"
|
|
31616
31627
|
);
|
|
31617
31628
|
} else {
|
|
31618
31629
|
const releasedLocks = await forceReleaseLock(slockHome);
|
|
31619
31630
|
if (releasedLocks.length > 0) {
|
|
31620
31631
|
process.stderr.write(
|
|
31621
|
-
`
|
|
31632
|
+
`Service startup: force-released ${releasedLocks.length} stale lock(s).
|
|
31622
31633
|
`
|
|
31623
31634
|
);
|
|
31624
31635
|
}
|
|
@@ -31626,19 +31637,19 @@ async function runSupervisorStartupRecovery(slockHome) {
|
|
|
31626
31637
|
const report = await runFullCleanup(slockHome, { skipLockCleanup: parentHoldsLock });
|
|
31627
31638
|
if (report.anyAction) {
|
|
31628
31639
|
process.stderr.write(
|
|
31629
|
-
`
|
|
31640
|
+
`Service startup recovery: cleaned ${report.stalePidfiles.length} pidfile(s), ${report.powerLossRecovered.length} quarantined, ${report.tmpFilesCleared.length} tmp file(s), ${report.staleLocks.length} stale lock(s).
|
|
31630
31641
|
`
|
|
31631
31642
|
);
|
|
31632
31643
|
}
|
|
31633
31644
|
} catch (err) {
|
|
31634
31645
|
const msg = err instanceof Error ? err.message : String(err);
|
|
31635
31646
|
process.stderr.write(
|
|
31636
|
-
`
|
|
31647
|
+
`Service startup recovery pass failed: ${msg}. Continuing; cleanup will retry on next service restart.
|
|
31637
31648
|
`
|
|
31638
31649
|
);
|
|
31639
31650
|
}
|
|
31640
31651
|
}
|
|
31641
|
-
async function
|
|
31652
|
+
async function resolveServiceIdentity() {
|
|
31642
31653
|
const here = fileURLToPath2(import.meta.url);
|
|
31643
31654
|
const installRoot = dirname8(dirname8(here));
|
|
31644
31655
|
let version = null;
|
|
@@ -31652,30 +31663,30 @@ async function resolveSupervisorIdentity() {
|
|
|
31652
31663
|
}
|
|
31653
31664
|
return { installRoot, version };
|
|
31654
31665
|
}
|
|
31655
|
-
async function
|
|
31666
|
+
async function writeServiceVersionEvidence(slockHome) {
|
|
31656
31667
|
try {
|
|
31657
|
-
const ident = await
|
|
31668
|
+
const ident = await resolveServiceIdentity();
|
|
31658
31669
|
const payload = {
|
|
31659
31670
|
version: ident.version,
|
|
31660
31671
|
installRoot: ident.installRoot,
|
|
31661
31672
|
pid: process.pid,
|
|
31662
31673
|
writtenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
31663
31674
|
};
|
|
31664
|
-
const dest =
|
|
31675
|
+
const dest = serviceVersionPath(slockHome);
|
|
31665
31676
|
const tmp = `${dest}.tmp`;
|
|
31666
31677
|
await writeFile7(tmp, JSON.stringify(payload) + "\n", { mode: 384 });
|
|
31667
31678
|
await rename2(tmp, dest);
|
|
31668
31679
|
} catch (err) {
|
|
31669
31680
|
const msg = err instanceof Error ? err.message : String(err);
|
|
31670
31681
|
process.stderr.write(
|
|
31671
|
-
`
|
|
31682
|
+
`Service: failed to write version evidence: ${msg}. Continuing.
|
|
31672
31683
|
`
|
|
31673
31684
|
);
|
|
31674
31685
|
}
|
|
31675
31686
|
}
|
|
31676
|
-
async function
|
|
31687
|
+
async function readServiceVersionEvidence(slockHome) {
|
|
31677
31688
|
try {
|
|
31678
|
-
const raw = await readFile7(
|
|
31689
|
+
const raw = await readFile7(serviceVersionPath(slockHome), "utf8");
|
|
31679
31690
|
const parsed = JSON.parse(raw);
|
|
31680
31691
|
if (typeof parsed.installRoot !== "string" || typeof parsed.pid !== "number" || typeof parsed.writtenAt !== "string" || parsed.version !== null && typeof parsed.version !== "string") {
|
|
31681
31692
|
return null;
|
|
@@ -31690,12 +31701,12 @@ async function readSupervisorVersionEvidence(slockHome) {
|
|
|
31690
31701
|
return null;
|
|
31691
31702
|
}
|
|
31692
31703
|
}
|
|
31693
|
-
async function
|
|
31704
|
+
async function runService() {
|
|
31694
31705
|
const slockHome = resolveSlockHome();
|
|
31695
31706
|
await mkdir8(computerDir(slockHome), { recursive: true });
|
|
31696
|
-
await
|
|
31697
|
-
await writePidfileAt(
|
|
31698
|
-
await
|
|
31707
|
+
await runServiceStartupRecovery(slockHome);
|
|
31708
|
+
await writePidfileAt(servicePidPath(slockHome), process.pid);
|
|
31709
|
+
await writeServiceVersionEvidence(slockHome);
|
|
31699
31710
|
const children = /* @__PURE__ */ new Map();
|
|
31700
31711
|
const { [PARENT_LOCK_HELD_ENV_VAR]: _parentLockMarker, ...childEnv } = process.env;
|
|
31701
31712
|
const spawnChild = async (serverId) => {
|
|
@@ -31718,14 +31729,14 @@ async function runSupervise() {
|
|
|
31718
31729
|
children.delete(serverId);
|
|
31719
31730
|
await clearPidfileAt(serverDaemonPidPath(slockHome, serverId));
|
|
31720
31731
|
if (handle.stopping) return;
|
|
31721
|
-
const classification =
|
|
31732
|
+
const classification = classifyRunnerExit(code, signal);
|
|
31722
31733
|
if (classification === "config-error") {
|
|
31723
31734
|
try {
|
|
31724
31735
|
await markFatalConfig(slockHome, serverId, code, signal);
|
|
31725
31736
|
} catch {
|
|
31726
31737
|
}
|
|
31727
31738
|
process.stderr.write(
|
|
31728
|
-
`
|
|
31739
|
+
`Service: server ${serverId} child exited with EX_CONFIG (${EX_CONFIG_EXIT_CODE}); marked degraded, NOT auto-restarting. See ${serverDaemonLogPath(slockHome, serverId)} for the actionable error.
|
|
31729
31740
|
`
|
|
31730
31741
|
);
|
|
31731
31742
|
return;
|
|
@@ -31743,7 +31754,7 @@ async function runSupervise() {
|
|
|
31743
31754
|
}
|
|
31744
31755
|
if (await isDegraded(slockHome, serverId)) {
|
|
31745
31756
|
process.stderr.write(
|
|
31746
|
-
`
|
|
31757
|
+
`Service: server ${serverId} marked degraded (>=3 crashes in 60s); skipping auto-restart. Run \`slock-computer doctor ${serverId} --reset-health\` after fixing the underlying issue.
|
|
31747
31758
|
`
|
|
31748
31759
|
);
|
|
31749
31760
|
return;
|
|
@@ -31776,7 +31787,7 @@ async function runSupervise() {
|
|
|
31776
31787
|
if (shuttingDown) return;
|
|
31777
31788
|
shuttingDown = true;
|
|
31778
31789
|
for (const handle of children.values()) killChild(handle);
|
|
31779
|
-
void clearPidfileAt(
|
|
31790
|
+
void clearPidfileAt(servicePidPath(slockHome)).then(() => process.exit(0));
|
|
31780
31791
|
};
|
|
31781
31792
|
process.on("SIGTERM", shutdown);
|
|
31782
31793
|
process.on("SIGINT", shutdown);
|
|
@@ -31798,7 +31809,7 @@ async function runStart(opts = {}, deps = {}) {
|
|
|
31798
31809
|
serverLabel: opts.serverLabel ?? null
|
|
31799
31810
|
},
|
|
31800
31811
|
{
|
|
31801
|
-
|
|
31812
|
+
spawnDetachedService: deps.spawnDetachedService,
|
|
31802
31813
|
readPidfile: deps.readPidfile,
|
|
31803
31814
|
isProcessAlive: deps.isProcessAlive,
|
|
31804
31815
|
sleep: deps.sleep,
|
|
@@ -31806,17 +31817,17 @@ async function runStart(opts = {}, deps = {}) {
|
|
|
31806
31817
|
ensurePollIntervalMs: deps.ensurePollIntervalMs,
|
|
31807
31818
|
onEvent: (event) => {
|
|
31808
31819
|
if (event.type === "already_running") {
|
|
31809
|
-
info(`
|
|
31820
|
+
info(`Service already running (pid ${event.servicePid}).`);
|
|
31810
31821
|
} else if (event.type === "running") {
|
|
31811
31822
|
info(
|
|
31812
|
-
`Running
|
|
31823
|
+
`Running service in the foreground (managing ${event.managedTargets.length} of ${event.attachedCount} attached server(s)). Ctrl-C to stop.`
|
|
31813
31824
|
);
|
|
31814
31825
|
} else if (event.type === "spawned") {
|
|
31815
|
-
info(`
|
|
31826
|
+
info(`Service started (pid ${event.servicePid}); keeps running after this terminal closes.`);
|
|
31816
31827
|
spawnedBackground = {
|
|
31817
31828
|
managedCount: event.managedTargets.length,
|
|
31818
31829
|
attachedCount: event.attachedCount,
|
|
31819
|
-
logPath:
|
|
31830
|
+
logPath: serviceLogPath(resolveSlockHome())
|
|
31820
31831
|
};
|
|
31821
31832
|
} else if (event.type === "ready") {
|
|
31822
31833
|
info(formatReadySummary(event.ready, event.managedTargets, opts));
|
|
@@ -31847,17 +31858,17 @@ async function runStop(deps = {}) {
|
|
|
31847
31858
|
{
|
|
31848
31859
|
readPidfile: deps.readPidfile,
|
|
31849
31860
|
isProcessAlive: deps.isProcessAlive,
|
|
31850
|
-
|
|
31861
|
+
killService: deps.killService,
|
|
31851
31862
|
sleep: deps.sleep,
|
|
31852
31863
|
pollIntervalMs: deps.pollIntervalMs,
|
|
31853
31864
|
timeoutMs: deps.timeoutMs,
|
|
31854
31865
|
onEvent: (event) => {
|
|
31855
31866
|
if (event.type === "not_running") {
|
|
31856
|
-
info("
|
|
31867
|
+
info("Service not running.");
|
|
31857
31868
|
} else if (event.type === "stale_pidfile_cleared") {
|
|
31858
|
-
info(`
|
|
31869
|
+
info(`Service not running (cleared stale pidfile for pid ${event.pid}).`);
|
|
31859
31870
|
} else if (event.type === "stopped") {
|
|
31860
|
-
info(`Stopped
|
|
31871
|
+
info(`Stopped service (pid ${event.pid}).`);
|
|
31861
31872
|
}
|
|
31862
31873
|
}
|
|
31863
31874
|
}
|
|
@@ -31882,7 +31893,7 @@ async function runDetach(serverId, serverLabel = serverId) {
|
|
|
31882
31893
|
} else if (event.type === "detached") {
|
|
31883
31894
|
info(`Detached from server ${event.serverLabel}.`);
|
|
31884
31895
|
info(
|
|
31885
|
-
`The
|
|
31896
|
+
`The service (if running) will stop that server's daemon on its next reconcile tick.`
|
|
31886
31897
|
);
|
|
31887
31898
|
}
|
|
31888
31899
|
}
|
|
@@ -32206,9 +32217,9 @@ async function buildStatusReport(installRoot) {
|
|
|
32206
32217
|
const sessionRead = await readUserSession(userSessionPath(installRoot));
|
|
32207
32218
|
const session = sessionRead.session;
|
|
32208
32219
|
const attachments = await listServerAttachments(installRoot);
|
|
32209
|
-
const
|
|
32210
|
-
...await pidStatus(
|
|
32211
|
-
logPath:
|
|
32220
|
+
const service = {
|
|
32221
|
+
...await pidStatus(servicePidPath(installRoot)),
|
|
32222
|
+
logPath: serviceLogPath(installRoot)
|
|
32212
32223
|
};
|
|
32213
32224
|
const servers = [];
|
|
32214
32225
|
for (const a of attachments) {
|
|
@@ -32231,7 +32242,7 @@ async function buildStatusReport(installRoot) {
|
|
|
32231
32242
|
userId: session ? str(session.userId) : null,
|
|
32232
32243
|
loginServerUrl: session ? str(session.serverUrl) : null,
|
|
32233
32244
|
userSessionError: sessionRead.state === "invalid" ? sessionRead.error : null,
|
|
32234
|
-
|
|
32245
|
+
service,
|
|
32235
32246
|
servers
|
|
32236
32247
|
};
|
|
32237
32248
|
}
|
|
@@ -32252,9 +32263,9 @@ async function runStatus(opts) {
|
|
|
32252
32263
|
);
|
|
32253
32264
|
if (report.loginServerUrl) info(`Login server: ${report.loginServerUrl}`);
|
|
32254
32265
|
info(
|
|
32255
|
-
`
|
|
32266
|
+
`Service: ${report.service.running ? `running (pid ${report.service.pid})` : "stopped \u2014 run `slock-computer start`"}`
|
|
32256
32267
|
);
|
|
32257
|
-
info(`
|
|
32268
|
+
info(`Service log: ${report.service.logPath}`);
|
|
32258
32269
|
info("");
|
|
32259
32270
|
if (report.servers.length === 0) {
|
|
32260
32271
|
info("Attachments: none \u2014 run `slock-computer attach /<serverSlug>` (e.g. `/myserver`).");
|
|
@@ -32486,8 +32497,8 @@ async function runDoctorChecks() {
|
|
|
32486
32497
|
report.userSessionError ? { name: "user session", ok: false, detail: "invalid user session file \u2014 re-run `slock-computer login`" } : report.loggedIn ? { name: "user session", ok: true, detail: `logged in (user ${report.userId ?? "?"})` } : { name: "user session", ok: false, detail: "not logged in \u2014 run `slock-computer login`" }
|
|
32487
32498
|
);
|
|
32488
32499
|
checks.push(
|
|
32489
|
-
report.
|
|
32490
|
-
name: "
|
|
32500
|
+
report.service.running ? { name: "service", ok: true, detail: `running (pid ${report.service.pid})` } : {
|
|
32501
|
+
name: "service",
|
|
32491
32502
|
ok: true,
|
|
32492
32503
|
detail: "stopped (run `slock-computer start` when you want background)"
|
|
32493
32504
|
}
|
|
@@ -32533,7 +32544,7 @@ async function runDoctor(opts) {
|
|
|
32533
32544
|
if (opts.resetHealth && opts.serverId) {
|
|
32534
32545
|
await resetHealth(slockHome, opts.serverId);
|
|
32535
32546
|
info(`Reset health state for server ${opts.serverLabel ?? opts.serverId}.`);
|
|
32536
|
-
info(`
|
|
32547
|
+
info(`Service will resume auto-restart on next daemon exit.`);
|
|
32537
32548
|
}
|
|
32538
32549
|
const checks = await runDoctorChecks();
|
|
32539
32550
|
const allOk = checks.every((c) => c.ok);
|
|
@@ -32607,14 +32618,14 @@ import { readFile as readFile10 } from "fs/promises";
|
|
|
32607
32618
|
var DEFAULT_LINES = 200;
|
|
32608
32619
|
async function runLogs(opts) {
|
|
32609
32620
|
const home = resolveSlockHome();
|
|
32610
|
-
const file = opts.
|
|
32621
|
+
const file = opts.service ? serviceLogPath(home) : serverDaemonLogPath(home, await resolveTargetServerId({ server: opts.server }));
|
|
32611
32622
|
let content;
|
|
32612
32623
|
try {
|
|
32613
32624
|
content = await readFile10(file, "utf8");
|
|
32614
32625
|
} catch {
|
|
32615
32626
|
fail(
|
|
32616
32627
|
"NO_DAEMON_LOG",
|
|
32617
|
-
opts.
|
|
32628
|
+
opts.service ? `No service log at ${file}. Start the service first (\`slock-computer start\`).` : `No daemon log at ${file}. Start its daemon first (\`slock-computer start\`).`
|
|
32618
32629
|
);
|
|
32619
32630
|
}
|
|
32620
32631
|
const n = Number.isInteger(opts.lines) && opts.lines > 0 ? opts.lines : DEFAULT_LINES;
|
|
@@ -32682,7 +32693,7 @@ async function emitServiceStateTransition(slockHome, fromState, toState, trigger
|
|
|
32682
32693
|
trigger
|
|
32683
32694
|
};
|
|
32684
32695
|
try {
|
|
32685
|
-
const path3 =
|
|
32696
|
+
const path3 = serviceLogPath(slockHome);
|
|
32686
32697
|
await mkdir10(dirname10(path3), { recursive: true });
|
|
32687
32698
|
await appendFile3(path3, JSON.stringify(entry) + "\n");
|
|
32688
32699
|
} catch {
|
|
@@ -32866,7 +32877,7 @@ async function runChannelSet(slockHome, raw) {
|
|
|
32866
32877
|
}
|
|
32867
32878
|
await writeChannel(slockHome, parsed);
|
|
32868
32879
|
info(`Channel set to ${parsed}.`);
|
|
32869
|
-
info(`Note:
|
|
32880
|
+
info(`Note: service reads channel at startup; restart \`slock-computer start\` to apply.`);
|
|
32870
32881
|
}
|
|
32871
32882
|
|
|
32872
32883
|
// src/upgradeCli.ts
|
|
@@ -33372,49 +33383,49 @@ async function rollbackSwap(currentBinaryDir, deps = {}) {
|
|
|
33372
33383
|
}
|
|
33373
33384
|
}
|
|
33374
33385
|
async function rollbackRestart(slockHome, currentBinaryDir, deps = {}) {
|
|
33375
|
-
const
|
|
33386
|
+
const readServicePid = deps.readServicePid ?? (() => defaultReadServicePid(slockHome));
|
|
33376
33387
|
const isProcessAlive4 = deps.isProcessAlive ?? defaultIsProcessAlive;
|
|
33377
|
-
const
|
|
33378
|
-
const
|
|
33388
|
+
const killService = deps.killService ?? defaultKillService;
|
|
33389
|
+
const forceKillService = deps.forceKillService ?? defaultForceKillService;
|
|
33379
33390
|
const waitForExit = deps.waitForExit ?? defaultWaitForExit;
|
|
33380
|
-
const
|
|
33391
|
+
const spawnFreshService = deps.spawnFreshService;
|
|
33381
33392
|
const healthCheck = deps.healthCheck ?? (() => defaultHealthCheck(slockHome));
|
|
33382
33393
|
const healthTimeoutMs = deps.healthTimeoutMs ?? 3e4;
|
|
33383
33394
|
const healthPollIntervalMs = deps.healthPollIntervalMs ?? 500;
|
|
33384
|
-
let
|
|
33395
|
+
let serviceStopped = false;
|
|
33385
33396
|
try {
|
|
33386
|
-
const pid = await
|
|
33397
|
+
const pid = await readServicePid();
|
|
33387
33398
|
if (pid === null || !isProcessAlive4(pid)) {
|
|
33388
|
-
|
|
33399
|
+
serviceStopped = true;
|
|
33389
33400
|
} else {
|
|
33390
|
-
await
|
|
33401
|
+
await killService(pid);
|
|
33391
33402
|
const exited = await waitForExit(pid, 1e4);
|
|
33392
33403
|
if (!exited) {
|
|
33393
|
-
await
|
|
33404
|
+
await forceKillService(pid);
|
|
33394
33405
|
const escalatedExit = await waitForExit(pid, 5e3);
|
|
33395
|
-
|
|
33406
|
+
serviceStopped = escalatedExit;
|
|
33396
33407
|
} else {
|
|
33397
|
-
|
|
33408
|
+
serviceStopped = true;
|
|
33398
33409
|
}
|
|
33399
33410
|
}
|
|
33400
33411
|
} catch (e) {
|
|
33401
33412
|
return {
|
|
33402
33413
|
binaryRestored: false,
|
|
33403
|
-
|
|
33404
|
-
|
|
33405
|
-
|
|
33414
|
+
serviceStopped: false,
|
|
33415
|
+
serviceRespawned: false,
|
|
33416
|
+
serviceHealthy: false,
|
|
33406
33417
|
failedStep: "stop",
|
|
33407
33418
|
reason: e instanceof Error ? e.message : String(e)
|
|
33408
33419
|
};
|
|
33409
33420
|
}
|
|
33410
|
-
if (!
|
|
33421
|
+
if (!serviceStopped) {
|
|
33411
33422
|
return {
|
|
33412
33423
|
binaryRestored: false,
|
|
33413
|
-
|
|
33414
|
-
|
|
33415
|
-
|
|
33424
|
+
serviceStopped: false,
|
|
33425
|
+
serviceRespawned: false,
|
|
33426
|
+
serviceHealthy: false,
|
|
33416
33427
|
failedStep: "stop",
|
|
33417
|
-
reason: "new-version
|
|
33428
|
+
reason: "new-version service did not exit (graceful + SIGKILL both timed out)"
|
|
33418
33429
|
};
|
|
33419
33430
|
}
|
|
33420
33431
|
const swapRb = await rollbackSwap(currentBinaryDir, {
|
|
@@ -33424,31 +33435,31 @@ async function rollbackRestart(slockHome, currentBinaryDir, deps = {}) {
|
|
|
33424
33435
|
if (!swapRb.rolledBack) {
|
|
33425
33436
|
return {
|
|
33426
33437
|
binaryRestored: false,
|
|
33427
|
-
|
|
33428
|
-
|
|
33429
|
-
|
|
33438
|
+
serviceStopped: true,
|
|
33439
|
+
serviceRespawned: false,
|
|
33440
|
+
serviceHealthy: false,
|
|
33430
33441
|
failedStep: "binary",
|
|
33431
33442
|
reason: "could not restore .prev \u2192 currentBinaryDir"
|
|
33432
33443
|
};
|
|
33433
33444
|
}
|
|
33434
|
-
if (!
|
|
33445
|
+
if (!spawnFreshService) {
|
|
33435
33446
|
return {
|
|
33436
33447
|
binaryRestored: true,
|
|
33437
|
-
|
|
33438
|
-
|
|
33439
|
-
|
|
33448
|
+
serviceStopped: true,
|
|
33449
|
+
serviceRespawned: false,
|
|
33450
|
+
serviceHealthy: false,
|
|
33440
33451
|
failedStep: "respawn",
|
|
33441
|
-
reason: "no
|
|
33452
|
+
reason: "no spawnFreshService callback wired; old service not respawned"
|
|
33442
33453
|
};
|
|
33443
33454
|
}
|
|
33444
33455
|
try {
|
|
33445
|
-
await
|
|
33456
|
+
await spawnFreshService();
|
|
33446
33457
|
} catch (e) {
|
|
33447
33458
|
return {
|
|
33448
33459
|
binaryRestored: true,
|
|
33449
|
-
|
|
33450
|
-
|
|
33451
|
-
|
|
33460
|
+
serviceStopped: true,
|
|
33461
|
+
serviceRespawned: false,
|
|
33462
|
+
serviceHealthy: false,
|
|
33452
33463
|
failedStep: "respawn",
|
|
33453
33464
|
reason: e instanceof Error ? e.message : String(e)
|
|
33454
33465
|
};
|
|
@@ -33465,53 +33476,53 @@ async function rollbackRestart(slockHome, currentBinaryDir, deps = {}) {
|
|
|
33465
33476
|
if (!healthy) {
|
|
33466
33477
|
return {
|
|
33467
33478
|
binaryRestored: true,
|
|
33468
|
-
|
|
33469
|
-
|
|
33470
|
-
|
|
33479
|
+
serviceStopped: true,
|
|
33480
|
+
serviceRespawned: true,
|
|
33481
|
+
serviceHealthy: false,
|
|
33471
33482
|
failedStep: "health",
|
|
33472
|
-
reason: "old
|
|
33483
|
+
reason: "old service failed health check after rollback respawn"
|
|
33473
33484
|
};
|
|
33474
33485
|
}
|
|
33475
33486
|
return {
|
|
33476
33487
|
binaryRestored: true,
|
|
33477
|
-
|
|
33478
|
-
|
|
33479
|
-
|
|
33488
|
+
serviceStopped: true,
|
|
33489
|
+
serviceRespawned: true,
|
|
33490
|
+
serviceHealthy: true
|
|
33480
33491
|
};
|
|
33481
33492
|
}
|
|
33482
33493
|
async function restartPhase(slockHome, deps = {}) {
|
|
33483
|
-
const
|
|
33484
|
-
const
|
|
33485
|
-
const
|
|
33494
|
+
const readServicePid = deps.readServicePid ?? (() => defaultReadServicePid(slockHome));
|
|
33495
|
+
const killService = deps.killService ?? defaultKillService;
|
|
33496
|
+
const forceKillService = deps.forceKillService ?? defaultForceKillService;
|
|
33486
33497
|
const waitForExit = deps.waitForExit ?? defaultWaitForExit;
|
|
33487
|
-
const
|
|
33498
|
+
const spawnFreshService = deps.spawnFreshService;
|
|
33488
33499
|
const healthCheck = deps.healthCheck ?? (() => defaultHealthCheck(slockHome));
|
|
33489
33500
|
const healthTimeoutMs = deps.healthTimeoutMs ?? 3e4;
|
|
33490
33501
|
const healthPollIntervalMs = deps.healthPollIntervalMs ?? 500;
|
|
33491
33502
|
const forceKill = deps.forceKill === true;
|
|
33492
|
-
const oldPid = await
|
|
33503
|
+
const oldPid = await readServicePid();
|
|
33493
33504
|
if (oldPid !== null) {
|
|
33494
33505
|
try {
|
|
33495
33506
|
if (forceKill) {
|
|
33496
|
-
await
|
|
33507
|
+
await forceKillService(oldPid);
|
|
33497
33508
|
} else {
|
|
33498
|
-
await
|
|
33509
|
+
await killService(oldPid);
|
|
33499
33510
|
const exited = await waitForExit(oldPid, 1e4);
|
|
33500
33511
|
if (!exited) {
|
|
33501
|
-
await
|
|
33512
|
+
await forceKillService(oldPid);
|
|
33502
33513
|
const escalatedExit = await waitForExit(oldPid, 5e3);
|
|
33503
33514
|
if (!escalatedExit) {
|
|
33504
|
-
return { ok: false, reason: "
|
|
33515
|
+
return { ok: false, reason: "service_kill_failed" };
|
|
33505
33516
|
}
|
|
33506
33517
|
}
|
|
33507
33518
|
}
|
|
33508
33519
|
} catch {
|
|
33509
|
-
return { ok: false, reason: "
|
|
33520
|
+
return { ok: false, reason: "service_kill_failed" };
|
|
33510
33521
|
}
|
|
33511
33522
|
}
|
|
33512
|
-
if (
|
|
33523
|
+
if (spawnFreshService) {
|
|
33513
33524
|
try {
|
|
33514
|
-
await
|
|
33525
|
+
await spawnFreshService();
|
|
33515
33526
|
} catch {
|
|
33516
33527
|
return { ok: false, reason: "spawn_failed" };
|
|
33517
33528
|
}
|
|
@@ -33525,16 +33536,16 @@ async function restartPhase(slockHome, deps = {}) {
|
|
|
33525
33536
|
}
|
|
33526
33537
|
return { ok: false, reason: "health_check_timeout" };
|
|
33527
33538
|
}
|
|
33528
|
-
async function
|
|
33539
|
+
async function defaultReadServicePid(slockHome) {
|
|
33529
33540
|
try {
|
|
33530
|
-
const raw = (await readFile14(
|
|
33541
|
+
const raw = (await readFile14(servicePidPath(slockHome), "utf8")).trim();
|
|
33531
33542
|
const pid = Number.parseInt(raw, 10);
|
|
33532
33543
|
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
33533
33544
|
} catch {
|
|
33534
33545
|
return null;
|
|
33535
33546
|
}
|
|
33536
33547
|
}
|
|
33537
|
-
async function
|
|
33548
|
+
async function defaultKillService(pid) {
|
|
33538
33549
|
try {
|
|
33539
33550
|
process.kill(pid, "SIGTERM");
|
|
33540
33551
|
} catch (err) {
|
|
@@ -33542,7 +33553,7 @@ async function defaultKillSupervisor(pid) {
|
|
|
33542
33553
|
throw err;
|
|
33543
33554
|
}
|
|
33544
33555
|
}
|
|
33545
|
-
async function
|
|
33556
|
+
async function defaultForceKillService(pid) {
|
|
33546
33557
|
try {
|
|
33547
33558
|
process.kill(pid, "SIGKILL");
|
|
33548
33559
|
} catch (err) {
|
|
@@ -33566,7 +33577,7 @@ async function defaultWaitForExit(pid, timeoutMs) {
|
|
|
33566
33577
|
return false;
|
|
33567
33578
|
}
|
|
33568
33579
|
async function defaultHealthCheck(slockHome) {
|
|
33569
|
-
const pid = await
|
|
33580
|
+
const pid = await defaultReadServicePid(slockHome);
|
|
33570
33581
|
if (pid === null) return false;
|
|
33571
33582
|
try {
|
|
33572
33583
|
process.kill(pid, 0);
|
|
@@ -33742,11 +33753,11 @@ async function runUpgrade(slockHome, opts) {
|
|
|
33742
33753
|
};
|
|
33743
33754
|
}
|
|
33744
33755
|
const restart = await restartPhase(slockHome, {
|
|
33745
|
-
|
|
33746
|
-
|
|
33747
|
-
|
|
33756
|
+
readServicePid: deps.readServicePid,
|
|
33757
|
+
killService: deps.killService,
|
|
33758
|
+
forceKillService: deps.forceKillService,
|
|
33748
33759
|
waitForExit: deps.waitForExit,
|
|
33749
|
-
|
|
33760
|
+
spawnFreshService: deps.spawnFreshService,
|
|
33750
33761
|
healthCheck: deps.healthCheck,
|
|
33751
33762
|
healthTimeoutMs: deps.healthTimeoutMs,
|
|
33752
33763
|
healthPollIntervalMs: deps.healthPollIntervalMs,
|
|
@@ -33754,12 +33765,12 @@ async function runUpgrade(slockHome, opts) {
|
|
|
33754
33765
|
});
|
|
33755
33766
|
if (!restart.ok) {
|
|
33756
33767
|
const rb = await rollbackRestart(slockHome, opts.currentBinaryDir, {
|
|
33757
|
-
|
|
33768
|
+
readServicePid: deps.readServicePid,
|
|
33758
33769
|
isProcessAlive: deps.isProcessAlive,
|
|
33759
|
-
|
|
33760
|
-
|
|
33770
|
+
killService: deps.killService,
|
|
33771
|
+
forceKillService: deps.forceKillService,
|
|
33761
33772
|
waitForExit: deps.waitForExit,
|
|
33762
|
-
|
|
33773
|
+
spawnFreshService: deps.spawnFreshService,
|
|
33763
33774
|
healthCheck: deps.healthCheck,
|
|
33764
33775
|
healthTimeoutMs: deps.healthTimeoutMs,
|
|
33765
33776
|
healthPollIntervalMs: deps.healthPollIntervalMs,
|
|
@@ -33774,7 +33785,7 @@ async function runUpgrade(slockHome, opts) {
|
|
|
33774
33785
|
verify,
|
|
33775
33786
|
swap,
|
|
33776
33787
|
restart,
|
|
33777
|
-
rolledBack: rb.binaryRestored && rb.
|
|
33788
|
+
rolledBack: rb.binaryRestored && rb.serviceHealthy,
|
|
33778
33789
|
rollback: rb
|
|
33779
33790
|
};
|
|
33780
33791
|
}
|
|
@@ -33787,12 +33798,12 @@ async function runUpgrade(slockHome, opts) {
|
|
|
33787
33798
|
});
|
|
33788
33799
|
if (!rolling.ok) {
|
|
33789
33800
|
const rb = await rollbackRestart(slockHome, opts.currentBinaryDir, {
|
|
33790
|
-
|
|
33801
|
+
readServicePid: deps.readServicePid,
|
|
33791
33802
|
isProcessAlive: deps.isProcessAlive,
|
|
33792
|
-
|
|
33793
|
-
|
|
33803
|
+
killService: deps.killService,
|
|
33804
|
+
forceKillService: deps.forceKillService,
|
|
33794
33805
|
waitForExit: deps.waitForExit,
|
|
33795
|
-
|
|
33806
|
+
spawnFreshService: deps.spawnFreshService,
|
|
33796
33807
|
healthCheck: deps.healthCheck,
|
|
33797
33808
|
healthTimeoutMs: deps.healthTimeoutMs,
|
|
33798
33809
|
healthPollIntervalMs: deps.healthPollIntervalMs,
|
|
@@ -33809,7 +33820,7 @@ async function runUpgrade(slockHome, opts) {
|
|
|
33809
33820
|
swap,
|
|
33810
33821
|
restart,
|
|
33811
33822
|
rolling,
|
|
33812
|
-
rolledBack: rb.binaryRestored && rb.
|
|
33823
|
+
rolledBack: rb.binaryRestored && rb.serviceHealthy,
|
|
33813
33824
|
rollback: rb
|
|
33814
33825
|
};
|
|
33815
33826
|
}
|
|
@@ -33956,8 +33967,8 @@ async function readBundledDaemonVersion(binaryDir) {
|
|
|
33956
33967
|
return null;
|
|
33957
33968
|
}
|
|
33958
33969
|
}
|
|
33959
|
-
async function
|
|
33960
|
-
await
|
|
33970
|
+
async function defaultSpawnFreshService(slockHome) {
|
|
33971
|
+
await spawnDetachedService(slockHome);
|
|
33961
33972
|
}
|
|
33962
33973
|
async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
33963
33974
|
let channel2;
|
|
@@ -34057,7 +34068,7 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
|
34057
34068
|
info(`Drain mode: ${drainMode}${drainMode === "force" ? " (in-flight turns will be dropped)" : ""}.`);
|
|
34058
34069
|
}
|
|
34059
34070
|
const runUpgradeFn = deps.runUpgradeFn ?? runUpgrade;
|
|
34060
|
-
const
|
|
34071
|
+
const spawnFreshService = deps.spawnFreshService ?? defaultSpawnFreshService;
|
|
34061
34072
|
const outcome = await runUpgradeFn(slockHome, {
|
|
34062
34073
|
targetVersion,
|
|
34063
34074
|
fromVersion,
|
|
@@ -34065,12 +34076,12 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
|
34065
34076
|
currentBinaryDir,
|
|
34066
34077
|
drainMode,
|
|
34067
34078
|
deps: {
|
|
34068
|
-
// Wire the production
|
|
34079
|
+
// Wire the production service-spawn into BOTH phase 5 (happy)
|
|
34069
34080
|
// and the operational-rollback respawn path inside `runUpgrade`.
|
|
34070
34081
|
// Without this, phase 5 falls through to a no-spawn health-poll
|
|
34071
34082
|
// and rollback later trips `failedStep="respawn"`. See Dayu
|
|
34072
34083
|
// blocker (#wg-slock-computer:b43b36fb msg=911eb84e).
|
|
34073
|
-
|
|
34084
|
+
spawnFreshService: () => spawnFreshService(slockHome)
|
|
34074
34085
|
}
|
|
34075
34086
|
});
|
|
34076
34087
|
const readBundledFn = deps.readBundledDaemonVersion ?? readBundledDaemonVersion;
|
|
@@ -34100,7 +34111,7 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
|
|
|
34100
34111
|
}
|
|
34101
34112
|
if (outcome.phase === "cleanup") {
|
|
34102
34113
|
info(
|
|
34103
|
-
`Upgrade ${fromVersion} \u2192 ${targetVersion} succeeded; cleanup phase reported a non-fatal issue: ${outcome.reason ?? "unknown"}. Active layout +
|
|
34114
|
+
`Upgrade ${fromVersion} \u2192 ${targetVersion} succeeded; cleanup phase reported a non-fatal issue: ${outcome.reason ?? "unknown"}. Active layout + service are healthy.`
|
|
34104
34115
|
);
|
|
34105
34116
|
await appendUpgradeLogEntry(slockHome, {
|
|
34106
34117
|
fromBundle: bundle(fromVersion),
|
|
@@ -34273,8 +34284,8 @@ function buildSimulatedDeps(slockHome, opts) {
|
|
|
34273
34284
|
fsRename: opts.simulateFail === "swap" ? async () => {
|
|
34274
34285
|
throw new Error("simulated swap failure: fsRename");
|
|
34275
34286
|
} : void 0,
|
|
34276
|
-
|
|
34277
|
-
|
|
34287
|
+
readServicePid: async () => null,
|
|
34288
|
+
spawnFreshService: async () => {
|
|
34278
34289
|
await maybeSleep();
|
|
34279
34290
|
spawnCalls += 1;
|
|
34280
34291
|
if (opts.simulateFail === "restart" && spawnCalls === 1) {
|
|
@@ -34366,7 +34377,7 @@ async function captureStateSnapshot(slockHome, version, currentBinaryDir) {
|
|
|
34366
34377
|
upgradeSnapshot: await pathInfo(upgradeSnapshotPath(slockHome)),
|
|
34367
34378
|
stagingDir: stagingExists,
|
|
34368
34379
|
stagingEntries,
|
|
34369
|
-
|
|
34380
|
+
servicePid: await pathInfo(servicePidPath(slockHome)),
|
|
34370
34381
|
channelFile: await pathInfo(join8(computerDir(slockHome), "channel")),
|
|
34371
34382
|
computerDir: await pathInfo(computerDir(slockHome)),
|
|
34372
34383
|
servers,
|
|
@@ -34445,8 +34456,8 @@ async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
|
34445
34456
|
const currentBinaryDir = opts.currentBinaryDir ?? (deps.currentBinaryDir ?? defaultCurrentBinaryDirLocal)();
|
|
34446
34457
|
const fromVersion = opts.fromVersion ?? await (deps.currentVersion ?? defaultCurrentVersionLocal)();
|
|
34447
34458
|
const channel2 = opts.channel ?? "latest";
|
|
34448
|
-
const
|
|
34449
|
-
await
|
|
34459
|
+
const spawnFreshService = deps.spawnFreshService ?? (async (h) => {
|
|
34460
|
+
await spawnDetachedService(h);
|
|
34450
34461
|
});
|
|
34451
34462
|
await mkdir16(slockHome, { recursive: true });
|
|
34452
34463
|
const outcome = await runUpgrade(slockHome, {
|
|
@@ -34474,7 +34485,7 @@ async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
|
34474
34485
|
// dependencies from the registry; this smoke isolates the swap /
|
|
34475
34486
|
// restart mechanics and keeps dependency hydration out of scope.
|
|
34476
34487
|
npmInstall: async () => ({ exitCode: 0, stderr: "" }),
|
|
34477
|
-
|
|
34488
|
+
spawnFreshService: () => spawnFreshService(slockHome),
|
|
34478
34489
|
// PR-E 18/n: the workspace-built tarball still carries
|
|
34479
34490
|
// `workspace:*` (or `file:` after pack-rewrite in some workflows)
|
|
34480
34491
|
// for `@slock-ai/daemon`, which production preflight rejects as
|
|
@@ -34485,7 +34496,7 @@ async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
|
34485
34496
|
preflight: { allowUnsafeSpec: true }
|
|
34486
34497
|
}
|
|
34487
34498
|
});
|
|
34488
|
-
const activeVersion = await
|
|
34499
|
+
const activeVersion = await readServiceVersionEvidence(slockHome);
|
|
34489
34500
|
return { outcome, activeVersion };
|
|
34490
34501
|
}
|
|
34491
34502
|
async function runUpgradeInstallSmokeCli(slockHome, opts, writer = (s) => process.stdout.write(s)) {
|
|
@@ -34556,12 +34567,12 @@ program2.name("slock-computer").description("Slock Computer \u2014 local-machine
|
|
|
34556
34567
|
program2.command("login").description("Log in via device-code (one user identity per Computer / SLOCK_HOME).").option("--server-url <url>", `Slock API base URL; defaults to SLOCK_SERVER_URL or ${DEFAULT_SLOCK_SERVER_URL}`).action(withCliExit(async (opts) => {
|
|
34557
34568
|
await runLogin({ serverUrl: opts.serverUrl });
|
|
34558
34569
|
}));
|
|
34559
|
-
program2.command("attach").argument("<serverSlug>", "target Slock server slug (canonical form `/myserver`; bare `myserver` accepted)").description("Attach this Computer to one Slock server (add-not-replace; multi-server OK).").option("--server-url <url>", `Slock API base URL; defaults to the saved user session, SLOCK_SERVER_URL, or ${DEFAULT_SLOCK_SERVER_URL}`).option("--name <name>", "Computer display name; defaults to a sanitized hostname").option("--no-run", "only authorize + write local state; do not start the
|
|
34570
|
+
program2.command("attach").argument("<serverSlug>", "target Slock server slug (canonical form `/myserver`; bare `myserver` accepted)").description("Attach this Computer to one Slock server (add-not-replace; multi-server OK).").option("--server-url <url>", `Slock API base URL; defaults to the saved user session, SLOCK_SERVER_URL, or ${DEFAULT_SLOCK_SERVER_URL}`).option("--name <name>", "Computer display name; defaults to a sanitized hostname").option("--no-run", "only authorize + write local state; do not start the service").option("--foreground", "run the service in this terminal instead of the background").action(withCliExit(async (serverSlug, opts) => {
|
|
34560
34571
|
await withMutationLock(
|
|
34561
34572
|
() => runAttach({ serverSlug, serverUrl: opts.serverUrl, name: opts.name, run: opts.run, foreground: opts.foreground })
|
|
34562
34573
|
);
|
|
34563
34574
|
}));
|
|
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
|
|
34575
|
+
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 service").option("--foreground", "run the service in this terminal instead of the background").option("-y, --yes", "allow non-interactive setup after confirming the planned actions").action(
|
|
34565
34576
|
withCliExit(async (serverSlug, opts) => {
|
|
34566
34577
|
await withMutationLock(
|
|
34567
34578
|
() => runSetup({
|
|
@@ -34578,10 +34589,10 @@ program2.command("setup").argument("<serverSlug>", "target Slock server slug (ca
|
|
|
34578
34589
|
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) => {
|
|
34579
34590
|
await withMutationLock(async () => runDetach(await resolveTargetServerId({ server: serverSlug }), serverSlug));
|
|
34580
34591
|
}));
|
|
34581
|
-
program2.command("status").description("Show this Computer's aggregate state (login +
|
|
34592
|
+
program2.command("status").description("Show this Computer's aggregate state (login + service + per-server daemons).").option("--json", "emit the machine-readable report").action(withCliExit(async (opts) => {
|
|
34582
34593
|
await runStatus({ json: opts.json });
|
|
34583
34594
|
}));
|
|
34584
|
-
program2.command("start").argument("[serverSlug]", "optional: verify this server is attached and ensure its daemon is reconciled (default: ensure all attached)").description("Start/ensure the Computer
|
|
34595
|
+
program2.command("start").argument("[serverSlug]", "optional: verify this server is attached and ensure its daemon is reconciled (default: ensure all attached)").description("Start/ensure the Computer service (manages all per-server daemons).").option("--foreground", "stay in this terminal instead of detaching").action(withCliExit(async (serverSlug, opts) => {
|
|
34585
34596
|
await withMutationLock(
|
|
34586
34597
|
async () => runStart({
|
|
34587
34598
|
foreground: opts.foreground,
|
|
@@ -34590,10 +34601,10 @@ program2.command("start").argument("[serverSlug]", "optional: verify this server
|
|
|
34590
34601
|
})
|
|
34591
34602
|
);
|
|
34592
34603
|
}));
|
|
34593
|
-
program2.command("stop").description("Stop the Computer
|
|
34604
|
+
program2.command("stop").description("Stop the Computer service (and all managed per-server daemons).").action(withCliExit(async () => {
|
|
34594
34605
|
await withMutationLock(() => runStop());
|
|
34595
34606
|
}));
|
|
34596
|
-
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
|
|
34607
|
+
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(
|
|
34597
34608
|
withCliExit(
|
|
34598
34609
|
async (serverSlug, opts) => {
|
|
34599
34610
|
const serverId = serverSlug ? await resolveTargetServerId({ server: serverSlug }) : void 0;
|
|
@@ -34608,7 +34619,7 @@ program2.command("doctor").argument("[serverSlug]", "optional: scope detail (rec
|
|
|
34608
34619
|
}
|
|
34609
34620
|
)
|
|
34610
34621
|
);
|
|
34611
|
-
program2.command("reset").description("Clear a degraded state and resume the
|
|
34622
|
+
program2.command("reset").description("Clear a degraded state and resume the service's auto-restart loop.").option("--service", "clear the service-level crash history (cascade record)").option("--runner", "clear a runner's crash history (selected by `--server`)").option("--server <slug>", "with `--runner`, select target server slug (required when \u22652 attached)").option("--json", "emit the machine-readable result").action(
|
|
34612
34623
|
withCliExit(async (opts) => {
|
|
34613
34624
|
await withMutationLock(
|
|
34614
34625
|
() => runReset({
|
|
@@ -34620,8 +34631,8 @@ program2.command("reset").description("Clear a degraded state and resume the sup
|
|
|
34620
34631
|
);
|
|
34621
34632
|
})
|
|
34622
34633
|
);
|
|
34623
|
-
program2.command("logs").description("Tail one server's daemon log (or the
|
|
34624
|
-
await runLogs({ lines: opts.lines, server: opts.server ?? null,
|
|
34634
|
+
program2.command("logs").description("Tail one server's daemon 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 daemon log").action(withCliExit(async (opts) => {
|
|
34635
|
+
await runLogs({ lines: opts.lines, server: opts.server ?? null, service: !!opts.service });
|
|
34625
34636
|
}));
|
|
34626
34637
|
var runners = program2.command("runners").description("Computer runner control plane (per-server scoped; \xA712 whitelist server-side).");
|
|
34627
34638
|
runners.command("list").description("List runners on one attached server.").option("--json", "emit the machine-readable list").option("--server <slug>", "select target server slug (required when \u22652 attached)").action(withCliExit(async (opts) => {
|
|
@@ -34701,8 +34712,8 @@ program2.command("upgrade").description(
|
|
|
34701
34712
|
}
|
|
34702
34713
|
)
|
|
34703
34714
|
);
|
|
34704
|
-
program2.command("
|
|
34705
|
-
await
|
|
34715
|
+
program2.command("__service", { hidden: true }).action(withCliExit(async () => {
|
|
34716
|
+
await runService();
|
|
34706
34717
|
}));
|
|
34707
34718
|
program2.command("__run", { hidden: true }).argument("<serverId>", "server id this daemon child is bound to").action(withCliExit(async (serverId) => {
|
|
34708
34719
|
await runResident(serverId);
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ interface ComputerStatusReport {
|
|
|
22
22
|
userId: string | null;
|
|
23
23
|
loginServerUrl: string | null;
|
|
24
24
|
userSessionError: string | null;
|
|
25
|
-
|
|
25
|
+
service: DaemonState & {
|
|
26
26
|
logPath: string;
|
|
27
27
|
};
|
|
28
28
|
servers: ServerStatusRow[];
|
|
@@ -45,13 +45,13 @@ interface RunnerListItem {
|
|
|
45
45
|
* budget near breach, see §1/§2)
|
|
46
46
|
* crashed — observed exit / fatal signal
|
|
47
47
|
* stopped — intentional stop (operator-driven via `runners stop` or
|
|
48
|
-
*
|
|
48
|
+
* service shutdown)
|
|
49
49
|
*/
|
|
50
50
|
declare const RUNNER_STATE_VALUES: readonly ["starting", "running", "degraded", "crashed", "stopped"];
|
|
51
51
|
type RunnerState = (typeof RUNNER_STATE_VALUES)[number];
|
|
52
52
|
declare function isRunnerState(value: unknown): value is RunnerState;
|
|
53
53
|
/**
|
|
54
|
-
* Service (
|
|
54
|
+
* Service (service) lifecycle states (§3.2). Mirrors runner shape but
|
|
55
55
|
* narrower — the service is a singleton per install root.
|
|
56
56
|
*
|
|
57
57
|
* starting — pidfile written, socket not yet listening
|
|
@@ -465,7 +465,7 @@ declare function readServiceStatus(installRoot: string): Promise<ServiceStatusRe
|
|
|
465
465
|
* Read a single attached server's daemon state row plus the runners
|
|
466
466
|
* currently running on it. Throws `StateReaderError("NOT_ATTACHED")` if
|
|
467
467
|
* `serverId` is not in the attached set, or `"INVALID_ATTACHMENT"` if
|
|
468
|
-
* the
|
|
468
|
+
* the runner.state.json under that id is unreadable.
|
|
469
469
|
*/
|
|
470
470
|
declare function readRunnerStatus(installRoot: string, serverId: string): Promise<RunnerStatusResult>;
|
|
471
471
|
/**
|
package/dist/lib/index.js
CHANGED
|
@@ -126,7 +126,7 @@ function serverDir(slockHome, serverId) {
|
|
|
126
126
|
return path.join(serversDir(slockHome), assertValidServerId(serverId));
|
|
127
127
|
}
|
|
128
128
|
function serverAttachmentPath(slockHome, serverId) {
|
|
129
|
-
return path.join(serverDir(slockHome, serverId), "
|
|
129
|
+
return path.join(serverDir(slockHome, serverId), "runner.state.json");
|
|
130
130
|
}
|
|
131
131
|
function serverDaemonPidPath(slockHome, serverId) {
|
|
132
132
|
return path.join(serverDir(slockHome, serverId), "daemon.pid");
|
|
@@ -137,11 +137,11 @@ function serverDaemonLogPath(slockHome, serverId) {
|
|
|
137
137
|
function serverHealthPath(slockHome, serverId) {
|
|
138
138
|
return path.join(serverDir(slockHome, serverId), "health.json");
|
|
139
139
|
}
|
|
140
|
-
function
|
|
141
|
-
return path.join(computerDir(slockHome), "
|
|
140
|
+
function servicePidPath(slockHome) {
|
|
141
|
+
return path.join(computerDir(slockHome), "service.pid");
|
|
142
142
|
}
|
|
143
|
-
function
|
|
144
|
-
return path.join(computerDir(slockHome), "
|
|
143
|
+
function serviceLogPath(slockHome) {
|
|
144
|
+
return path.join(computerDir(slockHome), "service.log");
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// src/serverState.ts
|
|
@@ -283,9 +283,9 @@ async function buildStatusReport(installRoot) {
|
|
|
283
283
|
const sessionRead = await readUserSession(userSessionPath(installRoot));
|
|
284
284
|
const session = sessionRead.session;
|
|
285
285
|
const attachments = await listServerAttachments(installRoot);
|
|
286
|
-
const
|
|
287
|
-
...await pidStatus(
|
|
288
|
-
logPath:
|
|
286
|
+
const service = {
|
|
287
|
+
...await pidStatus(servicePidPath(installRoot)),
|
|
288
|
+
logPath: serviceLogPath(installRoot)
|
|
289
289
|
};
|
|
290
290
|
const servers = [];
|
|
291
291
|
for (const a of attachments) {
|
|
@@ -308,7 +308,7 @@ async function buildStatusReport(installRoot) {
|
|
|
308
308
|
userId: session ? str(session.userId) : null,
|
|
309
309
|
loginServerUrl: session ? str(session.serverUrl) : null,
|
|
310
310
|
userSessionError: sessionRead.state === "invalid" ? sessionRead.error : null,
|
|
311
|
-
|
|
311
|
+
service,
|
|
312
312
|
servers
|
|
313
313
|
};
|
|
314
314
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slock-ai/computer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16-alpha.0",
|
|
4
4
|
"description": "Slock Computer — standalone human/local-machine control-plane CLI (login + attach). Distinct from the agent-facing @slock-ai/cli.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"commander": "^12.1.0",
|
|
29
29
|
"proper-lockfile": "^4.1.2",
|
|
30
30
|
"undici": "^7.24.7",
|
|
31
|
-
"@slock-ai/daemon": "0.55.
|
|
31
|
+
"@slock-ai/daemon": "0.55.2-alpha.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^25.5.0",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"build": "pnpm run build:deps && tsup",
|
|
45
45
|
"test": "node --import tsx --test --test-force-exit 'src/**/*.test.ts'",
|
|
46
46
|
"typecheck": "tsc --noEmit",
|
|
47
|
-
"lint:boundaries": "node scripts/check-boundaries.mjs"
|
|
47
|
+
"lint:boundaries": "node scripts/check-boundaries.mjs",
|
|
48
|
+
"lint:naming": "node scripts/check-naming.mjs"
|
|
48
49
|
}
|
|
49
50
|
}
|