@slock-ai/computer 0.0.4 → 0.0.6

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.
Files changed (2) hide show
  1. package/dist/index.js +167 -65
  2. 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
- const res = await fetch2(this.url("/api/computer/attach"), {
72
- method: "POST",
73
- headers: {
74
- "Content-Type": "application/json",
75
- Authorization: `Bearer ${this.accessToken}`
76
- },
77
- body: JSON.stringify({ serverSlug, name })
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) return { status: "disabled" };
93
- const code = body && typeof body.code === "string" ? body.code : `http_${res.status}`;
94
- return { status: "error", code };
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).
@@ -290,6 +298,12 @@ function adoptionLogPath(slockHome) {
290
298
  function channelPath(slockHome) {
291
299
  return path.join(computerDir(slockHome), "channel");
292
300
  }
301
+ function upgradeStagingDir(slockHome, version) {
302
+ return path.join(computerDir(slockHome), "upgrade-staging", version);
303
+ }
304
+ function upgradeSnapshotPath(slockHome) {
305
+ return path.join(computerDir(slockHome), "upgrade-snapshot.json");
306
+ }
293
307
 
294
308
  // src/output.ts
295
309
  var CliExit = class extends Error {
@@ -515,6 +529,12 @@ async function runAttach(opts) {
515
529
  "Not authorized to attach to that server. Check the server slug and that you're a member."
516
530
  );
517
531
  }
532
+ if (attached.status === "server_not_found") {
533
+ fail(
534
+ "ATTACH_SERVER_NOT_FOUND",
535
+ `Server ${formatServerSlugDisplay(slugForServer)} was not found on ${baseUrl}. Check the slug spelling and --server-url, then retry.`
536
+ );
537
+ }
518
538
  if (attached.status === "error") {
519
539
  if (attached.code === "session_invalid") {
520
540
  fail(
@@ -522,6 +542,12 @@ async function runAttach(opts) {
522
542
  "Your user session is no longer valid. Re-run `slock-computer login`."
523
543
  );
524
544
  }
545
+ if (attached.code === "request_failed") {
546
+ fail(
547
+ "ATTACH_REQUEST_FAILED",
548
+ `Could not reach ${baseUrl} while attaching to ${formatServerSlugDisplay(slugForServer)}. Check --server-url / network connectivity, then retry.`
549
+ );
550
+ }
525
551
  if (attached.code === "COMPUTER_NAME_COLLISION") {
526
552
  fail(
527
553
  "COMPUTER_NAME_COLLISION",
@@ -835,9 +861,10 @@ async function runAdoptLegacy(inputs) {
835
861
  failureReason: result.code ? `unexpected_response_${result.code}` : "unexpected_response_missing_code"
836
862
  });
837
863
  const responseDetail = result.code ? `status ${result.httpStatus}, code ${result.code}` : `status ${result.httpStatus}, missing error code`;
864
+ 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
865
  fail(
839
866
  "ADOPT_UNEXPECTED_RESPONSE",
840
- `Server returned an unexpected legacy adoption response (${responseDetail}). 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.`
867
+ `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
868
  );
842
869
  }
843
870
  if (result.status === "error") {
@@ -971,8 +998,9 @@ async function appendAdoptionLog(slockHome, line) {
971
998
  }
972
999
 
973
1000
  // src/setup.ts
974
- import { readdir as readdir3, readFile as readFile6 } from "fs/promises";
975
- import { join as join3 } from "path";
1001
+ 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";
1002
+ import { dirname as dirname8, join as join3 } from "path";
1003
+ import { fetch as fetch3 } from "undici";
976
1004
 
977
1005
  // src/supervisor.ts
978
1006
  import { spawn as spawn2 } from "child_process";
@@ -1662,14 +1690,74 @@ async function bestEffortServerRevoke(serverUrl, apiKey, serverId) {
1662
1690
  }
1663
1691
 
1664
1692
  // src/setup.ts
1693
+ var USER_SESSION_EXPIRY_LEEWAY_MS = 3e4;
1665
1694
  async function hasValidUserSession(slockHome) {
1666
1695
  try {
1667
1696
  const parsed = JSON.parse(await readFile6(userSessionPath(slockHome), "utf8"));
1668
- return parsed.kind === "user-session" && typeof parsed.accessToken === "string" && parsed.accessToken.length > 0;
1697
+ return parsed.kind === "user-session" && typeof parsed.accessToken === "string" && parsed.accessToken.length > 0 && !isJwtExpired(parsed.accessToken);
1669
1698
  } catch {
1670
1699
  return false;
1671
1700
  }
1672
1701
  }
1702
+ function isJwtExpired(token, nowMs = Date.now()) {
1703
+ const [, payload] = token.split(".");
1704
+ if (!payload) return false;
1705
+ try {
1706
+ const parsed = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
1707
+ return typeof parsed.exp === "number" && parsed.exp * 1e3 <= nowMs + USER_SESSION_EXPIRY_LEEWAY_MS;
1708
+ } catch {
1709
+ return false;
1710
+ }
1711
+ }
1712
+ async function refreshUserSession(slockHome, serverUrl) {
1713
+ const file = userSessionPath(slockHome);
1714
+ let session;
1715
+ try {
1716
+ session = JSON.parse(await readFile6(file, "utf8"));
1717
+ } catch {
1718
+ return false;
1719
+ }
1720
+ if (session.kind !== "user-session" || typeof session.refreshToken !== "string" || session.refreshToken.length === 0) {
1721
+ return false;
1722
+ }
1723
+ const baseUrl = resolveServerUrl(serverUrl, session.serverUrl, process.env.SLOCK_SERVER_URL);
1724
+ const tmpFile = `${file}.${process.pid}.${Date.now()}.tmp`;
1725
+ try {
1726
+ const res = await fetch3(new URL("/api/auth/refresh", baseUrl).toString(), {
1727
+ method: "POST",
1728
+ headers: { "Content-Type": "application/json" },
1729
+ body: JSON.stringify({ refreshToken: session.refreshToken })
1730
+ });
1731
+ const body = await res.json().catch(() => null);
1732
+ if (res.status !== 200 || typeof body?.accessToken !== "string" || typeof body.refreshToken !== "string") {
1733
+ return false;
1734
+ }
1735
+ await mkdir8(dirname8(file), { recursive: true });
1736
+ await writeFile7(
1737
+ tmpFile,
1738
+ JSON.stringify(
1739
+ {
1740
+ kind: "user-session",
1741
+ userId: session.userId,
1742
+ accessToken: body.accessToken,
1743
+ refreshToken: body.refreshToken,
1744
+ serverUrl: baseUrl,
1745
+ createdAt: session.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1746
+ refreshedAt: (/* @__PURE__ */ new Date()).toISOString()
1747
+ },
1748
+ null,
1749
+ 2
1750
+ ),
1751
+ { mode: 384 }
1752
+ );
1753
+ await chmod4(tmpFile, 384);
1754
+ await rename3(tmpFile, file);
1755
+ return true;
1756
+ } catch {
1757
+ await rm2(tmpFile, { force: true }).catch(() => void 0);
1758
+ return false;
1759
+ }
1760
+ }
1673
1761
  async function hasLiveLegacyDaemon(slockHome) {
1674
1762
  let machineDirs;
1675
1763
  try {
@@ -1701,6 +1789,7 @@ async function runSetup(opts, deps = {}) {
1701
1789
  const attach = deps.runAttach ?? runAttach;
1702
1790
  const adopt = deps.runAdoptLegacy ?? runAdoptLegacy;
1703
1791
  const start = deps.runStart ?? runStart;
1792
+ const refreshSession = deps.refreshUserSession ?? refreshUserSession;
1704
1793
  const legacyDaemonCheck = deps.hasLiveLegacyDaemon ?? hasLiveLegacyDaemon;
1705
1794
  if (!isTty && !opts.yes) {
1706
1795
  fail(
@@ -1717,13 +1806,18 @@ async function runSetup(opts, deps = {}) {
1717
1806
  const label = formatServerSlugDisplay(opts.serverSlug);
1718
1807
  info(`Setting up Slock Computer for ${label}\u2026`);
1719
1808
  if (!await hasValidUserSession(slockHome)) {
1720
- if (!isTty) {
1721
- fail(
1722
- "NON_INTERACTIVE_SETUP_REQUIRES_FLAGS",
1723
- "No user session is available and setup is running non-interactively. Run `slock-computer login` in a terminal first, then re-run setup with --yes."
1724
- );
1809
+ if (await refreshSession(slockHome, opts.serverUrl)) {
1810
+ info("User session: refreshed.");
1811
+ } else {
1812
+ if (!isTty) {
1813
+ fail(
1814
+ "NON_INTERACTIVE_SETUP_REQUIRES_FLAGS",
1815
+ "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."
1816
+ );
1817
+ }
1818
+ info("User session: missing or expired; starting login.");
1819
+ await login({ serverUrl: opts.serverUrl });
1725
1820
  }
1726
- await login({ serverUrl: opts.serverUrl });
1727
1821
  } else {
1728
1822
  info("User session: already logged in.");
1729
1823
  }
@@ -1786,11 +1880,22 @@ async function runSetup(opts, deps = {}) {
1786
1880
 
1787
1881
  // src/status.ts
1788
1882
  import { readFile as readFile7 } from "fs/promises";
1789
- async function readJsonSafe(path2) {
1883
+ async function readUserSession(path2) {
1790
1884
  try {
1791
- return JSON.parse(await readFile7(path2, "utf8"));
1792
- } catch {
1793
- return null;
1885
+ const parsed = JSON.parse(await readFile7(path2, "utf8"));
1886
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1887
+ return { state: "present", session: parsed, error: null };
1888
+ }
1889
+ return { state: "invalid", session: null, error: "not a JSON object" };
1890
+ } catch (err) {
1891
+ if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
1892
+ return { state: "missing", session: null, error: null };
1893
+ }
1894
+ return {
1895
+ state: "invalid",
1896
+ session: null,
1897
+ error: err instanceof Error ? err.message : String(err)
1898
+ };
1794
1899
  }
1795
1900
  }
1796
1901
  function str(v) {
@@ -1807,7 +1912,8 @@ async function deriveHealth(slockHome, serverId, daemon) {
1807
1912
  }
1808
1913
  async function buildStatusReport() {
1809
1914
  const slockHome = resolveSlockHome();
1810
- const session = await readJsonSafe(userSessionPath(slockHome));
1915
+ const sessionRead = await readUserSession(userSessionPath(slockHome));
1916
+ const session = sessionRead.session;
1811
1917
  const attachments = await listServerAttachments(slockHome);
1812
1918
  const supervisor = {
1813
1919
  ...await pidStatus(supervisorPidPath(slockHome)),
@@ -1833,6 +1939,7 @@ async function buildStatusReport() {
1833
1939
  loggedIn,
1834
1940
  userId: session ? str(session.userId) : null,
1835
1941
  loginServerUrl: session ? str(session.serverUrl) : null,
1942
+ userSessionError: sessionRead.state === "invalid" ? sessionRead.error : null,
1836
1943
  supervisor,
1837
1944
  servers
1838
1945
  };
@@ -1848,8 +1955,9 @@ async function runStatus(opts) {
1848
1955
  }
1849
1956
  info("");
1850
1957
  info(`SLOCK_HOME: ${report.slockHome}`);
1958
+ 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
1959
  info(
1852
- `Logged in: ${report.loggedIn ? `yes (user ${report.userId ?? "?"})` : "no \u2014 run `slock-computer login`"}`
1960
+ `Logged in: ${loginDetail}`
1853
1961
  );
1854
1962
  if (report.loginServerUrl) info(`Login server: ${report.loginServerUrl}`);
1855
1963
  info(
@@ -2028,7 +2136,7 @@ async function runDoctorChecks() {
2028
2136
  const checks = [];
2029
2137
  checks.push({ name: "SLOCK_HOME", ok: true, detail: report.slockHome });
2030
2138
  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`" }
2139
+ 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
2140
  );
2033
2141
  checks.push(
2034
2142
  report.supervisor.running ? { name: "supervisor", ok: true, detail: `running (pid ${report.supervisor.pid})` } : {
@@ -2171,13 +2279,13 @@ async function runLogs(opts) {
2171
2279
 
2172
2280
  // src/concurrency.ts
2173
2281
  import lockfile from "proper-lockfile";
2174
- import { mkdir as mkdir8 } from "fs/promises";
2282
+ import { mkdir as mkdir9 } from "fs/promises";
2175
2283
  import { join as join4 } from "path";
2176
2284
  var STALE_LOCK_THRESHOLD_MS = 6e4;
2177
2285
  async function withMutationLock(fn) {
2178
2286
  const slockHome = resolveSlockHome();
2179
2287
  const lockTarget = computerDir(slockHome);
2180
- await mkdir8(lockTarget, { recursive: true });
2288
+ await mkdir9(lockTarget, { recursive: true });
2181
2289
  const lockfilePath = join4(lockTarget, ".lock");
2182
2290
  let release = null;
2183
2291
  try {
@@ -2215,8 +2323,8 @@ async function withMutationLock(fn) {
2215
2323
  }
2216
2324
 
2217
2325
  // src/channel.ts
2218
- import { readFile as readFile9, writeFile as writeFile7, mkdir as mkdir9 } from "fs/promises";
2219
- import { dirname as dirname8 } from "path";
2326
+ import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir10 } from "fs/promises";
2327
+ import { dirname as dirname9 } from "path";
2220
2328
  var DEFAULT_CHANNEL = "latest";
2221
2329
  var SEMVER_RE = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
2222
2330
  function parseChannel(raw) {
@@ -2240,8 +2348,8 @@ async function readChannel(slockHome) {
2240
2348
  }
2241
2349
  async function writeChannel(slockHome, channel2) {
2242
2350
  const p = channelPath(slockHome);
2243
- await mkdir9(dirname8(p), { recursive: true });
2244
- await writeFile7(p, `${channel2}
2351
+ await mkdir10(dirname9(p), { recursive: true });
2352
+ await writeFile8(p, `${channel2}
2245
2353
  `, { mode: 384 });
2246
2354
  }
2247
2355
  async function runChannelShow(slockHome) {
@@ -2265,11 +2373,11 @@ async function runChannelSet(slockHome, raw) {
2265
2373
  // src/upgradeCli.ts
2266
2374
  import { readFile as readFile12 } from "fs/promises";
2267
2375
  import { fileURLToPath as fileURLToPath2 } from "url";
2268
- import { dirname as dirname9, join as join7 } from "path";
2376
+ import { dirname as dirname10, join as join7 } from "path";
2269
2377
 
2270
2378
  // src/upgrade.ts
2271
2379
  import { spawn as spawn4 } from "child_process";
2272
- import { mkdir as mkdir10, readFile as readFile11, writeFile as writeFile8, rm as rm2, rename as rename3 } from "fs/promises";
2380
+ import { mkdir as mkdir11, readFile as readFile11, writeFile as writeFile9, rm as rm3, rename as rename4 } from "fs/promises";
2273
2381
  import { join as join6 } from "path";
2274
2382
  import { createHash as createHash3 } from "crypto";
2275
2383
 
@@ -2540,14 +2648,11 @@ function satisfiesTilde(ver, base) {
2540
2648
  }
2541
2649
 
2542
2650
  // src/upgrade.ts
2543
- function upgradeStagingDir(slockHome, version) {
2544
- return join6(computerDir(slockHome), "upgrade-staging", version);
2545
- }
2546
2651
  async function stagePhase(slockHome, version, deps = {}) {
2547
2652
  const npmPack = deps.npmPack ?? defaultNpmPack;
2548
2653
  const fsReadFile = deps.fsReadFile ?? readFile11;
2549
2654
  const stagedPath = upgradeStagingDir(slockHome, version);
2550
- await mkdir10(stagedPath, { recursive: true });
2655
+ await mkdir11(stagedPath, { recursive: true });
2551
2656
  const packageRef = `@slock-ai/computer@${version}`;
2552
2657
  const result = await npmPack(stagedPath, packageRef);
2553
2658
  if (result.exitCode !== 0) {
@@ -2648,19 +2753,16 @@ async function defaultFetchAdvertisedHash(version) {
2648
2753
  }
2649
2754
  async function cleanupStaged(slockHome, version) {
2650
2755
  try {
2651
- await rm2(upgradeStagingDir(slockHome, version), { recursive: true, force: true });
2756
+ await rm3(upgradeStagingDir(slockHome, version), { recursive: true, force: true });
2652
2757
  } catch {
2653
2758
  }
2654
2759
  }
2655
- function upgradeSnapshotPath(slockHome) {
2656
- return join6(computerDir(slockHome), "upgrade-snapshot.json");
2657
- }
2658
2760
  async function snapshotPhase(slockHome, snap) {
2659
2761
  const path2 = upgradeSnapshotPath(slockHome);
2660
2762
  const tmp = `${path2}.tmp`;
2661
- await mkdir10(computerDir(slockHome), { recursive: true });
2662
- await writeFile8(tmp, JSON.stringify(snap, null, 2), { mode: 384 });
2663
- await rename3(tmp, path2);
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 mkdir10(destDir, { recursive: true });
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 ?? rename3;
2704
- const fsRm = deps.fsRm ?? ((p) => rm2(p, { recursive: true, force: true }));
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 ?? rename3;
2727
- const fsRm = deps.fsRm ?? ((p) => rm2(p, { recursive: true, force: true }));
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 rm2(prevBinaryDir, { recursive: true, force: true });
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 dirname9(dirname9(here));
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 mkdir11, readdir as readdir4, stat as stat3, writeFile as writeFile9 } from "fs/promises";
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 writeFile9(join8(cwd, filename), tarballBytes);
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 mkdir11(join8(destDir, "package"), { recursive: true });
3446
- await writeFile9(join8(destDir, "package", "marker.txt"), `NEW@${targetVersion}`);
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 mkdir11(snapshotPath, { recursive: true });
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 mkdir11(slockHome, { recursive: true });
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 mkdir11(upgradeOpts.currentBinaryDir, { recursive: true });
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 mkdir12, readFile as readFile13 } from "fs/promises";
3705
+ import { copyFile, mkdir as mkdir13, readFile as readFile13 } from "fs/promises";
3604
3706
  import { createHash as createHash5 } from "crypto";
3605
- import { dirname as dirname10, isAbsolute, join as join9, resolve as pathResolve } from "path";
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 mkdir12(slockHome, { recursive: true });
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 dirname10(dirname10(here));
3781
+ return dirname11(dirname11(here));
3680
3782
  }
3681
3783
  async function defaultCurrentVersionLocal() {
3682
3784
  const pkgPath = join9(defaultCurrentBinaryDirLocal(), "package.json");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slock-ai/computer",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
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": {