@slock-ai/computer 0.0.2 → 0.0.4
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 +97 -23
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -121,15 +121,18 @@ var ComputerAttachClient = class {
|
|
|
121
121
|
resumed: body.resumed === true
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
const code = body && typeof body.code === "string" ? body.code :
|
|
125
|
-
if (res.status === 401
|
|
126
|
-
return { status: "legacy_key_invalid" };
|
|
124
|
+
const code = body && typeof body.code === "string" ? body.code : void 0;
|
|
125
|
+
if (res.status === 401) {
|
|
126
|
+
if (code === "legacy_key_invalid") return { status: "legacy_key_invalid" };
|
|
127
|
+
if (code === "auth_required") return { status: "auth_required" };
|
|
128
|
+
return { status: "unexpected_response", httpStatus: res.status, ...code ? { code } : {} };
|
|
127
129
|
}
|
|
128
130
|
if (res.status === 409 && code === "legacy_machine_key_migrated") {
|
|
129
131
|
return { status: "legacy_machine_key_migrated" };
|
|
130
132
|
}
|
|
131
133
|
if (res.status === 403) return { status: "not_authorized" };
|
|
132
134
|
if (res.status === 404) return { status: "disabled" };
|
|
135
|
+
if (!code) return { status: "unexpected_response", httpStatus: res.status };
|
|
133
136
|
return { status: "error", code };
|
|
134
137
|
}
|
|
135
138
|
/**
|
|
@@ -306,13 +309,22 @@ function fail(code, message, exitCode = 1) {
|
|
|
306
309
|
throw new CliExit(exitCode);
|
|
307
310
|
}
|
|
308
311
|
|
|
312
|
+
// src/serverUrl.ts
|
|
313
|
+
var DEFAULT_SLOCK_SERVER_URL = "https://api.slock.ai";
|
|
314
|
+
function resolveServerUrl(...candidates) {
|
|
315
|
+
for (const candidate of candidates) {
|
|
316
|
+
const value = candidate?.trim();
|
|
317
|
+
if (value) return value;
|
|
318
|
+
}
|
|
319
|
+
return DEFAULT_SLOCK_SERVER_URL;
|
|
320
|
+
}
|
|
321
|
+
|
|
309
322
|
// src/login.ts
|
|
310
323
|
function sleep(ms) {
|
|
311
324
|
return new Promise((r) => setTimeout(r, ms));
|
|
312
325
|
}
|
|
313
326
|
async function runLogin(opts) {
|
|
314
|
-
const baseUrl = (opts.serverUrl
|
|
315
|
-
if (!baseUrl) fail("MISSING_SERVER_URL", "Set SLOCK_SERVER_URL or pass --server-url <url>.");
|
|
327
|
+
const baseUrl = resolveServerUrl(opts.serverUrl, process.env.SLOCK_SERVER_URL);
|
|
316
328
|
const client = new DeviceAuthClient(baseUrl);
|
|
317
329
|
let grant;
|
|
318
330
|
try {
|
|
@@ -482,10 +494,7 @@ async function runAttach(opts) {
|
|
|
482
494
|
`User session at ${sessionFile} is invalid. Re-run \`slock-computer login\`.`
|
|
483
495
|
);
|
|
484
496
|
}
|
|
485
|
-
const baseUrl = (opts.serverUrl
|
|
486
|
-
if (!baseUrl) {
|
|
487
|
-
fail("MISSING_SERVER_URL", "Set SLOCK_SERVER_URL or pass --server-url <url>.");
|
|
488
|
-
}
|
|
497
|
+
const baseUrl = resolveServerUrl(opts.serverUrl, session.serverUrl, process.env.SLOCK_SERVER_URL);
|
|
489
498
|
const client = new ComputerAttachClient(baseUrl, session.accessToken);
|
|
490
499
|
const slugForServer = normalizeServerSlug(opts.serverSlug);
|
|
491
500
|
if (!slugForServer) {
|
|
@@ -682,6 +691,43 @@ async function stopLegacyDaemonByOwnerFile(ownerFile) {
|
|
|
682
691
|
}
|
|
683
692
|
return { attempted: true, pid, outcome: "timed_out" };
|
|
684
693
|
}
|
|
694
|
+
async function readLegacyOwnerEvidence(ownerFile) {
|
|
695
|
+
let raw;
|
|
696
|
+
try {
|
|
697
|
+
raw = await readFile3(ownerFile, "utf8");
|
|
698
|
+
} catch {
|
|
699
|
+
return { ownerFile, reason: "owner_file_absent" };
|
|
700
|
+
}
|
|
701
|
+
let owner;
|
|
702
|
+
try {
|
|
703
|
+
owner = JSON.parse(raw);
|
|
704
|
+
} catch {
|
|
705
|
+
return { ownerFile, reason: "owner_json_unparseable" };
|
|
706
|
+
}
|
|
707
|
+
const pid = typeof owner.pid === "number" ? owner.pid : void 0;
|
|
708
|
+
return {
|
|
709
|
+
ownerFile,
|
|
710
|
+
pid,
|
|
711
|
+
alive: typeof pid === "number" ? isProcessAlive(pid) : void 0,
|
|
712
|
+
startedAt: typeof owner.startedAt === "string" ? owner.startedAt : void 0,
|
|
713
|
+
serverUrl: typeof owner.serverUrl === "string" ? owner.serverUrl : void 0,
|
|
714
|
+
reason: typeof pid === "number" ? void 0 : "owner_json_missing_pid"
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function formatLegacyOwnerEvidence(slockHome, evidence) {
|
|
718
|
+
const fields = [
|
|
719
|
+
`SLOCK_HOME=${slockHome}`,
|
|
720
|
+
`owner=${evidence.ownerFile}`
|
|
721
|
+
];
|
|
722
|
+
if (typeof evidence.pid === "number") {
|
|
723
|
+
fields.push(`pid=${evidence.pid}`);
|
|
724
|
+
if (typeof evidence.alive === "boolean") fields.push(`alive=${evidence.alive}`);
|
|
725
|
+
}
|
|
726
|
+
if (evidence.startedAt) fields.push(`startedAt=${evidence.startedAt}`);
|
|
727
|
+
if (evidence.serverUrl) fields.push(`serverUrl=${evidence.serverUrl}`);
|
|
728
|
+
if (evidence.reason) fields.push(`ownerStatus=${evidence.reason}`);
|
|
729
|
+
return fields.join(" ");
|
|
730
|
+
}
|
|
685
731
|
async function runAdoptLegacy(inputs) {
|
|
686
732
|
const slockHome = resolveSlockHome();
|
|
687
733
|
const sessionFile = userSessionPath(slockHome);
|
|
@@ -700,10 +746,7 @@ async function runAdoptLegacy(inputs) {
|
|
|
700
746
|
`User session at ${sessionFile} is invalid. Re-run \`slock-computer login\`.`
|
|
701
747
|
);
|
|
702
748
|
}
|
|
703
|
-
const baseUrl = (inputs.serverUrl
|
|
704
|
-
if (!baseUrl) {
|
|
705
|
-
fail("MISSING_SERVER_URL", "Set SLOCK_SERVER_URL or pass --server-url <url>.");
|
|
706
|
-
}
|
|
749
|
+
const baseUrl = resolveServerUrl(inputs.serverUrl, session.serverUrl, process.env.SLOCK_SERVER_URL);
|
|
707
750
|
const slugForServer = normalizeServerSlug(inputs.serverSlug);
|
|
708
751
|
if (!slugForServer) {
|
|
709
752
|
fail("ADOPT_NOT_AUTHORIZED", "Server slug must not be empty.");
|
|
@@ -715,6 +758,7 @@ async function runAdoptLegacy(inputs) {
|
|
|
715
758
|
const client = new ComputerAttachClient(baseUrl, session.accessToken);
|
|
716
759
|
const adoptStartedAt = /* @__PURE__ */ new Date();
|
|
717
760
|
const legacyOwnerFile = legacyLockOwnerPath(slockHome, legacy.rawKey);
|
|
761
|
+
const ownerEvidence = await readLegacyOwnerEvidence(legacyOwnerFile);
|
|
718
762
|
const result = await client.adoptLegacy(legacy.rawKey, inputs.name);
|
|
719
763
|
legacy.rawKey = void 0;
|
|
720
764
|
if (result.status === "disabled") {
|
|
@@ -740,7 +784,7 @@ async function runAdoptLegacy(inputs) {
|
|
|
740
784
|
});
|
|
741
785
|
fail(
|
|
742
786
|
"LEGACY_KEY_INVALID",
|
|
743
|
-
|
|
787
|
+
`Server rejected the legacy api key (unknown / wrong server / malformed). Local legacy owner evidence for this key: ${formatLegacyOwnerEvidence(slockHome, ownerEvidence)}. Verify the key came from this SLOCK_HOME and server, or use a fresh isolated SLOCK_HOME for a clean Computer setup.`
|
|
744
788
|
);
|
|
745
789
|
}
|
|
746
790
|
if (result.status === "legacy_machine_key_migrated") {
|
|
@@ -753,7 +797,20 @@ async function runAdoptLegacy(inputs) {
|
|
|
753
797
|
});
|
|
754
798
|
fail(
|
|
755
799
|
"LEGACY_MACHINE_KEY_MIGRATED",
|
|
756
|
-
|
|
800
|
+
`This machine has already been adopted; the legacy key is no longer accepted. Local legacy owner evidence for this key: ${formatLegacyOwnerEvidence(slockHome, ownerEvidence)}. Use \`slock-computer attach\` to add another Computer attachment, or use a fresh isolated SLOCK_HOME for a clean setup.`
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
if (result.status === "auth_required") {
|
|
804
|
+
await appendAdoptionLog(slockHome, {
|
|
805
|
+
mode: legacy.mode,
|
|
806
|
+
redactedPrefix: legacy.redactedPrefix,
|
|
807
|
+
startedAt: adoptStartedAt,
|
|
808
|
+
outcome: "failed",
|
|
809
|
+
failureReason: "auth_required"
|
|
810
|
+
});
|
|
811
|
+
fail(
|
|
812
|
+
"ADOPT_AUTH_REQUIRED",
|
|
813
|
+
`Your Computer user session was rejected by the server before legacy adoption. Local legacy owner evidence for this key: ${formatLegacyOwnerEvidence(slockHome, ownerEvidence)}. Re-run \`slock-computer login\` for this server (use the same \`--server-url\` if not on production), then retry the adopt command. No local Computer state was written.`
|
|
757
814
|
);
|
|
758
815
|
}
|
|
759
816
|
if (result.status === "not_authorized") {
|
|
@@ -769,6 +826,20 @@ async function runAdoptLegacy(inputs) {
|
|
|
769
826
|
"Not authorized to adopt this machine on this server. Check that you are a current member."
|
|
770
827
|
);
|
|
771
828
|
}
|
|
829
|
+
if (result.status === "unexpected_response") {
|
|
830
|
+
await appendAdoptionLog(slockHome, {
|
|
831
|
+
mode: legacy.mode,
|
|
832
|
+
redactedPrefix: legacy.redactedPrefix,
|
|
833
|
+
startedAt: adoptStartedAt,
|
|
834
|
+
outcome: "failed",
|
|
835
|
+
failureReason: result.code ? `unexpected_response_${result.code}` : "unexpected_response_missing_code"
|
|
836
|
+
});
|
|
837
|
+
const responseDetail = result.code ? `status ${result.httpStatus}, code ${result.code}` : `status ${result.httpStatus}, missing error code`;
|
|
838
|
+
fail(
|
|
839
|
+
"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.`
|
|
841
|
+
);
|
|
842
|
+
}
|
|
772
843
|
if (result.status === "error") {
|
|
773
844
|
await appendAdoptionLog(slockHome, {
|
|
774
845
|
mode: legacy.mode,
|
|
@@ -777,7 +848,10 @@ async function runAdoptLegacy(inputs) {
|
|
|
777
848
|
outcome: "failed",
|
|
778
849
|
failureReason: result.code
|
|
779
850
|
});
|
|
780
|
-
fail(
|
|
851
|
+
fail(
|
|
852
|
+
"ADOPT_FAILED",
|
|
853
|
+
`Adoption failed at server exchange (${result.code}). Local legacy owner evidence for this key: ${formatLegacyOwnerEvidence(slockHome, ownerEvidence)}. Confirm the user session is valid, the legacy key belongs to this server/SLOCK_HOME, and the server URL is correct. No local Computer state was written.`
|
|
854
|
+
);
|
|
781
855
|
}
|
|
782
856
|
info(result.resumed ? "Adopted (resumed prior attachment); running preflight\u2026" : "Adopted; running preflight\u2026");
|
|
783
857
|
const pre = await client.preflight(result.apiKey);
|
|
@@ -1663,7 +1737,7 @@ async function runSetup(opts, deps = {}) {
|
|
|
1663
1737
|
if (!opts.adoptLegacy && liveLegacy) {
|
|
1664
1738
|
fail(
|
|
1665
1739
|
"LEGACY_DAEMON_RUNNING",
|
|
1666
|
-
|
|
1740
|
+
`A legacy daemon appears to be running in ${slockHome}, so Computer setup stopped before creating a second attachment. To proceed: try the Computer beta in an isolated home with \`SLOCK_HOME=$HOME/.slock-computer-beta slock-computer setup ${label}\`; or stop the legacy daemon with \`pkill -f slock-daemon && rm -f ~/.slock/daemon.pid\`; or migrate the existing daemon with \`--adopt-legacy --legacy-api-key <key>\`.`
|
|
1667
1741
|
);
|
|
1668
1742
|
}
|
|
1669
1743
|
if (opts.adoptLegacy && hasLegacyKey) {
|
|
@@ -1678,7 +1752,7 @@ async function runSetup(opts, deps = {}) {
|
|
|
1678
1752
|
} else if (opts.adoptLegacy && liveLegacy) {
|
|
1679
1753
|
fail(
|
|
1680
1754
|
"LEGACY_DAEMON_RUNNING",
|
|
1681
|
-
|
|
1755
|
+
`A legacy daemon is running in ${slockHome}, but no legacy key was provided. To proceed: provide --legacy-api-key-file/--legacy-api-key/--legacy-api-key-stdin to adopt it; or stop the legacy daemon with \`pkill -f slock-daemon && rm -f ~/.slock/daemon.pid\`; or use an isolated home with \`SLOCK_HOME=$HOME/.slock-computer-beta slock-computer setup ${label}\` for a clean beta trial.`
|
|
1682
1756
|
);
|
|
1683
1757
|
} else {
|
|
1684
1758
|
if (opts.adoptLegacy) {
|
|
@@ -3634,16 +3708,16 @@ function withCliExit(fn) {
|
|
|
3634
3708
|
};
|
|
3635
3709
|
}
|
|
3636
3710
|
var program = new Command();
|
|
3637
|
-
program.name("slock-computer").description("Slock Computer \u2014 local-machine control plane (login + N per-server attachments).").version("0.0.
|
|
3638
|
-
program.command("login").description("Log in via device-code (one user identity per Computer / SLOCK_HOME).").option("--server-url <url>",
|
|
3711
|
+
program.name("slock-computer").description("Slock Computer \u2014 local-machine control plane (login + N per-server attachments).").version("0.0.3");
|
|
3712
|
+
program.command("login").description("Log in via device-code (one user identity per Computer / SLOCK_HOME).").option("--server-url <url>", `Slock API base URL; defaults to SLOCK_SERVER_URL or ${DEFAULT_SLOCK_SERVER_URL}`).action(withCliExit(async (opts) => {
|
|
3639
3713
|
await runLogin({ serverUrl: opts.serverUrl });
|
|
3640
3714
|
}));
|
|
3641
|
-
program.command("attach").argument("<serverSlug>", "target Slock server slug (canonical form `/myserver`; bare `myserver` accepted)").description("Attach this Computer to one Slock server (add-not-replace; multi-server OK).").option("--server-url <url>",
|
|
3715
|
+
program.command("attach").argument("<serverSlug>", "target Slock server slug (canonical form `/myserver`; bare `myserver` accepted)").description("Attach this Computer to one Slock server (add-not-replace; multi-server OK).").option("--server-url <url>", `Slock API base URL; defaults to the saved user session, SLOCK_SERVER_URL, or ${DEFAULT_SLOCK_SERVER_URL}`).option("--name <name>", "Computer display name; defaults to a sanitized hostname").option("--no-run", "only authorize + write local state; do not start the supervisor").option("--foreground", "run the supervisor in this terminal instead of the background").action(withCliExit(async (serverSlug, opts) => {
|
|
3642
3716
|
await withMutationLock(
|
|
3643
3717
|
() => runAttach({ serverSlug, serverUrl: opts.serverUrl, name: opts.name, run: opts.run, foreground: opts.foreground })
|
|
3644
3718
|
);
|
|
3645
3719
|
}));
|
|
3646
|
-
program.command("setup").argument("<serverSlug>", "target Slock server slug (canonical form `/myserver`; bare `myserver` accepted)").description("Set up this Computer for one server: login if needed, attach/adopt if needed, then start.").option("--server-url <url>",
|
|
3720
|
+
program.command("setup").argument("<serverSlug>", "target Slock server slug (canonical form `/myserver`; bare `myserver` accepted)").description("Set up this Computer for one server: login if needed, attach/adopt if needed, then start.").option("--server-url <url>", `Slock API base URL; defaults to the saved user session, SLOCK_SERVER_URL, or ${DEFAULT_SLOCK_SERVER_URL}`).option("--name <name>", "Computer display name for a new attachment/adoption; defaults to a sanitized hostname").option("--adopt-legacy", "attempt one-time migration from a legacy daemon before fresh attach fallback").option("--legacy-api-key <key>", "legacy key for --adopt-legacy (migration-only; prefer file/stdin)").option("--legacy-api-key-file <path>", "path to a file containing the legacy key for --adopt-legacy").option("--legacy-api-key-stdin", "read the legacy key from stdin for --adopt-legacy").option("--no-start", "stop after login + attach/adopt; do not start the supervisor").option("--foreground", "run the supervisor in this terminal instead of the background").option("-y, --yes", "allow non-interactive setup after confirming the planned actions").action(
|
|
3647
3721
|
withCliExit(async (serverSlug, opts) => {
|
|
3648
3722
|
await withMutationLock(
|
|
3649
3723
|
() => runSetup({
|
|
@@ -3663,7 +3737,7 @@ program.command("setup").argument("<serverSlug>", "target Slock server slug (can
|
|
|
3663
3737
|
);
|
|
3664
3738
|
program.command("adopt-legacy").argument("<serverSlug>", "target Slock server slug (the legacy machine's server)").description(
|
|
3665
3739
|
"One-time migration: trade a legacy sk_machine_* / sk_daemon_* key for a fresh Computer attachment (sk_computer_*)."
|
|
3666
|
-
).option("--server-url <url>",
|
|
3740
|
+
).option("--server-url <url>", `Slock API base URL; defaults to the saved user session, SLOCK_SERVER_URL, or ${DEFAULT_SLOCK_SERVER_URL}`).option("--name <name>", "name to record on the new Computer attachment (default: existing machine name)").option("--legacy-api-key <key>", "raw legacy key on argv (insecure on shared shells; prefer --legacy-api-key-file or stdin)").option("--legacy-api-key-file <path>", "path to a 0600 file containing the legacy key (one line)").option("--legacy-api-key-stdin", "read the legacy key from stdin").action(
|
|
3667
3741
|
withCliExit(async (serverSlug, opts) => {
|
|
3668
3742
|
await withMutationLock(
|
|
3669
3743
|
() => runAdoptLegacy({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slock-ai/computer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
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": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"commander": "^12.1.0",
|
|
22
22
|
"proper-lockfile": "^4.1.2",
|
|
23
23
|
"undici": "^7.24.7",
|
|
24
|
-
"@slock-ai/daemon": "0.
|
|
24
|
+
"@slock-ai/daemon": "0.53.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^25.5.0",
|