@slock-ai/computer 0.0.4 → 0.0.5
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 +161 -59
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -68,15 +68,21 @@ var ComputerAttachClient = class {
|
|
|
68
68
|
}
|
|
69
69
|
/** POST /api/computer/attach — user-authed; issues sk_computer_*. */
|
|
70
70
|
async attach(serverSlug, name) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
let res;
|
|
72
|
+
try {
|
|
73
|
+
res = await fetch2(this.url("/api/computer/attach"), {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify({ serverSlug, name })
|
|
80
|
+
});
|
|
81
|
+
} catch {
|
|
82
|
+
return { status: "error", code: "request_failed" };
|
|
83
|
+
}
|
|
79
84
|
const body = await res.json().catch(() => null);
|
|
85
|
+
const code = body && typeof body.code === "string" ? body.code : void 0;
|
|
80
86
|
if (res.status === 201 && body && typeof body.apiKey === "string") {
|
|
81
87
|
return {
|
|
82
88
|
status: "success",
|
|
@@ -89,9 +95,11 @@ var ComputerAttachClient = class {
|
|
|
89
95
|
}
|
|
90
96
|
if (res.status === 401) return { status: "error", code: "session_invalid" };
|
|
91
97
|
if (res.status === 403) return { status: "not_authorized" };
|
|
92
|
-
if (res.status === 404)
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
if (res.status === 404) {
|
|
99
|
+
if (code === "not_authorized" || code === "server_not_found") return { status: "server_not_found" };
|
|
100
|
+
if (!code || code === "computer_attach_disabled") return { status: "disabled" };
|
|
101
|
+
}
|
|
102
|
+
return { status: "error", code: code ?? `http_${res.status}` };
|
|
95
103
|
}
|
|
96
104
|
/**
|
|
97
105
|
* POST /api/computer/adopt-legacy — task #39 PR-J1 (RFC v8.2 §5.11).
|
|
@@ -515,6 +523,12 @@ async function runAttach(opts) {
|
|
|
515
523
|
"Not authorized to attach to that server. Check the server slug and that you're a member."
|
|
516
524
|
);
|
|
517
525
|
}
|
|
526
|
+
if (attached.status === "server_not_found") {
|
|
527
|
+
fail(
|
|
528
|
+
"ATTACH_SERVER_NOT_FOUND",
|
|
529
|
+
`Server ${formatServerSlugDisplay(slugForServer)} was not found on ${baseUrl}. Check the slug spelling and --server-url, then retry.`
|
|
530
|
+
);
|
|
531
|
+
}
|
|
518
532
|
if (attached.status === "error") {
|
|
519
533
|
if (attached.code === "session_invalid") {
|
|
520
534
|
fail(
|
|
@@ -522,6 +536,12 @@ async function runAttach(opts) {
|
|
|
522
536
|
"Your user session is no longer valid. Re-run `slock-computer login`."
|
|
523
537
|
);
|
|
524
538
|
}
|
|
539
|
+
if (attached.code === "request_failed") {
|
|
540
|
+
fail(
|
|
541
|
+
"ATTACH_REQUEST_FAILED",
|
|
542
|
+
`Could not reach ${baseUrl} while attaching to ${formatServerSlugDisplay(slugForServer)}. Check --server-url / network connectivity, then retry.`
|
|
543
|
+
);
|
|
544
|
+
}
|
|
525
545
|
if (attached.code === "COMPUTER_NAME_COLLISION") {
|
|
526
546
|
fail(
|
|
527
547
|
"COMPUTER_NAME_COLLISION",
|
|
@@ -835,9 +855,10 @@ async function runAdoptLegacy(inputs) {
|
|
|
835
855
|
failureReason: result.code ? `unexpected_response_${result.code}` : "unexpected_response_missing_code"
|
|
836
856
|
});
|
|
837
857
|
const responseDetail = result.code ? `status ${result.httpStatus}, code ${result.code}` : `status ${result.httpStatus}, missing error code`;
|
|
858
|
+
const authHint = result.httpStatus === 401 ? " If your server may be on an older release that does not emit `code: auth_required`, re-run `slock-computer login` first to refresh your user session, then retry. If the issue persists, report it as server contract drift." : "";
|
|
838
859
|
fail(
|
|
839
860
|
"ADOPT_UNEXPECTED_RESPONSE",
|
|
840
|
-
`Server returned an unexpected legacy adoption response (${responseDetail})
|
|
861
|
+
`Server returned an unexpected legacy adoption response (${responseDetail}).${authHint} Local legacy owner evidence for this key: ${formatLegacyOwnerEvidence(slockHome, ownerEvidence)}. Please report this with the command, server URL, and SLOCK_HOME; no local Computer state was written.`
|
|
841
862
|
);
|
|
842
863
|
}
|
|
843
864
|
if (result.status === "error") {
|
|
@@ -971,8 +992,9 @@ async function appendAdoptionLog(slockHome, line) {
|
|
|
971
992
|
}
|
|
972
993
|
|
|
973
994
|
// src/setup.ts
|
|
974
|
-
import { readdir as readdir3, readFile as readFile6 } from "fs/promises";
|
|
975
|
-
import { join as join3 } from "path";
|
|
995
|
+
import { chmod as chmod4, mkdir as mkdir8, readdir as readdir3, readFile as readFile6, rename as rename3, rm as rm2, writeFile as writeFile7 } from "fs/promises";
|
|
996
|
+
import { dirname as dirname8, join as join3 } from "path";
|
|
997
|
+
import { fetch as fetch3 } from "undici";
|
|
976
998
|
|
|
977
999
|
// src/supervisor.ts
|
|
978
1000
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -1662,14 +1684,74 @@ async function bestEffortServerRevoke(serverUrl, apiKey, serverId) {
|
|
|
1662
1684
|
}
|
|
1663
1685
|
|
|
1664
1686
|
// src/setup.ts
|
|
1687
|
+
var USER_SESSION_EXPIRY_LEEWAY_MS = 3e4;
|
|
1665
1688
|
async function hasValidUserSession(slockHome) {
|
|
1666
1689
|
try {
|
|
1667
1690
|
const parsed = JSON.parse(await readFile6(userSessionPath(slockHome), "utf8"));
|
|
1668
|
-
return parsed.kind === "user-session" && typeof parsed.accessToken === "string" && parsed.accessToken.length > 0;
|
|
1691
|
+
return parsed.kind === "user-session" && typeof parsed.accessToken === "string" && parsed.accessToken.length > 0 && !isJwtExpired(parsed.accessToken);
|
|
1669
1692
|
} catch {
|
|
1670
1693
|
return false;
|
|
1671
1694
|
}
|
|
1672
1695
|
}
|
|
1696
|
+
function isJwtExpired(token, nowMs = Date.now()) {
|
|
1697
|
+
const [, payload] = token.split(".");
|
|
1698
|
+
if (!payload) return false;
|
|
1699
|
+
try {
|
|
1700
|
+
const parsed = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
1701
|
+
return typeof parsed.exp === "number" && parsed.exp * 1e3 <= nowMs + USER_SESSION_EXPIRY_LEEWAY_MS;
|
|
1702
|
+
} catch {
|
|
1703
|
+
return false;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
async function refreshUserSession(slockHome, serverUrl) {
|
|
1707
|
+
const file = userSessionPath(slockHome);
|
|
1708
|
+
let session;
|
|
1709
|
+
try {
|
|
1710
|
+
session = JSON.parse(await readFile6(file, "utf8"));
|
|
1711
|
+
} catch {
|
|
1712
|
+
return false;
|
|
1713
|
+
}
|
|
1714
|
+
if (session.kind !== "user-session" || typeof session.refreshToken !== "string" || session.refreshToken.length === 0) {
|
|
1715
|
+
return false;
|
|
1716
|
+
}
|
|
1717
|
+
const baseUrl = resolveServerUrl(serverUrl, session.serverUrl, process.env.SLOCK_SERVER_URL);
|
|
1718
|
+
const tmpFile = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
1719
|
+
try {
|
|
1720
|
+
const res = await fetch3(new URL("/api/auth/refresh", baseUrl).toString(), {
|
|
1721
|
+
method: "POST",
|
|
1722
|
+
headers: { "Content-Type": "application/json" },
|
|
1723
|
+
body: JSON.stringify({ refreshToken: session.refreshToken })
|
|
1724
|
+
});
|
|
1725
|
+
const body = await res.json().catch(() => null);
|
|
1726
|
+
if (res.status !== 200 || typeof body?.accessToken !== "string" || typeof body.refreshToken !== "string") {
|
|
1727
|
+
return false;
|
|
1728
|
+
}
|
|
1729
|
+
await mkdir8(dirname8(file), { recursive: true });
|
|
1730
|
+
await writeFile7(
|
|
1731
|
+
tmpFile,
|
|
1732
|
+
JSON.stringify(
|
|
1733
|
+
{
|
|
1734
|
+
kind: "user-session",
|
|
1735
|
+
userId: session.userId,
|
|
1736
|
+
accessToken: body.accessToken,
|
|
1737
|
+
refreshToken: body.refreshToken,
|
|
1738
|
+
serverUrl: baseUrl,
|
|
1739
|
+
createdAt: session.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1740
|
+
refreshedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1741
|
+
},
|
|
1742
|
+
null,
|
|
1743
|
+
2
|
|
1744
|
+
),
|
|
1745
|
+
{ mode: 384 }
|
|
1746
|
+
);
|
|
1747
|
+
await chmod4(tmpFile, 384);
|
|
1748
|
+
await rename3(tmpFile, file);
|
|
1749
|
+
return true;
|
|
1750
|
+
} catch {
|
|
1751
|
+
await rm2(tmpFile, { force: true }).catch(() => void 0);
|
|
1752
|
+
return false;
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1673
1755
|
async function hasLiveLegacyDaemon(slockHome) {
|
|
1674
1756
|
let machineDirs;
|
|
1675
1757
|
try {
|
|
@@ -1701,6 +1783,7 @@ async function runSetup(opts, deps = {}) {
|
|
|
1701
1783
|
const attach = deps.runAttach ?? runAttach;
|
|
1702
1784
|
const adopt = deps.runAdoptLegacy ?? runAdoptLegacy;
|
|
1703
1785
|
const start = deps.runStart ?? runStart;
|
|
1786
|
+
const refreshSession = deps.refreshUserSession ?? refreshUserSession;
|
|
1704
1787
|
const legacyDaemonCheck = deps.hasLiveLegacyDaemon ?? hasLiveLegacyDaemon;
|
|
1705
1788
|
if (!isTty && !opts.yes) {
|
|
1706
1789
|
fail(
|
|
@@ -1717,13 +1800,18 @@ async function runSetup(opts, deps = {}) {
|
|
|
1717
1800
|
const label = formatServerSlugDisplay(opts.serverSlug);
|
|
1718
1801
|
info(`Setting up Slock Computer for ${label}\u2026`);
|
|
1719
1802
|
if (!await hasValidUserSession(slockHome)) {
|
|
1720
|
-
if (
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1803
|
+
if (await refreshSession(slockHome, opts.serverUrl)) {
|
|
1804
|
+
info("User session: refreshed.");
|
|
1805
|
+
} else {
|
|
1806
|
+
if (!isTty) {
|
|
1807
|
+
fail(
|
|
1808
|
+
"NON_INTERACTIVE_SETUP_REQUIRES_FLAGS",
|
|
1809
|
+
"No valid user session is available and setup is running non-interactively. Run `slock-computer login` in a terminal first, then re-run setup with --yes."
|
|
1810
|
+
);
|
|
1811
|
+
}
|
|
1812
|
+
info("User session: missing or expired; starting login.");
|
|
1813
|
+
await login({ serverUrl: opts.serverUrl });
|
|
1725
1814
|
}
|
|
1726
|
-
await login({ serverUrl: opts.serverUrl });
|
|
1727
1815
|
} else {
|
|
1728
1816
|
info("User session: already logged in.");
|
|
1729
1817
|
}
|
|
@@ -1786,11 +1874,22 @@ async function runSetup(opts, deps = {}) {
|
|
|
1786
1874
|
|
|
1787
1875
|
// src/status.ts
|
|
1788
1876
|
import { readFile as readFile7 } from "fs/promises";
|
|
1789
|
-
async function
|
|
1877
|
+
async function readUserSession(path2) {
|
|
1790
1878
|
try {
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1879
|
+
const parsed = JSON.parse(await readFile7(path2, "utf8"));
|
|
1880
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1881
|
+
return { state: "present", session: parsed, error: null };
|
|
1882
|
+
}
|
|
1883
|
+
return { state: "invalid", session: null, error: "not a JSON object" };
|
|
1884
|
+
} catch (err) {
|
|
1885
|
+
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
|
|
1886
|
+
return { state: "missing", session: null, error: null };
|
|
1887
|
+
}
|
|
1888
|
+
return {
|
|
1889
|
+
state: "invalid",
|
|
1890
|
+
session: null,
|
|
1891
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1892
|
+
};
|
|
1794
1893
|
}
|
|
1795
1894
|
}
|
|
1796
1895
|
function str(v) {
|
|
@@ -1807,7 +1906,8 @@ async function deriveHealth(slockHome, serverId, daemon) {
|
|
|
1807
1906
|
}
|
|
1808
1907
|
async function buildStatusReport() {
|
|
1809
1908
|
const slockHome = resolveSlockHome();
|
|
1810
|
-
const
|
|
1909
|
+
const sessionRead = await readUserSession(userSessionPath(slockHome));
|
|
1910
|
+
const session = sessionRead.session;
|
|
1811
1911
|
const attachments = await listServerAttachments(slockHome);
|
|
1812
1912
|
const supervisor = {
|
|
1813
1913
|
...await pidStatus(supervisorPidPath(slockHome)),
|
|
@@ -1833,6 +1933,7 @@ async function buildStatusReport() {
|
|
|
1833
1933
|
loggedIn,
|
|
1834
1934
|
userId: session ? str(session.userId) : null,
|
|
1835
1935
|
loginServerUrl: session ? str(session.serverUrl) : null,
|
|
1936
|
+
userSessionError: sessionRead.state === "invalid" ? sessionRead.error : null,
|
|
1836
1937
|
supervisor,
|
|
1837
1938
|
servers
|
|
1838
1939
|
};
|
|
@@ -1848,8 +1949,9 @@ async function runStatus(opts) {
|
|
|
1848
1949
|
}
|
|
1849
1950
|
info("");
|
|
1850
1951
|
info(`SLOCK_HOME: ${report.slockHome}`);
|
|
1952
|
+
const loginDetail = report.userSessionError ? "no \u2014 user session file is invalid; re-run `slock-computer login`" : report.loggedIn ? `yes (user ${report.userId ?? "?"})` : "no \u2014 run `slock-computer login`";
|
|
1851
1953
|
info(
|
|
1852
|
-
`Logged in: ${
|
|
1954
|
+
`Logged in: ${loginDetail}`
|
|
1853
1955
|
);
|
|
1854
1956
|
if (report.loginServerUrl) info(`Login server: ${report.loginServerUrl}`);
|
|
1855
1957
|
info(
|
|
@@ -2028,7 +2130,7 @@ async function runDoctorChecks() {
|
|
|
2028
2130
|
const checks = [];
|
|
2029
2131
|
checks.push({ name: "SLOCK_HOME", ok: true, detail: report.slockHome });
|
|
2030
2132
|
checks.push(
|
|
2031
|
-
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`" }
|
|
2133
|
+
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`" }
|
|
2032
2134
|
);
|
|
2033
2135
|
checks.push(
|
|
2034
2136
|
report.supervisor.running ? { name: "supervisor", ok: true, detail: `running (pid ${report.supervisor.pid})` } : {
|
|
@@ -2171,13 +2273,13 @@ async function runLogs(opts) {
|
|
|
2171
2273
|
|
|
2172
2274
|
// src/concurrency.ts
|
|
2173
2275
|
import lockfile from "proper-lockfile";
|
|
2174
|
-
import { mkdir as
|
|
2276
|
+
import { mkdir as mkdir9 } from "fs/promises";
|
|
2175
2277
|
import { join as join4 } from "path";
|
|
2176
2278
|
var STALE_LOCK_THRESHOLD_MS = 6e4;
|
|
2177
2279
|
async function withMutationLock(fn) {
|
|
2178
2280
|
const slockHome = resolveSlockHome();
|
|
2179
2281
|
const lockTarget = computerDir(slockHome);
|
|
2180
|
-
await
|
|
2282
|
+
await mkdir9(lockTarget, { recursive: true });
|
|
2181
2283
|
const lockfilePath = join4(lockTarget, ".lock");
|
|
2182
2284
|
let release = null;
|
|
2183
2285
|
try {
|
|
@@ -2215,8 +2317,8 @@ async function withMutationLock(fn) {
|
|
|
2215
2317
|
}
|
|
2216
2318
|
|
|
2217
2319
|
// src/channel.ts
|
|
2218
|
-
import { readFile as readFile9, writeFile as
|
|
2219
|
-
import { dirname as
|
|
2320
|
+
import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir10 } from "fs/promises";
|
|
2321
|
+
import { dirname as dirname9 } from "path";
|
|
2220
2322
|
var DEFAULT_CHANNEL = "latest";
|
|
2221
2323
|
var SEMVER_RE = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
|
|
2222
2324
|
function parseChannel(raw) {
|
|
@@ -2240,8 +2342,8 @@ async function readChannel(slockHome) {
|
|
|
2240
2342
|
}
|
|
2241
2343
|
async function writeChannel(slockHome, channel2) {
|
|
2242
2344
|
const p = channelPath(slockHome);
|
|
2243
|
-
await
|
|
2244
|
-
await
|
|
2345
|
+
await mkdir10(dirname9(p), { recursive: true });
|
|
2346
|
+
await writeFile8(p, `${channel2}
|
|
2245
2347
|
`, { mode: 384 });
|
|
2246
2348
|
}
|
|
2247
2349
|
async function runChannelShow(slockHome) {
|
|
@@ -2265,11 +2367,11 @@ async function runChannelSet(slockHome, raw) {
|
|
|
2265
2367
|
// src/upgradeCli.ts
|
|
2266
2368
|
import { readFile as readFile12 } from "fs/promises";
|
|
2267
2369
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2268
|
-
import { dirname as
|
|
2370
|
+
import { dirname as dirname10, join as join7 } from "path";
|
|
2269
2371
|
|
|
2270
2372
|
// src/upgrade.ts
|
|
2271
2373
|
import { spawn as spawn4 } from "child_process";
|
|
2272
|
-
import { mkdir as
|
|
2374
|
+
import { mkdir as mkdir11, readFile as readFile11, writeFile as writeFile9, rm as rm3, rename as rename4 } from "fs/promises";
|
|
2273
2375
|
import { join as join6 } from "path";
|
|
2274
2376
|
import { createHash as createHash3 } from "crypto";
|
|
2275
2377
|
|
|
@@ -2547,7 +2649,7 @@ async function stagePhase(slockHome, version, deps = {}) {
|
|
|
2547
2649
|
const npmPack = deps.npmPack ?? defaultNpmPack;
|
|
2548
2650
|
const fsReadFile = deps.fsReadFile ?? readFile11;
|
|
2549
2651
|
const stagedPath = upgradeStagingDir(slockHome, version);
|
|
2550
|
-
await
|
|
2652
|
+
await mkdir11(stagedPath, { recursive: true });
|
|
2551
2653
|
const packageRef = `@slock-ai/computer@${version}`;
|
|
2552
2654
|
const result = await npmPack(stagedPath, packageRef);
|
|
2553
2655
|
if (result.exitCode !== 0) {
|
|
@@ -2648,7 +2750,7 @@ async function defaultFetchAdvertisedHash(version) {
|
|
|
2648
2750
|
}
|
|
2649
2751
|
async function cleanupStaged(slockHome, version) {
|
|
2650
2752
|
try {
|
|
2651
|
-
await
|
|
2753
|
+
await rm3(upgradeStagingDir(slockHome, version), { recursive: true, force: true });
|
|
2652
2754
|
} catch {
|
|
2653
2755
|
}
|
|
2654
2756
|
}
|
|
@@ -2658,9 +2760,9 @@ function upgradeSnapshotPath(slockHome) {
|
|
|
2658
2760
|
async function snapshotPhase(slockHome, snap) {
|
|
2659
2761
|
const path2 = upgradeSnapshotPath(slockHome);
|
|
2660
2762
|
const tmp = `${path2}.tmp`;
|
|
2661
|
-
await
|
|
2662
|
-
await
|
|
2663
|
-
await
|
|
2763
|
+
await mkdir11(computerDir(slockHome), { recursive: true });
|
|
2764
|
+
await writeFile9(tmp, JSON.stringify(snap, null, 2), { mode: 384 });
|
|
2765
|
+
await rename4(tmp, path2);
|
|
2664
2766
|
}
|
|
2665
2767
|
async function clearUpgradeSnapshot(slockHome) {
|
|
2666
2768
|
try {
|
|
@@ -2671,7 +2773,7 @@ async function clearUpgradeSnapshot(slockHome) {
|
|
|
2671
2773
|
}
|
|
2672
2774
|
async function extractTarball(tarballPath, destDir, deps = {}) {
|
|
2673
2775
|
const tarSpawn = deps.tarSpawn ?? defaultTarSpawn;
|
|
2674
|
-
await
|
|
2776
|
+
await mkdir11(destDir, { recursive: true });
|
|
2675
2777
|
const result = await tarSpawn(tarballPath, destDir);
|
|
2676
2778
|
if (result.exitCode !== 0) {
|
|
2677
2779
|
const err = new Error(
|
|
@@ -2700,8 +2802,8 @@ function defaultTarSpawn(tarballPath, destDir) {
|
|
|
2700
2802
|
});
|
|
2701
2803
|
}
|
|
2702
2804
|
async function swapPhase(currentBinaryDir, stagedBinaryDir, deps = {}) {
|
|
2703
|
-
const fsRename = deps.fsRename ??
|
|
2704
|
-
const fsRm = deps.fsRm ?? ((p) =>
|
|
2805
|
+
const fsRename = deps.fsRename ?? rename4;
|
|
2806
|
+
const fsRm = deps.fsRm ?? ((p) => rm3(p, { recursive: true, force: true }));
|
|
2705
2807
|
const prevBinaryDir = `${currentBinaryDir}.prev`;
|
|
2706
2808
|
try {
|
|
2707
2809
|
await fsRm(prevBinaryDir);
|
|
@@ -2723,8 +2825,8 @@ async function swapPhase(currentBinaryDir, stagedBinaryDir, deps = {}) {
|
|
|
2723
2825
|
return { prevBinaryDir, newBinaryDir: currentBinaryDir };
|
|
2724
2826
|
}
|
|
2725
2827
|
async function rollbackSwap(currentBinaryDir, deps = {}) {
|
|
2726
|
-
const fsRename = deps.fsRename ??
|
|
2727
|
-
const fsRm = deps.fsRm ?? ((p) =>
|
|
2828
|
+
const fsRename = deps.fsRename ?? rename4;
|
|
2829
|
+
const fsRm = deps.fsRm ?? ((p) => rm3(p, { recursive: true, force: true }));
|
|
2728
2830
|
const prevBinaryDir = `${currentBinaryDir}.prev`;
|
|
2729
2831
|
try {
|
|
2730
2832
|
await fsRm(currentBinaryDir);
|
|
@@ -2942,7 +3044,7 @@ async function cleanupSuccessPhase(slockHome, version, prevBinaryDir) {
|
|
|
2942
3044
|
await cleanupStaged(slockHome, version);
|
|
2943
3045
|
await clearUpgradeSnapshot(slockHome);
|
|
2944
3046
|
try {
|
|
2945
|
-
await
|
|
3047
|
+
await rm3(prevBinaryDir, { recursive: true, force: true });
|
|
2946
3048
|
} catch {
|
|
2947
3049
|
}
|
|
2948
3050
|
}
|
|
@@ -3355,7 +3457,7 @@ async function defaultFetchDistTags() {
|
|
|
3355
3457
|
}
|
|
3356
3458
|
function defaultCurrentBinaryDir() {
|
|
3357
3459
|
const here = fileURLToPath2(import.meta.url);
|
|
3358
|
-
return
|
|
3460
|
+
return dirname10(dirname10(here));
|
|
3359
3461
|
}
|
|
3360
3462
|
async function defaultCurrentVersion() {
|
|
3361
3463
|
const pkgPath = join7(defaultCurrentBinaryDir(), "package.json");
|
|
@@ -3371,7 +3473,7 @@ async function defaultCurrentVersion() {
|
|
|
3371
3473
|
}
|
|
3372
3474
|
|
|
3373
3475
|
// src/upgradeTestHarness.ts
|
|
3374
|
-
import { mkdir as
|
|
3476
|
+
import { mkdir as mkdir12, readdir as readdir4, stat as stat3, writeFile as writeFile10 } from "fs/promises";
|
|
3375
3477
|
import { join as join8 } from "path";
|
|
3376
3478
|
import { createHash as createHash4 } from "crypto";
|
|
3377
3479
|
var PHASES = /* @__PURE__ */ new Set([
|
|
@@ -3430,7 +3532,7 @@ function buildSimulatedDeps(slockHome, opts) {
|
|
|
3430
3532
|
return { tarballPath: "", exitCode: 1, stderr: "simulated stage failure" };
|
|
3431
3533
|
}
|
|
3432
3534
|
const filename = `slock-ai-computer-${targetVersion}.tgz`;
|
|
3433
|
-
await
|
|
3535
|
+
await writeFile10(join8(cwd, filename), tarballBytes);
|
|
3434
3536
|
return { tarballPath: join8(cwd, filename), exitCode: 0, stderr: "" };
|
|
3435
3537
|
},
|
|
3436
3538
|
fetchAdvertisedHash: async () => {
|
|
@@ -3442,8 +3544,8 @@ function buildSimulatedDeps(slockHome, opts) {
|
|
|
3442
3544
|
if (opts.simulateFail === "extract") {
|
|
3443
3545
|
return { exitCode: 1, stderr: "simulated extract failure" };
|
|
3444
3546
|
}
|
|
3445
|
-
await
|
|
3446
|
-
await
|
|
3547
|
+
await mkdir12(join8(destDir, "package"), { recursive: true });
|
|
3548
|
+
await writeFile10(join8(destDir, "package", "marker.txt"), `NEW@${targetVersion}`);
|
|
3447
3549
|
return { exitCode: 0, stderr: "" };
|
|
3448
3550
|
},
|
|
3449
3551
|
fsRename: opts.simulateFail === "swap" ? async () => {
|
|
@@ -3503,7 +3605,7 @@ function buildSimulatedDeps(slockHome, opts) {
|
|
|
3503
3605
|
}
|
|
3504
3606
|
async function arrangeSnapshotFailure(slockHome) {
|
|
3505
3607
|
const snapshotPath = join8(slockHome, "computer", "upgrade-snapshot.json");
|
|
3506
|
-
await
|
|
3608
|
+
await mkdir12(snapshotPath, { recursive: true });
|
|
3507
3609
|
}
|
|
3508
3610
|
async function pathInfo(path2) {
|
|
3509
3611
|
try {
|
|
@@ -3558,12 +3660,12 @@ async function runUpgradeTestHarness(slockHome, opts, writer = (s) => process.st
|
|
|
3558
3660
|
process.exitCode = 1;
|
|
3559
3661
|
return;
|
|
3560
3662
|
}
|
|
3561
|
-
await
|
|
3663
|
+
await mkdir12(slockHome, { recursive: true });
|
|
3562
3664
|
if (opts.simulateFail === "snapshot") {
|
|
3563
3665
|
await arrangeSnapshotFailure(slockHome);
|
|
3564
3666
|
}
|
|
3565
3667
|
const { opts: upgradeOpts } = buildSimulatedDeps(slockHome, opts);
|
|
3566
|
-
await
|
|
3668
|
+
await mkdir12(upgradeOpts.currentBinaryDir, { recursive: true });
|
|
3567
3669
|
let outcome;
|
|
3568
3670
|
try {
|
|
3569
3671
|
outcome = await runUpgrade(slockHome, upgradeOpts);
|
|
@@ -3600,9 +3702,9 @@ async function runUpgradeTestHarness(slockHome, opts, writer = (s) => process.st
|
|
|
3600
3702
|
}
|
|
3601
3703
|
|
|
3602
3704
|
// src/upgradeInstallSmoke.ts
|
|
3603
|
-
import { copyFile, mkdir as
|
|
3705
|
+
import { copyFile, mkdir as mkdir13, readFile as readFile13 } from "fs/promises";
|
|
3604
3706
|
import { createHash as createHash5 } from "crypto";
|
|
3605
|
-
import { dirname as
|
|
3707
|
+
import { dirname as dirname11, isAbsolute, join as join9, resolve as pathResolve } from "path";
|
|
3606
3708
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3607
3709
|
async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
3608
3710
|
if (typeof opts.packageTarball !== "string" || opts.packageTarball.trim().length === 0) {
|
|
@@ -3623,7 +3725,7 @@ async function runUpgradeInstallSmoke(slockHome, opts, deps = {}) {
|
|
|
3623
3725
|
const spawnFreshSupervisor = deps.spawnFreshSupervisor ?? (async (h) => {
|
|
3624
3726
|
await spawnDetachedSupervisor(h);
|
|
3625
3727
|
});
|
|
3626
|
-
await
|
|
3728
|
+
await mkdir13(slockHome, { recursive: true });
|
|
3627
3729
|
const outcome = await runUpgrade(slockHome, {
|
|
3628
3730
|
targetVersion: opts.targetVersion,
|
|
3629
3731
|
fromVersion,
|
|
@@ -3676,7 +3778,7 @@ async function runUpgradeInstallSmokeCli(slockHome, opts, writer = (s) => proces
|
|
|
3676
3778
|
}
|
|
3677
3779
|
function defaultCurrentBinaryDirLocal() {
|
|
3678
3780
|
const here = fileURLToPath3(import.meta.url);
|
|
3679
|
-
return
|
|
3781
|
+
return dirname11(dirname11(here));
|
|
3680
3782
|
}
|
|
3681
3783
|
async function defaultCurrentVersionLocal() {
|
|
3682
3784
|
const pkgPath = join9(defaultCurrentBinaryDirLocal(), "package.json");
|
package/package.json
CHANGED