@slock-ai/computer 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +631 -366
- package/dist/lib/index.d.ts +340 -36
- package/dist/lib/index.js +407 -9
- package/package.json +2 -2
package/dist/lib/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var IPC_ERROR_CODES = [
|
|
3
3
|
"IPC_FRAME_TOO_LARGE",
|
|
4
4
|
"IPC_PROTOCOL_VERSION_UNSUPPORTED",
|
|
5
|
+
"IPC_PROTOCOL_HANDSHAKE_FAILED",
|
|
5
6
|
"IPC_HEARTBEAT_TIMEOUT",
|
|
6
7
|
"IPC_MALFORMED_FRAME",
|
|
7
8
|
"IPC_REQUEST_TIMEOUT",
|
|
@@ -21,6 +22,402 @@ var ServiceClientError = class extends Error {
|
|
|
21
22
|
if (cause !== void 0) this.cause = cause;
|
|
22
23
|
}
|
|
23
24
|
};
|
|
25
|
+
var STATE_READER_ERROR_CODES = ["NOT_ATTACHED", "INVALID_ATTACHMENT"];
|
|
26
|
+
var StateReaderError = class extends Error {
|
|
27
|
+
code;
|
|
28
|
+
constructor(code, message) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.name = "StateReaderError";
|
|
31
|
+
this.code = code;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var MIGRATION_DETECTION_KINDS = ["match", "no-match", "ambiguous"];
|
|
35
|
+
function isMigrationDetectionKind(value) {
|
|
36
|
+
return typeof value === "string" && MIGRATION_DETECTION_KINDS.includes(value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/lib/migration.ts
|
|
40
|
+
import { readdir, readFile } from "fs/promises";
|
|
41
|
+
import { join } from "path";
|
|
42
|
+
var MACHINE_DIR_PREFIX = "machine-";
|
|
43
|
+
async function readOwnerEvidence(installRoot, machineDirName) {
|
|
44
|
+
const ownerFile = join(
|
|
45
|
+
installRoot,
|
|
46
|
+
"machines",
|
|
47
|
+
machineDirName,
|
|
48
|
+
"daemon.lock",
|
|
49
|
+
"owner.json"
|
|
50
|
+
);
|
|
51
|
+
let raw;
|
|
52
|
+
try {
|
|
53
|
+
raw = await readFile(ownerFile, "utf8");
|
|
54
|
+
} catch {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = JSON.parse(raw);
|
|
60
|
+
} catch {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
const machineName = typeof parsed.hostname === "string" && parsed.hostname.length > 0 ? parsed.hostname : void 0;
|
|
64
|
+
const serverUrl = typeof parsed.serverUrl === "string" && parsed.serverUrl.length > 0 ? parsed.serverUrl : void 0;
|
|
65
|
+
return { machineName, serverUrl };
|
|
66
|
+
}
|
|
67
|
+
async function detectLegacyMigration(installRoot, loggedInUserId) {
|
|
68
|
+
void loggedInUserId;
|
|
69
|
+
const machinesDir = join(installRoot, "machines");
|
|
70
|
+
let entries;
|
|
71
|
+
try {
|
|
72
|
+
entries = await readdir(machinesDir);
|
|
73
|
+
} catch {
|
|
74
|
+
return { kind: "no-match" };
|
|
75
|
+
}
|
|
76
|
+
const candidates = [];
|
|
77
|
+
for (const name of entries) {
|
|
78
|
+
if (!name.startsWith(MACHINE_DIR_PREFIX)) continue;
|
|
79
|
+
const evidence = await readOwnerEvidence(installRoot, name);
|
|
80
|
+
candidates.push({
|
|
81
|
+
machineId: name,
|
|
82
|
+
machineName: evidence.machineName,
|
|
83
|
+
serverUrl: evidence.serverUrl
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (candidates.length === 0) return { kind: "no-match" };
|
|
87
|
+
if (candidates.length === 1) {
|
|
88
|
+
const only = candidates[0];
|
|
89
|
+
return {
|
|
90
|
+
kind: "match",
|
|
91
|
+
machineId: only.machineId,
|
|
92
|
+
machineName: only.machineName,
|
|
93
|
+
serverUrl: only.serverUrl
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return { kind: "ambiguous", candidates };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/status.ts
|
|
100
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
101
|
+
|
|
102
|
+
// src/paths.ts
|
|
103
|
+
import { createHash } from "crypto";
|
|
104
|
+
import os from "os";
|
|
105
|
+
import path from "path";
|
|
106
|
+
function computerDir(slockHome) {
|
|
107
|
+
return path.join(slockHome, "computer");
|
|
108
|
+
}
|
|
109
|
+
function userSessionPath(slockHome) {
|
|
110
|
+
return path.join(computerDir(slockHome), "user-session.json");
|
|
111
|
+
}
|
|
112
|
+
var SERVER_ID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
113
|
+
function isValidServerId(serverId) {
|
|
114
|
+
return SERVER_ID_RE.test(serverId);
|
|
115
|
+
}
|
|
116
|
+
function assertValidServerId(serverId) {
|
|
117
|
+
if (!isValidServerId(serverId)) {
|
|
118
|
+
throw new Error(`invalid server id: ${JSON.stringify(serverId)} (expected a UUID)`);
|
|
119
|
+
}
|
|
120
|
+
return serverId;
|
|
121
|
+
}
|
|
122
|
+
function serversDir(slockHome) {
|
|
123
|
+
return path.join(computerDir(slockHome), "servers");
|
|
124
|
+
}
|
|
125
|
+
function serverDir(slockHome, serverId) {
|
|
126
|
+
return path.join(serversDir(slockHome), assertValidServerId(serverId));
|
|
127
|
+
}
|
|
128
|
+
function serverAttachmentPath(slockHome, serverId) {
|
|
129
|
+
return path.join(serverDir(slockHome, serverId), "attachment.json");
|
|
130
|
+
}
|
|
131
|
+
function serverDaemonPidPath(slockHome, serverId) {
|
|
132
|
+
return path.join(serverDir(slockHome, serverId), "daemon.pid");
|
|
133
|
+
}
|
|
134
|
+
function serverDaemonLogPath(slockHome, serverId) {
|
|
135
|
+
return path.join(serverDir(slockHome, serverId), "daemon.log");
|
|
136
|
+
}
|
|
137
|
+
function serverHealthPath(slockHome, serverId) {
|
|
138
|
+
return path.join(serverDir(slockHome, serverId), "health.json");
|
|
139
|
+
}
|
|
140
|
+
function supervisorPidPath(slockHome) {
|
|
141
|
+
return path.join(computerDir(slockHome), "supervisor.pid");
|
|
142
|
+
}
|
|
143
|
+
function supervisorLogPath(slockHome) {
|
|
144
|
+
return path.join(computerDir(slockHome), "supervisor.log");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/serverState.ts
|
|
148
|
+
import { readFile as readFile2, readdir as readdir2, writeFile, mkdir, unlink, access, chmod } from "fs/promises";
|
|
149
|
+
import { dirname } from "path";
|
|
150
|
+
import { constants as fsConstants } from "fs";
|
|
151
|
+
function parseAttachment(raw) {
|
|
152
|
+
try {
|
|
153
|
+
const a = JSON.parse(raw);
|
|
154
|
+
if (a.kind === "computer-attachment" && typeof a.serverId === "string" && typeof a.serverMachineId === "string" && typeof a.apiKey === "string" && a.apiKey.length > 0 && typeof a.serverUrl === "string") {
|
|
155
|
+
return {
|
|
156
|
+
kind: "computer-attachment",
|
|
157
|
+
serverId: a.serverId,
|
|
158
|
+
serverSlug: typeof a.serverSlug === "string" && a.serverSlug.length > 0 ? a.serverSlug : void 0,
|
|
159
|
+
serverMachineId: a.serverMachineId,
|
|
160
|
+
apiKey: a.apiKey,
|
|
161
|
+
serverUrl: a.serverUrl,
|
|
162
|
+
attachedAt: typeof a.attachedAt === "string" ? a.attachedAt : void 0
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
async function readServerAttachment(slockHome, serverId) {
|
|
170
|
+
if (!isValidServerId(serverId)) return null;
|
|
171
|
+
try {
|
|
172
|
+
return parseAttachment(await readFile2(serverAttachmentPath(slockHome, serverId), "utf8"));
|
|
173
|
+
} catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function listAttachedServerIds(slockHome) {
|
|
178
|
+
let entries;
|
|
179
|
+
try {
|
|
180
|
+
entries = await readdir2(serversDir(slockHome));
|
|
181
|
+
} catch {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
const ids = [];
|
|
185
|
+
for (const name of entries) {
|
|
186
|
+
if (!isValidServerId(name)) continue;
|
|
187
|
+
if (await readServerAttachment(slockHome, name)) ids.push(name);
|
|
188
|
+
}
|
|
189
|
+
return ids.sort();
|
|
190
|
+
}
|
|
191
|
+
async function listServerAttachments(slockHome) {
|
|
192
|
+
const ids = await listAttachedServerIds(slockHome);
|
|
193
|
+
const out = [];
|
|
194
|
+
for (const id of ids) {
|
|
195
|
+
const a = await readServerAttachment(slockHome, id);
|
|
196
|
+
if (a) out.push(a);
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/internal/process-primitives.ts
|
|
202
|
+
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2, unlink as unlink2 } from "fs/promises";
|
|
203
|
+
import { dirname as dirname2 } from "path";
|
|
204
|
+
async function readPidfileAt(pidfilePath) {
|
|
205
|
+
try {
|
|
206
|
+
const raw = (await readFile3(pidfilePath, "utf8")).trim();
|
|
207
|
+
const pid = Number.parseInt(raw, 10);
|
|
208
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
209
|
+
} catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function isProcessAlive(pid) {
|
|
214
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
215
|
+
try {
|
|
216
|
+
process.kill(pid, 0);
|
|
217
|
+
return true;
|
|
218
|
+
} catch (err) {
|
|
219
|
+
return err.code === "EPERM";
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/health.ts
|
|
224
|
+
import { readFile as readFile4, writeFile as writeFile3, unlink as unlink3, mkdir as mkdir3, appendFile } from "fs/promises";
|
|
225
|
+
import { dirname as dirname3 } from "path";
|
|
226
|
+
var CRASH_WINDOW_MS = 6e4;
|
|
227
|
+
var DEGRADED_THRESHOLD = 3;
|
|
228
|
+
async function readHealthFile(slockHome, serverId) {
|
|
229
|
+
if (!isValidServerId(serverId)) return { crashes: [] };
|
|
230
|
+
try {
|
|
231
|
+
const raw = await readFile4(serverHealthPath(slockHome, serverId), "utf8");
|
|
232
|
+
const parsed = JSON.parse(raw);
|
|
233
|
+
if (parsed && typeof parsed === "object" && Array.isArray(parsed.crashes)) {
|
|
234
|
+
return parsed;
|
|
235
|
+
}
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
return { crashes: [] };
|
|
239
|
+
}
|
|
240
|
+
async function isDegraded(slockHome, serverId, nowMs = Date.now()) {
|
|
241
|
+
const file = await readHealthFile(slockHome, serverId);
|
|
242
|
+
if (file.fatalConfig) return true;
|
|
243
|
+
const cutoffMs = nowMs - CRASH_WINDOW_MS;
|
|
244
|
+
const recent = file.crashes.filter((c) => {
|
|
245
|
+
const t = new Date(c.at).getTime();
|
|
246
|
+
return Number.isFinite(t) && t >= cutoffMs;
|
|
247
|
+
});
|
|
248
|
+
return recent.length >= DEGRADED_THRESHOLD;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/status.ts
|
|
252
|
+
async function readUserSession(path2) {
|
|
253
|
+
try {
|
|
254
|
+
const parsed = JSON.parse(await readFile5(path2, "utf8"));
|
|
255
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
256
|
+
return { state: "present", session: parsed, error: null };
|
|
257
|
+
}
|
|
258
|
+
return { state: "invalid", session: null, error: "not a JSON object" };
|
|
259
|
+
} catch (err) {
|
|
260
|
+
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
|
|
261
|
+
return { state: "missing", session: null, error: null };
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
state: "invalid",
|
|
265
|
+
session: null,
|
|
266
|
+
error: err instanceof Error ? err.message : String(err)
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function str(v) {
|
|
271
|
+
return typeof v === "string" && v.length > 0 ? v : null;
|
|
272
|
+
}
|
|
273
|
+
async function pidStatus(pidfile) {
|
|
274
|
+
const pid = await readPidfileAt(pidfile);
|
|
275
|
+
return pid !== null && isProcessAlive(pid) ? { running: true, pid } : { running: false };
|
|
276
|
+
}
|
|
277
|
+
async function deriveHealth(slockHome, serverId, daemon) {
|
|
278
|
+
if (!daemon.running) return "offline";
|
|
279
|
+
if (await isDegraded(slockHome, serverId)) return "degraded";
|
|
280
|
+
return "ok";
|
|
281
|
+
}
|
|
282
|
+
async function buildStatusReport(installRoot) {
|
|
283
|
+
const sessionRead = await readUserSession(userSessionPath(installRoot));
|
|
284
|
+
const session = sessionRead.session;
|
|
285
|
+
const attachments = await listServerAttachments(installRoot);
|
|
286
|
+
const supervisor = {
|
|
287
|
+
...await pidStatus(supervisorPidPath(installRoot)),
|
|
288
|
+
logPath: supervisorLogPath(installRoot)
|
|
289
|
+
};
|
|
290
|
+
const servers = [];
|
|
291
|
+
for (const a of attachments) {
|
|
292
|
+
const daemon = await pidStatus(serverDaemonPidPath(installRoot, a.serverId));
|
|
293
|
+
servers.push({
|
|
294
|
+
serverId: a.serverId,
|
|
295
|
+
serverSlug: a.serverSlug ?? null,
|
|
296
|
+
serverMachineId: a.serverMachineId,
|
|
297
|
+
serverUrl: a.serverUrl,
|
|
298
|
+
attachedAt: a.attachedAt ?? null,
|
|
299
|
+
daemonLogPath: serverDaemonLogPath(installRoot, a.serverId),
|
|
300
|
+
daemon,
|
|
301
|
+
health: await deriveHealth(installRoot, a.serverId, daemon)
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
const loggedIn = session?.kind === "user-session" && typeof session.accessToken === "string" && session.accessToken.length > 0;
|
|
305
|
+
return {
|
|
306
|
+
slockHome: installRoot,
|
|
307
|
+
loggedIn,
|
|
308
|
+
userId: session ? str(session.userId) : null,
|
|
309
|
+
loginServerUrl: session ? str(session.serverUrl) : null,
|
|
310
|
+
userSessionError: sessionRead.state === "invalid" ? sessionRead.error : null,
|
|
311
|
+
supervisor,
|
|
312
|
+
servers
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/apiClient.ts
|
|
317
|
+
import { fetch } from "undici";
|
|
318
|
+
var RunnersClient = class {
|
|
319
|
+
constructor(baseUrl, computerApiKey) {
|
|
320
|
+
this.baseUrl = baseUrl;
|
|
321
|
+
this.computerApiKey = computerApiKey;
|
|
322
|
+
}
|
|
323
|
+
url(p) {
|
|
324
|
+
return new URL(p, this.baseUrl).toString();
|
|
325
|
+
}
|
|
326
|
+
async list() {
|
|
327
|
+
const res = await fetch(this.url("/internal/computer/runners"), {
|
|
328
|
+
method: "GET",
|
|
329
|
+
headers: { Authorization: `Bearer ${this.computerApiKey}` }
|
|
330
|
+
});
|
|
331
|
+
const body = await res.json().catch(() => null);
|
|
332
|
+
if (res.status === 200 && body && Array.isArray(body.runners)) {
|
|
333
|
+
return {
|
|
334
|
+
status: "success",
|
|
335
|
+
whitelist: Array.isArray(body.whitelist) ? body.whitelist : [],
|
|
336
|
+
runners: body.runners
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
if (res.status === 401 || res.status === 403) return { status: "unauthorized" };
|
|
340
|
+
const code = body && typeof body.code === "string" ? body.code : `http_${res.status}`;
|
|
341
|
+
return { status: "error", code };
|
|
342
|
+
}
|
|
343
|
+
async stop(agentId) {
|
|
344
|
+
const res = await fetch(this.url(`/internal/computer/runners/${encodeURIComponent(agentId)}/stop`), {
|
|
345
|
+
method: "POST",
|
|
346
|
+
headers: { Authorization: `Bearer ${this.computerApiKey}`, "Content-Type": "application/json" },
|
|
347
|
+
body: "{}"
|
|
348
|
+
});
|
|
349
|
+
if (res.status === 200) return { status: "success" };
|
|
350
|
+
if (res.status === 404) return { status: "not_found" };
|
|
351
|
+
if (res.status === 401 || res.status === 403) return { status: "unauthorized" };
|
|
352
|
+
const body = await res.json().catch(() => null);
|
|
353
|
+
const code = body && typeof body.code === "string" ? body.code : `http_${res.status}`;
|
|
354
|
+
return { status: "error", code };
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// src/lib/readers.ts
|
|
359
|
+
async function readServiceStatus(installRoot) {
|
|
360
|
+
return buildStatusReport(installRoot);
|
|
361
|
+
}
|
|
362
|
+
async function readRunnerStatus(installRoot, serverId) {
|
|
363
|
+
const report = await buildStatusReport(installRoot);
|
|
364
|
+
const server = report.servers.find((s) => s.serverId === serverId);
|
|
365
|
+
if (!server) {
|
|
366
|
+
throw new StateReaderError(
|
|
367
|
+
"NOT_ATTACHED",
|
|
368
|
+
`Server ${serverId} is not attached to this Computer.`
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
const attachment = await readServerAttachment(installRoot, serverId);
|
|
372
|
+
if (!attachment) {
|
|
373
|
+
throw new StateReaderError(
|
|
374
|
+
"INVALID_ATTACHMENT",
|
|
375
|
+
`Attachment for server ${serverId} is missing or invalid.`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
const client = new RunnersClient(attachment.serverUrl, attachment.apiKey);
|
|
379
|
+
const result = await client.list();
|
|
380
|
+
if (result.status === "success") {
|
|
381
|
+
return { status: "ok", server, whitelist: result.whitelist, runners: result.runners };
|
|
382
|
+
}
|
|
383
|
+
if (result.status === "unauthorized") {
|
|
384
|
+
return { status: "unauthorized", server };
|
|
385
|
+
}
|
|
386
|
+
return { status: "error", server, code: result.code };
|
|
387
|
+
}
|
|
388
|
+
async function listRunners(installRoot, opts = {}) {
|
|
389
|
+
const all = await listServerAttachments(installRoot);
|
|
390
|
+
let subset = all;
|
|
391
|
+
if (opts.serverId !== void 0) {
|
|
392
|
+
const found = all.find((a) => a.serverId === opts.serverId);
|
|
393
|
+
if (!found) {
|
|
394
|
+
throw new StateReaderError(
|
|
395
|
+
"NOT_ATTACHED",
|
|
396
|
+
`Server ${opts.serverId} is not attached to this Computer.`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
subset = [found];
|
|
400
|
+
}
|
|
401
|
+
const servers = [];
|
|
402
|
+
for (const a of subset) {
|
|
403
|
+
const client = new RunnersClient(a.serverUrl, a.apiKey);
|
|
404
|
+
const result = await client.list();
|
|
405
|
+
const idCols = { serverId: a.serverId, serverSlug: a.serverSlug ?? null };
|
|
406
|
+
if (result.status === "success") {
|
|
407
|
+
servers.push({
|
|
408
|
+
...idCols,
|
|
409
|
+
status: "ok",
|
|
410
|
+
whitelist: result.whitelist,
|
|
411
|
+
runners: result.runners
|
|
412
|
+
});
|
|
413
|
+
} else if (result.status === "unauthorized") {
|
|
414
|
+
servers.push({ ...idCols, status: "unauthorized" });
|
|
415
|
+
} else {
|
|
416
|
+
servers.push({ ...idCols, status: "error", code: result.code });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return { servers };
|
|
420
|
+
}
|
|
24
421
|
|
|
25
422
|
// src/lib/state.ts
|
|
26
423
|
var RUNNER_STATE_VALUES = [
|
|
@@ -45,14 +442,7 @@ function isServiceState(value) {
|
|
|
45
442
|
}
|
|
46
443
|
|
|
47
444
|
// src/upgradeLog.ts
|
|
48
|
-
import { chmod, mkdir, open } from "fs/promises";
|
|
49
|
-
|
|
50
|
-
// src/paths.ts
|
|
51
|
-
import { createHash } from "crypto";
|
|
52
|
-
import os from "os";
|
|
53
|
-
import path from "path";
|
|
54
|
-
|
|
55
|
-
// src/upgradeLog.ts
|
|
445
|
+
import { chmod as chmod2, mkdir as mkdir4, open } from "fs/promises";
|
|
56
446
|
var UPGRADE_ERROR_CODES = [
|
|
57
447
|
"UPGRADE_DEPS_CHANGED",
|
|
58
448
|
"UPGRADE_NETWORK_FAILED",
|
|
@@ -96,12 +486,20 @@ function assertUpgradeLogEntry(entry) {
|
|
|
96
486
|
}
|
|
97
487
|
export {
|
|
98
488
|
IPC_ERROR_CODES,
|
|
489
|
+
MIGRATION_DETECTION_KINDS,
|
|
99
490
|
RUNNER_STATE_VALUES,
|
|
100
491
|
SERVICE_STATE_VALUES,
|
|
492
|
+
STATE_READER_ERROR_CODES,
|
|
101
493
|
ServiceClientError,
|
|
494
|
+
StateReaderError,
|
|
102
495
|
UPGRADE_ERROR_CODES,
|
|
103
496
|
assertUpgradeLogEntry,
|
|
497
|
+
detectLegacyMigration,
|
|
104
498
|
isIpcErrorCode,
|
|
499
|
+
isMigrationDetectionKind,
|
|
105
500
|
isRunnerState,
|
|
106
|
-
isServiceState
|
|
501
|
+
isServiceState,
|
|
502
|
+
listRunners,
|
|
503
|
+
readRunnerStatus,
|
|
504
|
+
readServiceStatus
|
|
107
505
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slock-ai/computer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
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.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^25.5.0",
|