@slock-ai/computer 0.0.15 → 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 +291 -221
- package/dist/lib/index.d.ts +5 -5
- package/dist/lib/index.js +69 -14
- package/package.json +3 -2
package/dist/lib/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ interface ServerStatusRow {
|
|
|
11
11
|
serverMachineId: string;
|
|
12
12
|
serverUrl: string;
|
|
13
13
|
attachedAt: string | null;
|
|
14
|
-
|
|
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;
|
|
@@ -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,22 +126,38 @@ 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
|
-
function
|
|
132
|
-
return path.join(serverDir(slockHome, serverId), "
|
|
131
|
+
function serverRunnerPidPath(slockHome, serverId) {
|
|
132
|
+
return path.join(serverDir(slockHome, serverId), "server-runner.pid");
|
|
133
133
|
}
|
|
134
|
-
function
|
|
135
|
-
return path.join(serverDir(slockHome, serverId), "
|
|
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
|
|
140
|
+
function serviceRunDir(slockHome) {
|
|
141
|
+
return path.join(computerDir(slockHome), "run");
|
|
142
|
+
}
|
|
143
|
+
function servicePidPath(slockHome) {
|
|
144
|
+
return path.join(serviceRunDir(slockHome), "service.pid");
|
|
145
|
+
}
|
|
146
|
+
function legacyServicePidPath(slockHome) {
|
|
147
|
+
return path.join(computerDir(slockHome), "service.pid");
|
|
148
|
+
}
|
|
149
|
+
function legacySupervisorPidPath(slockHome) {
|
|
141
150
|
return path.join(computerDir(slockHome), "supervisor.pid");
|
|
142
151
|
}
|
|
143
|
-
function
|
|
144
|
-
return
|
|
152
|
+
function servicePidReadFallback(slockHome) {
|
|
153
|
+
return [
|
|
154
|
+
servicePidPath(slockHome),
|
|
155
|
+
legacyServicePidPath(slockHome),
|
|
156
|
+
legacySupervisorPidPath(slockHome)
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
function serviceLogPath(slockHome) {
|
|
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";
|
|
@@ -283,20 +338,20 @@ async function buildStatusReport(installRoot) {
|
|
|
283
338
|
const sessionRead = await readUserSession(userSessionPath(installRoot));
|
|
284
339
|
const session = sessionRead.session;
|
|
285
340
|
const attachments = await listServerAttachments(installRoot);
|
|
286
|
-
const
|
|
287
|
-
...await
|
|
288
|
-
logPath:
|
|
341
|
+
const service = {
|
|
342
|
+
...await serviceState(installRoot),
|
|
343
|
+
logPath: serviceLogPath(installRoot)
|
|
289
344
|
};
|
|
290
345
|
const servers = [];
|
|
291
346
|
for (const a of attachments) {
|
|
292
|
-
const daemon = await pidStatus(
|
|
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
|
-
|
|
354
|
+
serverRunnerLogPath: serverRunnerLogPath(installRoot, a.serverId),
|
|
300
355
|
daemon,
|
|
301
356
|
health: await deriveHealth(installRoot, a.serverId, daemon)
|
|
302
357
|
});
|
|
@@ -308,7 +363,7 @@ async function buildStatusReport(installRoot) {
|
|
|
308
363
|
userId: session ? str(session.userId) : null,
|
|
309
364
|
loginServerUrl: session ? str(session.serverUrl) : null,
|
|
310
365
|
userSessionError: sessionRead.state === "invalid" ? sessionRead.error : null,
|
|
311
|
-
|
|
366
|
+
service,
|
|
312
367
|
servers
|
|
313
368
|
};
|
|
314
369
|
}
|
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",
|
|
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": {
|
|
@@ -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
|
}
|