@slock-ai/computer 0.0.16-alpha.0 → 0.0.16

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 CHANGED
@@ -29879,11 +29879,11 @@ function serverDir(slockHome, serverId) {
29879
29879
  function serverAttachmentPath(slockHome, serverId) {
29880
29880
  return path2.join(serverDir(slockHome, serverId), "runner.state.json");
29881
29881
  }
29882
- function serverDaemonPidPath(slockHome, serverId) {
29883
- return path2.join(serverDir(slockHome, serverId), "daemon.pid");
29882
+ function serverRunnerPidPath(slockHome, serverId) {
29883
+ return path2.join(serverDir(slockHome, serverId), "server-runner.pid");
29884
29884
  }
29885
- function serverDaemonLogPath(slockHome, serverId) {
29886
- return path2.join(serverDir(slockHome, serverId), "daemon.log");
29885
+ function serverRunnerLogPath(slockHome, serverId) {
29886
+ return path2.join(serverDir(slockHome, serverId), "server-runner.log");
29887
29887
  }
29888
29888
  function serverManagedFlagPath(slockHome, serverId) {
29889
29889
  return path2.join(serverDir(slockHome, serverId), "managed.flag");
@@ -29891,17 +29891,30 @@ function serverManagedFlagPath(slockHome, serverId) {
29891
29891
  function serverHealthPath(slockHome, serverId) {
29892
29892
  return path2.join(serverDir(slockHome, serverId), "health.json");
29893
29893
  }
29894
+ function serviceRunDir(slockHome) {
29895
+ return path2.join(computerDir(slockHome), "run");
29896
+ }
29894
29897
  function serviceStatePath(slockHome) {
29895
- return path2.join(computerDir(slockHome), "service.state.json");
29898
+ return path2.join(serviceRunDir(slockHome), "service.state.json");
29896
29899
  }
29897
29900
  function servicePidPath(slockHome) {
29901
+ return path2.join(serviceRunDir(slockHome), "service.pid");
29902
+ }
29903
+ function legacyServicePidPath(slockHome) {
29898
29904
  return path2.join(computerDir(slockHome), "service.pid");
29899
29905
  }
29900
29906
  function legacySupervisorPidPath(slockHome) {
29901
29907
  return path2.join(computerDir(slockHome), "supervisor.pid");
29902
29908
  }
29909
+ function servicePidReadFallback(slockHome) {
29910
+ return [
29911
+ servicePidPath(slockHome),
29912
+ legacyServicePidPath(slockHome),
29913
+ legacySupervisorPidPath(slockHome)
29914
+ ];
29915
+ }
29903
29916
  function serviceLogPath(slockHome) {
29904
- return path2.join(computerDir(slockHome), "service.log");
29917
+ return path2.join(serviceRunDir(slockHome), "service.log");
29905
29918
  }
29906
29919
  function serviceVersionPath(slockHome) {
29907
29920
  return path2.join(computerDir(slockHome), "service-version.json");
@@ -30877,7 +30890,7 @@ async function cleanupAllStalePidfiles(slockHome) {
30877
30890
  }
30878
30891
  const attached = await listAttachedServerIds(slockHome);
30879
30892
  for (const sid of attached) {
30880
- const p = serverDaemonPidPath(slockHome, sid);
30893
+ const p = serverRunnerPidPath(slockHome, sid);
30881
30894
  if (await cleanupStalePidfile(p)) cleaned.push(p);
30882
30895
  }
30883
30896
  return cleaned;
@@ -30925,7 +30938,7 @@ async function cleanupOrphanProcesses(slockHome, psSpawn) {
30925
30938
  const supPid = await readPidfileAt(servicePidPath(slockHome));
30926
30939
  if (supPid !== null) knownPids.add(supPid);
30927
30940
  for (const sid of managed) {
30928
- const pid = await readPidfileAt(serverDaemonPidPath(slockHome, sid));
30941
+ const pid = await readPidfileAt(serverRunnerPidPath(slockHome, sid));
30929
30942
  if (pid !== null) knownPids.add(pid);
30930
30943
  }
30931
30944
  if (supPid === null) return signaled;
@@ -31168,6 +31181,50 @@ async function emitRunnerStateTransition(slockHome, serverId, fromState, toState
31168
31181
 
31169
31182
  // src/services/start.ts
31170
31183
  init_esm_shims();
31184
+
31185
+ // src/internal/service-pid-fallback.ts
31186
+ init_esm_shims();
31187
+ async function findLiveServicePid(slockHome, deps = {}) {
31188
+ const readPidfile = deps.readPidfile ?? readPidfileAt;
31189
+ const isAlive = deps.isProcessAlive ?? isProcessAlive2;
31190
+ const clearStale = deps.clearPidfile ?? clearPidfileAt;
31191
+ return walkFallback(slockHome, readPidfile, isAlive, clearStale);
31192
+ }
31193
+ async function findLiveServicePidReadOnly(slockHome, deps = {}) {
31194
+ const readPidfile = deps.readPidfile ?? readPidfileAt;
31195
+ const isAlive = deps.isProcessAlive ?? isProcessAlive2;
31196
+ return walkFallback(slockHome, readPidfile, isAlive, async () => void 0);
31197
+ }
31198
+ async function walkFallback(slockHome, readPidfile, isAlive, clearStale) {
31199
+ const candidates = servicePidReadFallback(slockHome);
31200
+ let firstStalePidfile = null;
31201
+ let firstStalePid = null;
31202
+ for (const candidate of candidates) {
31203
+ const candidatePid = await readPidfile(candidate);
31204
+ if (candidatePid === null) continue;
31205
+ if (isAlive(candidatePid)) {
31206
+ return {
31207
+ pid: candidatePid,
31208
+ pidfilePath: candidate,
31209
+ firstStalePidfile,
31210
+ firstStalePid
31211
+ };
31212
+ }
31213
+ await clearStale(candidate);
31214
+ if (firstStalePidfile === null) {
31215
+ firstStalePidfile = candidate;
31216
+ firstStalePid = candidatePid;
31217
+ }
31218
+ }
31219
+ return {
31220
+ pid: null,
31221
+ pidfilePath: candidates[0],
31222
+ firstStalePidfile,
31223
+ firstStalePid
31224
+ };
31225
+ }
31226
+
31227
+ // src/services/start.ts
31171
31228
  var START_ENSURE_TIMEOUT_MS = 15e3;
31172
31229
  var START_ENSURE_POLL_INTERVAL_MS = 100;
31173
31230
  function emit4(opts, event) {
@@ -31189,7 +31246,7 @@ async function waitForManagedDaemonPids(slockHome, serverIds, opts) {
31189
31246
  while (ready.size < serverIds.length) {
31190
31247
  for (const serverId of serverIds) {
31191
31248
  if (ready.has(serverId)) continue;
31192
- const pid = await readPidfile(serverDaemonPidPath(slockHome, serverId));
31249
+ const pid = await readPidfile(serverRunnerPidPath(slockHome, serverId));
31193
31250
  if (pid && isAlive(pid)) ready.set(serverId, pid);
31194
31251
  }
31195
31252
  if (ready.size === serverIds.length) return ready;
@@ -31201,8 +31258,8 @@ async function waitForManagedDaemonPids(slockHome, serverIds, opts) {
31201
31258
  }
31202
31259
  function buildTimeoutMessage(slockHome, serverIds, ready, input) {
31203
31260
  const missing = serverIds.filter((id) => !ready.has(id));
31204
- const target = input.serverId && missing.length === 1 ? `${input.serverLabel ?? input.serverId}` : `${missing.length} daemon(s): ${missing.join(", ")}`;
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.`;
31261
+ const target = input.serverId && missing.length === 1 ? `${input.serverLabel ?? input.serverId}` : `${missing.length} server runner(s): ${missing.join(", ")}`;
31262
+ 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
31263
  }
31207
31264
  async function start(input, options = {}) {
31208
31265
  options.signal?.throwIfAborted?.();
@@ -31230,8 +31287,11 @@ async function start(input, options = {}) {
31230
31287
  for (const id of managedTargets) {
31231
31288
  await setServerManaged(slockHome, id);
31232
31289
  }
31233
- const existing = await readPidfileAt(servicePidPath(slockHome));
31234
- if (existing && isProcessAlive2(existing)) {
31290
+ const { pid: existing } = await findLiveServicePid(slockHome, {
31291
+ readPidfile: options.readPidfile,
31292
+ isProcessAlive: options.isProcessAlive
31293
+ });
31294
+ if (existing !== null) {
31235
31295
  emit4(options, {
31236
31296
  type: "already_running",
31237
31297
  servicePid: existing,
@@ -31327,7 +31387,7 @@ async function pollReadyOnce(slockHome, serverIds, opts) {
31327
31387
  const isAlive = opts.isProcessAlive ?? isProcessAlive2;
31328
31388
  const ready = /* @__PURE__ */ new Map();
31329
31389
  for (const serverId of serverIds) {
31330
- const pid = await readPidfile(serverDaemonPidPath(slockHome, serverId));
31390
+ const pid = await readPidfile(serverRunnerPidPath(slockHome, serverId));
31331
31391
  if (pid && isAlive(pid)) ready.set(serverId, pid);
31332
31392
  }
31333
31393
  return ready;
@@ -31357,26 +31417,23 @@ async function stop(input = {}, options = {}) {
31357
31417
  const sleep2 = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
31358
31418
  const pollIntervalMs = options.pollIntervalMs ?? STOP_POLL_INTERVAL_MS;
31359
31419
  const timeoutMs = options.timeoutMs ?? STOP_TIMEOUT_MS;
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
- }
31420
+ const { pid, pidfilePath, firstStalePidfile, firstStalePid } = await findLiveServicePid(slockHome, {
31421
+ readPidfile,
31422
+ isProcessAlive: isAlive
31423
+ });
31370
31424
  emit5(options, { type: "stopping", pid });
31371
31425
  if (pid === null) {
31426
+ if (firstStalePidfile !== null && firstStalePid !== null) {
31427
+ emit5(options, { type: "stale_pidfile_cleared", pid: firstStalePid });
31428
+ return {
31429
+ status: "stale_pidfile_cleared",
31430
+ pid: firstStalePid,
31431
+ pidfilePath: firstStalePidfile
31432
+ };
31433
+ }
31372
31434
  emit5(options, { type: "not_running" });
31373
31435
  return { status: "not_running", pid: null, pidfilePath };
31374
31436
  }
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
31437
  options.signal?.throwIfAborted?.();
31381
31438
  try {
31382
31439
  killer(pid);
@@ -31504,8 +31561,8 @@ async function detach(input, options = {}) {
31504
31561
  await clearServerManaged(slockHome, serverId);
31505
31562
  const subtree = [
31506
31563
  serverAttachmentPath(slockHome, serverId),
31507
- serverDaemonPidPath(slockHome, serverId),
31508
- serverDaemonLogPath(slockHome, serverId)
31564
+ serverRunnerPidPath(slockHome, serverId),
31565
+ serverRunnerLogPath(slockHome, serverId)
31509
31566
  ];
31510
31567
  for (const p of subtree) await clearPidfileAt(p);
31511
31568
  emit6(options, { type: "subtree_cleared", serverId, serverLabel });
@@ -31526,7 +31583,7 @@ function buildResidentSpawn(mode, serverId, selfEntry = process.argv[1] ?? "", e
31526
31583
  }
31527
31584
  var PARENT_LOCK_HELD_ENV_VAR = "SLOCK_COMPUTER_PARENT_MUTATION_LOCK_HELD";
31528
31585
  async function spawnDetachedService(slockHome) {
31529
- await mkdir8(computerDir(slockHome), { recursive: true });
31586
+ await mkdir8(serviceRunDir(slockHome), { recursive: true });
31530
31587
  const supLogFd = await open(serviceLogPath(slockHome), "a");
31531
31588
  const { command, args } = buildResidentSpawn("__service", null);
31532
31589
  const child = spawn2(command, args, {
@@ -31703,14 +31760,14 @@ async function readServiceVersionEvidence(slockHome) {
31703
31760
  }
31704
31761
  async function runService() {
31705
31762
  const slockHome = resolveSlockHome();
31706
- await mkdir8(computerDir(slockHome), { recursive: true });
31763
+ await mkdir8(serviceRunDir(slockHome), { recursive: true });
31707
31764
  await runServiceStartupRecovery(slockHome);
31708
31765
  await writePidfileAt(servicePidPath(slockHome), process.pid);
31709
31766
  await writeServiceVersionEvidence(slockHome);
31710
31767
  const children = /* @__PURE__ */ new Map();
31711
31768
  const { [PARENT_LOCK_HELD_ENV_VAR]: _parentLockMarker, ...childEnv } = process.env;
31712
31769
  const spawnChild = async (serverId) => {
31713
- const logPath = serverDaemonLogPath(slockHome, serverId);
31770
+ const logPath = serverRunnerLogPath(slockHome, serverId);
31714
31771
  await mkdir8(dirname8(logPath), { recursive: true });
31715
31772
  const logFd = await open(logPath, "a");
31716
31773
  const { command, args } = buildResidentSpawn("__run", serverId);
@@ -31723,11 +31780,11 @@ async function runService() {
31723
31780
  if (!child.pid) return;
31724
31781
  const handle = { serverId, child, stopping: false };
31725
31782
  children.set(serverId, handle);
31726
- await writePidfileAt(serverDaemonPidPath(slockHome, serverId), child.pid);
31783
+ await writePidfileAt(serverRunnerPidPath(slockHome, serverId), child.pid);
31727
31784
  child.on("exit", (code, signal) => {
31728
31785
  void (async () => {
31729
31786
  children.delete(serverId);
31730
- await clearPidfileAt(serverDaemonPidPath(slockHome, serverId));
31787
+ await clearPidfileAt(serverRunnerPidPath(slockHome, serverId));
31731
31788
  if (handle.stopping) return;
31732
31789
  const classification = classifyRunnerExit(code, signal);
31733
31790
  if (classification === "config-error") {
@@ -31736,7 +31793,7 @@ async function runService() {
31736
31793
  } catch {
31737
31794
  }
31738
31795
  process.stderr.write(
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.
31796
+ `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
31797
  `
31741
31798
  );
31742
31799
  return;
@@ -31847,7 +31904,7 @@ async function runStart(opts = {}, deps = {}) {
31847
31904
  info(
31848
31905
  `Managing ${sb.managedCount} of ${sb.attachedCount} attached server(s). Logs: ${sb.logPath}`
31849
31906
  );
31850
- info(`Per-server daemon logs: ~/.slock/computer/servers/<serverId>/daemon.log`);
31907
+ info(`Per-server server-runner logs: ~/.slock/computer/servers/<serverId>/server-runner.log`);
31851
31908
  info(`Check state with \`slock-computer status\`.`);
31852
31909
  }
31853
31910
  }
@@ -32208,6 +32265,10 @@ async function pidStatus(pidfile) {
32208
32265
  const pid = await readPidfileAt(pidfile);
32209
32266
  return pid !== null && isProcessAlive2(pid) ? { running: true, pid } : { running: false };
32210
32267
  }
32268
+ async function serviceState(slockHome) {
32269
+ const { pid } = await findLiveServicePidReadOnly(slockHome);
32270
+ return pid !== null ? { running: true, pid } : { running: false };
32271
+ }
32211
32272
  async function deriveHealth(slockHome, serverId, daemon) {
32212
32273
  if (!daemon.running) return "offline";
32213
32274
  if (await isDegraded(slockHome, serverId)) return "degraded";
@@ -32218,19 +32279,19 @@ async function buildStatusReport(installRoot) {
32218
32279
  const session = sessionRead.session;
32219
32280
  const attachments = await listServerAttachments(installRoot);
32220
32281
  const service = {
32221
- ...await pidStatus(servicePidPath(installRoot)),
32282
+ ...await serviceState(installRoot),
32222
32283
  logPath: serviceLogPath(installRoot)
32223
32284
  };
32224
32285
  const servers = [];
32225
32286
  for (const a of attachments) {
32226
- const daemon = await pidStatus(serverDaemonPidPath(installRoot, a.serverId));
32287
+ const daemon = await pidStatus(serverRunnerPidPath(installRoot, a.serverId));
32227
32288
  servers.push({
32228
32289
  serverId: a.serverId,
32229
32290
  serverSlug: a.serverSlug ?? null,
32230
32291
  serverMachineId: a.serverMachineId,
32231
32292
  serverUrl: a.serverUrl,
32232
32293
  attachedAt: a.attachedAt ?? null,
32233
- daemonLogPath: serverDaemonLogPath(installRoot, a.serverId),
32294
+ serverRunnerLogPath: serverRunnerLogPath(installRoot, a.serverId),
32234
32295
  daemon,
32235
32296
  health: await deriveHealth(installRoot, a.serverId, daemon)
32236
32297
  });
@@ -32277,7 +32338,7 @@ async function runStatus(opts) {
32277
32338
  info(
32278
32339
  ` ${pad(formatServerSlugDisplay(s.serverSlug), 24)}${pad(s.health, 12)}${pad(dcol, 24)}${pad(s.serverMachineId, 38)}${s.serverUrl}`
32279
32340
  );
32280
- info(` Daemon log: ${s.daemonLogPath}`);
32341
+ info(` Server runner log: ${s.serverRunnerLogPath}`);
32281
32342
  }
32282
32343
  if (report.servers.some((s) => s.health === "degraded")) {
32283
32344
  info("");
@@ -32618,14 +32679,14 @@ import { readFile as readFile10 } from "fs/promises";
32618
32679
  var DEFAULT_LINES = 200;
32619
32680
  async function runLogs(opts) {
32620
32681
  const home = resolveSlockHome();
32621
- const file = opts.service ? serviceLogPath(home) : serverDaemonLogPath(home, await resolveTargetServerId({ server: opts.server }));
32682
+ const file = opts.service ? serviceLogPath(home) : serverRunnerLogPath(home, await resolveTargetServerId({ server: opts.server }));
32622
32683
  let content;
32623
32684
  try {
32624
32685
  content = await readFile10(file, "utf8");
32625
32686
  } catch {
32626
32687
  fail(
32627
32688
  "NO_DAEMON_LOG",
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\`).`
32689
+ 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
32690
  );
32630
32691
  }
32631
32692
  const n = Number.isInteger(opts.lines) && opts.lines > 0 ? opts.lines : DEFAULT_LINES;
@@ -33537,13 +33598,8 @@ async function restartPhase(slockHome, deps = {}) {
33537
33598
  return { ok: false, reason: "health_check_timeout" };
33538
33599
  }
33539
33600
  async function defaultReadServicePid(slockHome) {
33540
- try {
33541
- const raw = (await readFile14(servicePidPath(slockHome), "utf8")).trim();
33542
- const pid = Number.parseInt(raw, 10);
33543
- return Number.isInteger(pid) && pid > 0 ? pid : null;
33544
- } catch {
33545
- return null;
33546
- }
33601
+ const { pid } = await findLiveServicePid(slockHome);
33602
+ return pid;
33547
33603
  }
33548
33604
  async function defaultKillService(pid) {
33549
33605
  try {
@@ -33861,7 +33917,7 @@ async function rollingDaemonHealthCheck(slockHome, deps = {}) {
33861
33917
  }
33862
33918
  async function defaultReadDaemonPid(slockHome, serverId) {
33863
33919
  try {
33864
- const raw = (await readFile14(serverDaemonPidPath(slockHome, serverId), "utf8")).trim();
33920
+ const raw = (await readFile14(serverRunnerPidPath(slockHome, serverId), "utf8")).trim();
33865
33921
  const pid = Number.parseInt(raw, 10);
33866
33922
  return Number.isInteger(pid) && pid > 0 ? pid : null;
33867
33923
  } catch {
@@ -34067,6 +34123,8 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
34067
34123
  if (drainMode !== void 0 && drainMode !== "drain") {
34068
34124
  info(`Drain mode: ${drainMode}${drainMode === "force" ? " (in-flight turns will be dropped)" : ""}.`);
34069
34125
  }
34126
+ const readBundledFn = deps.readBundledDaemonVersion ?? readBundledDaemonVersion;
34127
+ const fromBundledDaemonVersion = await readBundledFn(currentBinaryDir);
34070
34128
  const runUpgradeFn = deps.runUpgradeFn ?? runUpgrade;
34071
34129
  const spawnFreshService = deps.spawnFreshService ?? defaultSpawnFreshService;
34072
34130
  const outcome = await runUpgradeFn(slockHome, {
@@ -34084,17 +34142,18 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
34084
34142
  spawnFreshService: () => spawnFreshService(slockHome)
34085
34143
  }
34086
34144
  });
34087
- const readBundledFn = deps.readBundledDaemonVersion ?? readBundledDaemonVersion;
34088
- const bundledDaemonVersion = await readBundledFn(currentBinaryDir);
34089
- const bundle = (version) => bundledDaemonVersion !== null ? { computerVersion: version, bundledDaemonVersion } : { computerVersion: version };
34145
+ const toBundledDaemonVersion = await readBundledFn(currentBinaryDir);
34146
+ const bundle = (version, bundledDaemonVersion) => bundledDaemonVersion !== null ? { computerVersion: version, bundledDaemonVersion } : { computerVersion: version };
34147
+ const fromBundle = bundle(fromVersion, fromBundledDaemonVersion);
34148
+ const toBundle = bundle(targetVersion, toBundledDaemonVersion);
34090
34149
  const logTrigger = opts.trigger ?? "cli";
34091
34150
  if (outcome.ok) {
34092
34151
  info(
34093
34152
  `Upgrade ${fromVersion} \u2192 ${targetVersion} succeeded (health-OK in ${outcome.restart?.healthAfterMs ?? 0}ms).`
34094
34153
  );
34095
34154
  await appendUpgradeLogEntry(slockHome, {
34096
- fromBundle: bundle(fromVersion),
34097
- toBundle: bundle(targetVersion),
34155
+ fromBundle,
34156
+ toBundle,
34098
34157
  channel: channel2,
34099
34158
  trigger: logTrigger,
34100
34159
  outcome: "ok"
@@ -34114,8 +34173,8 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
34114
34173
  `Upgrade ${fromVersion} \u2192 ${targetVersion} succeeded; cleanup phase reported a non-fatal issue: ${outcome.reason ?? "unknown"}. Active layout + service are healthy.`
34115
34174
  );
34116
34175
  await appendUpgradeLogEntry(slockHome, {
34117
- fromBundle: bundle(fromVersion),
34118
- toBundle: bundle(targetVersion),
34176
+ fromBundle,
34177
+ toBundle,
34119
34178
  channel: channel2,
34120
34179
  trigger: logTrigger,
34121
34180
  outcome: "ok"
@@ -34125,8 +34184,8 @@ async function runUpgradeCli(slockHome, opts, deps = {}) {
34125
34184
  }
34126
34185
  const code = mapFailurePhaseToCode(outcome);
34127
34186
  await appendUpgradeLogEntry(slockHome, {
34128
- fromBundle: bundle(fromVersion),
34129
- toBundle: bundle(targetVersion),
34187
+ fromBundle,
34188
+ toBundle,
34130
34189
  channel: channel2,
34131
34190
  trigger: logTrigger,
34132
34191
  outcome: "err",
@@ -34499,10 +34558,10 @@ async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
34499
34558
  const activeVersion = await readServiceVersionEvidence(slockHome);
34500
34559
  return { outcome, activeVersion };
34501
34560
  }
34502
- async function runUpgradeInstallSmokeCli(slockHome, opts, writer = (s) => process.stdout.write(s)) {
34561
+ async function runUpgradeInstallSmokeCli(slockHome, opts, writer = (s) => process.stdout.write(s), deps = {}) {
34503
34562
  let report;
34504
34563
  try {
34505
- report = await runUpgradeInstallSmoke(slockHome, opts);
34564
+ report = await runUpgradeInstallSmoke(slockHome, opts, deps);
34506
34565
  } catch (e) {
34507
34566
  const msg = e instanceof Error ? e.message : String(e);
34508
34567
  writer(
@@ -34589,10 +34648,10 @@ program2.command("setup").argument("<serverSlug>", "target Slock server slug (ca
34589
34648
  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
34649
  await withMutationLock(async () => runDetach(await resolveTargetServerId({ server: serverSlug }), serverSlug));
34591
34650
  }));
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) => {
34651
+ 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
34652
  await runStatus({ json: opts.json });
34594
34653
  }));
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) => {
34654
+ 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
34655
  await withMutationLock(
34597
34656
  async () => runStart({
34598
34657
  foreground: opts.foreground,
@@ -34601,7 +34660,7 @@ program2.command("start").argument("[serverSlug]", "optional: verify this server
34601
34660
  })
34602
34661
  );
34603
34662
  }));
34604
- program2.command("stop").description("Stop the Computer service (and all managed per-server daemons).").action(withCliExit(async () => {
34663
+ program2.command("stop").description("Stop the Computer service (and all managed per-server server-runners).").action(withCliExit(async () => {
34605
34664
  await withMutationLock(() => runStop());
34606
34665
  }));
34607
34666
  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 +34690,7 @@ program2.command("reset").description("Clear a degraded state and resume the ser
34631
34690
  );
34632
34691
  })
34633
34692
  );
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) => {
34693
+ 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
34694
  await runLogs({ lines: opts.lines, server: opts.server ?? null, service: !!opts.service });
34636
34695
  }));
34637
34696
  var runners = program2.command("runners").description("Computer runner control plane (per-server scoped; \xA712 whitelist server-side).");
@@ -11,7 +11,7 @@ interface ServerStatusRow {
11
11
  serverMachineId: string;
12
12
  serverUrl: string;
13
13
  attachedAt: string | null;
14
- daemonLogPath: string;
14
+ serverRunnerLogPath: string;
15
15
  daemon: DaemonState;
16
16
  /** v6 §11 health enum surfaced in `status` table (PR-H §3.3). */
17
17
  health: ServerHealth;
package/dist/lib/index.js CHANGED
@@ -128,20 +128,36 @@ function serverDir(slockHome, serverId) {
128
128
  function serverAttachmentPath(slockHome, serverId) {
129
129
  return path.join(serverDir(slockHome, serverId), "runner.state.json");
130
130
  }
131
- function serverDaemonPidPath(slockHome, serverId) {
132
- return path.join(serverDir(slockHome, serverId), "daemon.pid");
131
+ function serverRunnerPidPath(slockHome, serverId) {
132
+ return path.join(serverDir(slockHome, serverId), "server-runner.pid");
133
133
  }
134
- function serverDaemonLogPath(slockHome, serverId) {
135
- return path.join(serverDir(slockHome, serverId), "daemon.log");
134
+ function serverRunnerLogPath(slockHome, serverId) {
135
+ return path.join(serverDir(slockHome, serverId), "server-runner.log");
136
136
  }
137
137
  function serverHealthPath(slockHome, serverId) {
138
138
  return path.join(serverDir(slockHome, serverId), "health.json");
139
139
  }
140
+ function serviceRunDir(slockHome) {
141
+ return path.join(computerDir(slockHome), "run");
142
+ }
140
143
  function servicePidPath(slockHome) {
144
+ return path.join(serviceRunDir(slockHome), "service.pid");
145
+ }
146
+ function legacyServicePidPath(slockHome) {
141
147
  return path.join(computerDir(slockHome), "service.pid");
142
148
  }
149
+ function legacySupervisorPidPath(slockHome) {
150
+ return path.join(computerDir(slockHome), "supervisor.pid");
151
+ }
152
+ function servicePidReadFallback(slockHome) {
153
+ return [
154
+ servicePidPath(slockHome),
155
+ legacyServicePidPath(slockHome),
156
+ legacySupervisorPidPath(slockHome)
157
+ ];
158
+ }
143
159
  function serviceLogPath(slockHome) {
144
- return path.join(computerDir(slockHome), "service.log");
160
+ return path.join(serviceRunDir(slockHome), "service.log");
145
161
  }
146
162
 
147
163
  // src/serverState.ts
@@ -220,6 +236,41 @@ function isProcessAlive(pid) {
220
236
  }
221
237
  }
222
238
 
239
+ // src/internal/service-pid-fallback.ts
240
+ async function findLiveServicePidReadOnly(slockHome, deps = {}) {
241
+ const readPidfile = deps.readPidfile ?? readPidfileAt;
242
+ const isAlive = deps.isProcessAlive ?? isProcessAlive;
243
+ return walkFallback(slockHome, readPidfile, isAlive, async () => void 0);
244
+ }
245
+ async function walkFallback(slockHome, readPidfile, isAlive, clearStale) {
246
+ const candidates = servicePidReadFallback(slockHome);
247
+ let firstStalePidfile = null;
248
+ let firstStalePid = null;
249
+ for (const candidate of candidates) {
250
+ const candidatePid = await readPidfile(candidate);
251
+ if (candidatePid === null) continue;
252
+ if (isAlive(candidatePid)) {
253
+ return {
254
+ pid: candidatePid,
255
+ pidfilePath: candidate,
256
+ firstStalePidfile,
257
+ firstStalePid
258
+ };
259
+ }
260
+ await clearStale(candidate);
261
+ if (firstStalePidfile === null) {
262
+ firstStalePidfile = candidate;
263
+ firstStalePid = candidatePid;
264
+ }
265
+ }
266
+ return {
267
+ pid: null,
268
+ pidfilePath: candidates[0],
269
+ firstStalePidfile,
270
+ firstStalePid
271
+ };
272
+ }
273
+
223
274
  // src/health.ts
224
275
  import { readFile as readFile4, writeFile as writeFile3, unlink as unlink3, mkdir as mkdir3, appendFile } from "fs/promises";
225
276
  import { dirname as dirname3 } from "path";
@@ -274,6 +325,10 @@ async function pidStatus(pidfile) {
274
325
  const pid = await readPidfileAt(pidfile);
275
326
  return pid !== null && isProcessAlive(pid) ? { running: true, pid } : { running: false };
276
327
  }
328
+ async function serviceState(slockHome) {
329
+ const { pid } = await findLiveServicePidReadOnly(slockHome);
330
+ return pid !== null ? { running: true, pid } : { running: false };
331
+ }
277
332
  async function deriveHealth(slockHome, serverId, daemon) {
278
333
  if (!daemon.running) return "offline";
279
334
  if (await isDegraded(slockHome, serverId)) return "degraded";
@@ -284,19 +339,19 @@ async function buildStatusReport(installRoot) {
284
339
  const session = sessionRead.session;
285
340
  const attachments = await listServerAttachments(installRoot);
286
341
  const service = {
287
- ...await pidStatus(servicePidPath(installRoot)),
342
+ ...await serviceState(installRoot),
288
343
  logPath: serviceLogPath(installRoot)
289
344
  };
290
345
  const servers = [];
291
346
  for (const a of attachments) {
292
- const daemon = await pidStatus(serverDaemonPidPath(installRoot, a.serverId));
347
+ const daemon = await pidStatus(serverRunnerPidPath(installRoot, a.serverId));
293
348
  servers.push({
294
349
  serverId: a.serverId,
295
350
  serverSlug: a.serverSlug ?? null,
296
351
  serverMachineId: a.serverMachineId,
297
352
  serverUrl: a.serverUrl,
298
353
  attachedAt: a.attachedAt ?? null,
299
- daemonLogPath: serverDaemonLogPath(installRoot, a.serverId),
354
+ serverRunnerLogPath: serverRunnerLogPath(installRoot, a.serverId),
300
355
  daemon,
301
356
  health: await deriveHealth(installRoot, a.serverId, daemon)
302
357
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slock-ai/computer",
3
- "version": "0.0.16-alpha.0",
3
+ "version": "0.0.16",
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.2-alpha.0"
31
+ "@slock-ai/daemon": "0.55.1"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^25.5.0",