@instafy/cli 0.1.7 → 0.1.8-staging.348
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/README.md +7 -1
- package/dist/api.js +3 -1
- package/dist/auth.js +112 -0
- package/dist/config-command.js +104 -0
- package/dist/config.js +111 -0
- package/dist/errors.js +10 -0
- package/dist/git-credential.js +201 -0
- package/dist/git-setup.js +56 -0
- package/dist/git.js +4 -1
- package/dist/index.js +260 -15
- package/dist/org.js +5 -18
- package/dist/project.js +11 -24
- package/dist/runtime.js +266 -57
- package/dist/tunnel.js +300 -13
- package/package.json +2 -1
package/dist/runtime.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2
2
|
import { existsSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import kleur from "kleur";
|
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
import { ensureRatholeBinary } from "./rathole.js";
|
|
9
|
+
import { resolveConfiguredAccessToken } from "./config.js";
|
|
9
10
|
const INSTAFY_DIR = path.join(os.homedir(), ".instafy");
|
|
10
11
|
const STATE_FILE = path.join(INSTAFY_DIR, "cli-runtime-state.json");
|
|
11
12
|
const LOG_DIR = path.join(INSTAFY_DIR, "cli-runtime-logs");
|
|
@@ -27,7 +28,82 @@ function resolveRuntimeBinary() {
|
|
|
27
28
|
return candidate;
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
|
-
throw new Error("runtime-agent binary not found.
|
|
31
|
+
throw new Error("runtime-agent binary not found. If you're in the instafy repo, run `cargo build -p runtime-agent`. Otherwise install Docker and rerun `instafy runtime:start`.");
|
|
32
|
+
}
|
|
33
|
+
function tryResolveRuntimeBinary() {
|
|
34
|
+
try {
|
|
35
|
+
return resolveRuntimeBinary();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isDockerAvailable() {
|
|
42
|
+
try {
|
|
43
|
+
const result = spawnSync("docker", ["version"], { stdio: "ignore" });
|
|
44
|
+
return result.status === 0;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function normalizeControllerUrlForDocker(controllerUrl) {
|
|
51
|
+
const trimmed = controllerUrl.trim().replace(/\/$/, "");
|
|
52
|
+
if (!trimmed) {
|
|
53
|
+
return trimmed;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const url = new URL(trimmed);
|
|
57
|
+
const host = url.hostname.toLowerCase();
|
|
58
|
+
if (host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "0.0.0.0") {
|
|
59
|
+
url.hostname = "host.docker.internal";
|
|
60
|
+
}
|
|
61
|
+
return url.toString().replace(/\/$/, "");
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return trimmed
|
|
65
|
+
.replace("127.0.0.1", "host.docker.internal")
|
|
66
|
+
.replace("localhost", "host.docker.internal")
|
|
67
|
+
.replace("0.0.0.0", "host.docker.internal")
|
|
68
|
+
.replace(/\/$/, "");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function resolveRuntimeAgentImage() {
|
|
72
|
+
const fromEnv = normalizeToken(process.env["INSTAFY_RUNTIME_AGENT_IMAGE"]) ??
|
|
73
|
+
normalizeToken(process.env["RUNTIME_AGENT_IMAGE"]) ??
|
|
74
|
+
null;
|
|
75
|
+
return fromEnv ?? "ghcr.io/instafy-dev/instafy-runtime-agent:latest";
|
|
76
|
+
}
|
|
77
|
+
function dockerContainerRunning(containerId) {
|
|
78
|
+
const id = containerId.trim();
|
|
79
|
+
if (!id) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const result = spawnSync("docker", ["inspect", "-f", "{{.State.Running}}", id], {
|
|
84
|
+
encoding: "utf8",
|
|
85
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
86
|
+
});
|
|
87
|
+
if (result.status !== 0) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return String(result.stdout ?? "").trim() === "true";
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function stopDockerContainer(containerId) {
|
|
97
|
+
const id = containerId.trim();
|
|
98
|
+
if (!id) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
spawnSync("docker", ["rm", "-f", id], { stdio: "ignore" });
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// ignore
|
|
106
|
+
}
|
|
31
107
|
}
|
|
32
108
|
function printStatus(label, value) {
|
|
33
109
|
console.log(`${kleur.cyan(label)} ${value}`);
|
|
@@ -131,6 +207,14 @@ function findRatholeOnPath() {
|
|
|
131
207
|
}
|
|
132
208
|
return null;
|
|
133
209
|
}
|
|
210
|
+
function resolveControllerAccessTokenForCli(options, env, supabaseAccessToken) {
|
|
211
|
+
return (normalizeToken(options.controllerAccessToken) ??
|
|
212
|
+
normalizeToken(env["INSTAFY_ACCESS_TOKEN"]) ??
|
|
213
|
+
normalizeToken(env["CONTROLLER_ACCESS_TOKEN"]) ??
|
|
214
|
+
supabaseAccessToken ??
|
|
215
|
+
normalizeToken(env["SUPABASE_ACCESS_TOKEN"]) ??
|
|
216
|
+
resolveConfiguredAccessToken());
|
|
217
|
+
}
|
|
134
218
|
export async function resolveRatholeBinaryForCli(options) {
|
|
135
219
|
const warn = options.warn ??
|
|
136
220
|
((message) => {
|
|
@@ -212,33 +296,34 @@ function isProcessAlive(pid) {
|
|
|
212
296
|
}
|
|
213
297
|
}
|
|
214
298
|
export async function runtimeStart(options) {
|
|
215
|
-
const bin = resolveRuntimeBinary();
|
|
216
299
|
const env = { ...process.env };
|
|
217
300
|
const existing = readState();
|
|
218
|
-
if (existing
|
|
219
|
-
|
|
301
|
+
if (existing) {
|
|
302
|
+
if (existing.runner === "docker" && existing.containerId && dockerContainerRunning(existing.containerId)) {
|
|
303
|
+
throw new Error(`Runtime already running (docker container ${existing.containerId}) for project ${existing.projectId}. Stop it first.`);
|
|
304
|
+
}
|
|
305
|
+
if ((!existing.runner || existing.runner === "process") && isProcessAlive(existing.pid)) {
|
|
306
|
+
throw new Error(`Runtime already running (pid ${existing.pid}) for project ${existing.projectId}. Stop it first.`);
|
|
307
|
+
}
|
|
220
308
|
}
|
|
221
|
-
const manifestInfo = findProjectManifest(
|
|
309
|
+
const manifestInfo = findProjectManifest(process.cwd());
|
|
222
310
|
const projectId = options.project ?? env["PROJECT_ID"] ?? manifestInfo.manifest?.projectId ?? null;
|
|
223
311
|
if (!projectId) {
|
|
224
|
-
throw new Error("
|
|
312
|
+
throw new Error("No project configured. Run `instafy project:init` in this folder (recommended) or pass --project.");
|
|
225
313
|
}
|
|
226
314
|
env["PROJECT_ID"] = projectId;
|
|
227
315
|
const supabaseAccessToken = resolveSupabaseAccessToken(options, env);
|
|
228
316
|
if (supabaseAccessToken) {
|
|
229
317
|
env["SUPABASE_ACCESS_TOKEN"] = supabaseAccessToken;
|
|
230
318
|
}
|
|
231
|
-
let controllerAccessToken =
|
|
232
|
-
normalizeToken(env["INSTAFY_ACCESS_TOKEN"]) ??
|
|
233
|
-
normalizeToken(env["CONTROLLER_ACCESS_TOKEN"]) ??
|
|
234
|
-
supabaseAccessToken;
|
|
319
|
+
let controllerAccessToken = resolveControllerAccessTokenForCli(options, env, supabaseAccessToken);
|
|
235
320
|
let runtimeAccessToken = normalizeToken(options.runtimeToken) ?? normalizeToken(env["RUNTIME_ACCESS_TOKEN"]);
|
|
236
321
|
const agentKey = options.controllerToken ??
|
|
237
322
|
env["INSTAFY_SERVICE_TOKEN"] ??
|
|
238
323
|
env["AGENT_LOGIN_KEY"] ??
|
|
239
324
|
env["AGENT_KEY"];
|
|
240
325
|
if (!agentKey && !controllerAccessToken && !runtimeAccessToken) {
|
|
241
|
-
throw new Error("
|
|
326
|
+
throw new Error("Login required. Run `instafy login`, or pass --access-token / --supabase-access-token, or provide --runtime-token.");
|
|
242
327
|
}
|
|
243
328
|
if (agentKey) {
|
|
244
329
|
env["AGENT_LOGIN_KEY"] = agentKey;
|
|
@@ -250,6 +335,7 @@ export async function runtimeStart(options) {
|
|
|
250
335
|
options.controllerUrl ??
|
|
251
336
|
env["INSTAFY_SERVER_URL"] ??
|
|
252
337
|
env["CONTROLLER_BASE_URL"] ??
|
|
338
|
+
manifestInfo.manifest?.controllerUrl ??
|
|
253
339
|
"http://127.0.0.1:8788";
|
|
254
340
|
if (!runtimeAccessToken && controllerAccessToken) {
|
|
255
341
|
runtimeAccessToken = await mintRuntimeAccessToken({
|
|
@@ -320,47 +406,123 @@ export async function runtimeStart(options) {
|
|
|
320
406
|
if (options.runtimeLeaseId && options.runtimeLeaseId.trim()) {
|
|
321
407
|
env["RUNTIME_LEASE_ID"] = options.runtimeLeaseId.trim();
|
|
322
408
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
409
|
+
const runtimeMode = (options.runtimeMode ?? "auto").toLowerCase();
|
|
410
|
+
const runtimeBin = runtimeMode === "docker" ? null : tryResolveRuntimeBinary();
|
|
411
|
+
const useDocker = runtimeMode === "docker" ||
|
|
412
|
+
(runtimeMode === "auto" && !runtimeBin);
|
|
413
|
+
if (!useDocker) {
|
|
414
|
+
if (!env["ORIGIN_ENDPOINT"]) {
|
|
415
|
+
const ratholeResolved = await resolveRatholeBinaryForCli({
|
|
416
|
+
env,
|
|
417
|
+
version: process.env["RATHOLE_VERSION"] ?? null,
|
|
418
|
+
cacheDir: process.env["RATHOLE_CACHE_DIR"] ?? null,
|
|
419
|
+
logger: (message) => console.log(kleur.cyan(`[rathole] ${message}`)),
|
|
420
|
+
warn: (message) => console.warn(kleur.yellow(message)),
|
|
421
|
+
});
|
|
422
|
+
if (!ratholeResolved) {
|
|
423
|
+
throw new Error("Tunnel is required but rathole is unavailable. Set RATHOLE_BIN (recommended) or pass --origin-endpoint to use a reachable URL.");
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const bin = runtimeBin ?? resolveRuntimeBinary();
|
|
427
|
+
printStatus("Starting runtime-agent:", bin);
|
|
428
|
+
printStatus("Project:", projectId);
|
|
429
|
+
printStatus("Workspace:", workspace);
|
|
430
|
+
printStatus("Origin:", originId);
|
|
431
|
+
const detached = Boolean(options.detach);
|
|
432
|
+
const logFile = options.logFile?.trim()
|
|
433
|
+
? path.resolve(options.logFile)
|
|
434
|
+
: detached
|
|
435
|
+
? path.join(LOG_DIR, `runtime-${Date.now()}.log`)
|
|
436
|
+
: undefined;
|
|
437
|
+
if (logFile) {
|
|
438
|
+
ensureLogDir();
|
|
439
|
+
}
|
|
440
|
+
let stdio;
|
|
441
|
+
if (!logFile && !detached) {
|
|
442
|
+
stdio = "inherit";
|
|
333
443
|
}
|
|
444
|
+
else {
|
|
445
|
+
const out = logFile ? openSync(logFile, "a") : "ignore";
|
|
446
|
+
stdio = ["ignore", out, out];
|
|
447
|
+
}
|
|
448
|
+
const spawnOptions = { env, stdio, detached };
|
|
449
|
+
const child = spawn(bin, spawnOptions);
|
|
450
|
+
if (detached) {
|
|
451
|
+
child.unref();
|
|
452
|
+
}
|
|
453
|
+
const startedAt = new Date().toISOString();
|
|
454
|
+
writeState({
|
|
455
|
+
runner: "process",
|
|
456
|
+
pid: child.pid ?? -1,
|
|
457
|
+
projectId,
|
|
458
|
+
workspace,
|
|
459
|
+
controllerUrl: env["CONTROLLER_BASE_URL"],
|
|
460
|
+
originId,
|
|
461
|
+
runtimeId: env["RUNTIME_ID"] ?? null,
|
|
462
|
+
displayName: env["RUNTIME_DISPLAY_NAME"],
|
|
463
|
+
startedAt,
|
|
464
|
+
logFile,
|
|
465
|
+
detached,
|
|
466
|
+
});
|
|
467
|
+
child.on("exit", (code, signal) => {
|
|
468
|
+
const msg = code !== null ? `code ${code}` : `signal ${signal}`;
|
|
469
|
+
console.log(kleur.yellow(`runtime-agent exited (${msg})`));
|
|
470
|
+
const current = readState();
|
|
471
|
+
if (current && current.pid === child.pid) {
|
|
472
|
+
clearState();
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
return;
|
|
334
476
|
}
|
|
335
|
-
|
|
477
|
+
if (!isDockerAvailable()) {
|
|
478
|
+
throw new Error("runtime-agent is not available (no local binary and docker is not installed). Install Docker Desktop, or build runtime-agent from source.");
|
|
479
|
+
}
|
|
480
|
+
const image = resolveRuntimeAgentImage();
|
|
481
|
+
const containerName = `instafy-runtime-${originId}`;
|
|
482
|
+
const hostPort = String(options.bindPort ?? env["ORIGIN_BIND_PORT"] ?? 54332);
|
|
483
|
+
const hostBindHost = options.bindHost ?? "127.0.0.1";
|
|
484
|
+
const dockerEnv = { ...env };
|
|
485
|
+
dockerEnv["WORKSPACE_DIR"] = "/workspace";
|
|
486
|
+
dockerEnv["CODEX_HOME"] = "/workspace/.codex";
|
|
487
|
+
dockerEnv["ORIGIN_BIND_HOST"] = "0.0.0.0";
|
|
488
|
+
dockerEnv["CONTROLLER_BASE_URL"] = normalizeControllerUrlForDocker(env["CONTROLLER_BASE_URL"] ?? "");
|
|
489
|
+
const envArgs = [];
|
|
490
|
+
for (const [key, value] of Object.entries(dockerEnv)) {
|
|
491
|
+
if (typeof value !== "string" || value.length === 0)
|
|
492
|
+
continue;
|
|
493
|
+
envArgs.push("-e", `${key}=${value}`);
|
|
494
|
+
}
|
|
495
|
+
const runArgs = [
|
|
496
|
+
"run",
|
|
497
|
+
"--detach",
|
|
498
|
+
"--name",
|
|
499
|
+
containerName,
|
|
500
|
+
"--add-host",
|
|
501
|
+
"host.docker.internal:host-gateway",
|
|
502
|
+
"-p",
|
|
503
|
+
`${hostBindHost}:${hostPort}:${hostPort}`,
|
|
504
|
+
"-v",
|
|
505
|
+
`${workspace}:/workspace`,
|
|
506
|
+
...envArgs,
|
|
507
|
+
image,
|
|
508
|
+
];
|
|
509
|
+
printStatus("Starting runtime-agent (docker):", image);
|
|
336
510
|
printStatus("Project:", projectId);
|
|
337
511
|
printStatus("Workspace:", workspace);
|
|
338
512
|
printStatus("Origin:", originId);
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
:
|
|
343
|
-
? path.join(LOG_DIR, `runtime-${Date.now()}.log`)
|
|
344
|
-
: undefined;
|
|
345
|
-
if (logFile) {
|
|
346
|
-
ensureLogDir();
|
|
347
|
-
}
|
|
348
|
-
let stdio;
|
|
349
|
-
if (!logFile && !detached) {
|
|
350
|
-
stdio = "inherit";
|
|
513
|
+
const started = spawnSync("docker", runArgs, { encoding: "utf8" });
|
|
514
|
+
if (started.status !== 0) {
|
|
515
|
+
const stderr = String(started.stderr ?? "").trim();
|
|
516
|
+
throw new Error(`docker run failed: ${stderr || "unknown error"}`);
|
|
351
517
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
const spawnOptions = { env, stdio, detached };
|
|
357
|
-
const child = spawn(bin, spawnOptions);
|
|
358
|
-
if (detached) {
|
|
359
|
-
child.unref();
|
|
518
|
+
const containerId = String(started.stdout ?? "").trim();
|
|
519
|
+
if (!containerId) {
|
|
520
|
+
throw new Error("docker run did not return a container id");
|
|
360
521
|
}
|
|
361
522
|
const startedAt = new Date().toISOString();
|
|
362
523
|
writeState({
|
|
363
|
-
|
|
524
|
+
runner: "docker",
|
|
525
|
+
pid: -1,
|
|
364
526
|
projectId,
|
|
365
527
|
workspace,
|
|
366
528
|
controllerUrl: env["CONTROLLER_BASE_URL"],
|
|
@@ -368,22 +530,40 @@ export async function runtimeStart(options) {
|
|
|
368
530
|
runtimeId: env["RUNTIME_ID"] ?? null,
|
|
369
531
|
displayName: env["RUNTIME_DISPLAY_NAME"],
|
|
370
532
|
startedAt,
|
|
371
|
-
|
|
372
|
-
|
|
533
|
+
detached: Boolean(options.detach),
|
|
534
|
+
containerId,
|
|
535
|
+
containerName,
|
|
373
536
|
});
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
console.log(kleur.
|
|
537
|
+
if (options.detach) {
|
|
538
|
+
printStatus("Container:", containerId);
|
|
539
|
+
console.log(kleur.gray(`Use: docker logs -f ${containerId}`));
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const logs = spawn("docker", ["logs", "-f", containerId], { stdio: "inherit" });
|
|
543
|
+
const handleExit = async () => {
|
|
544
|
+
stopDockerContainer(containerId);
|
|
377
545
|
const current = readState();
|
|
378
|
-
if (current
|
|
546
|
+
if (current?.containerId === containerId) {
|
|
379
547
|
clearState();
|
|
380
548
|
}
|
|
549
|
+
};
|
|
550
|
+
process.once("SIGINT", () => {
|
|
551
|
+
void handleExit();
|
|
552
|
+
});
|
|
553
|
+
process.once("SIGTERM", () => {
|
|
554
|
+
void handleExit();
|
|
555
|
+
});
|
|
556
|
+
logs.on("exit", () => {
|
|
557
|
+
void handleExit();
|
|
381
558
|
});
|
|
382
559
|
}
|
|
383
560
|
function formatStatus(state, running) {
|
|
384
561
|
return {
|
|
385
562
|
running,
|
|
563
|
+
runner: state.runner ?? "process",
|
|
386
564
|
pid: state.pid,
|
|
565
|
+
containerId: state.containerId ?? null,
|
|
566
|
+
containerName: state.containerName ?? null,
|
|
387
567
|
projectId: state.projectId,
|
|
388
568
|
workspace: state.workspace,
|
|
389
569
|
controllerUrl: state.controllerUrl ?? null,
|
|
@@ -404,7 +584,8 @@ async function sendOfflineBeat(state) {
|
|
|
404
584
|
let bearer = directToken;
|
|
405
585
|
if (!bearer) {
|
|
406
586
|
const controllerAccessToken = normalizeToken(process.env["CONTROLLER_ACCESS_TOKEN"]) ??
|
|
407
|
-
normalizeToken(process.env["SUPABASE_ACCESS_TOKEN"])
|
|
587
|
+
normalizeToken(process.env["SUPABASE_ACCESS_TOKEN"]) ??
|
|
588
|
+
resolveConfiguredAccessToken();
|
|
408
589
|
if (controllerAccessToken) {
|
|
409
590
|
try {
|
|
410
591
|
bearer = await mintRuntimeAccessToken({
|
|
@@ -465,14 +646,25 @@ export async function runtimeStatus(options) {
|
|
|
465
646
|
}
|
|
466
647
|
return;
|
|
467
648
|
}
|
|
468
|
-
const alive =
|
|
649
|
+
const alive = state.runner === "docker"
|
|
650
|
+
? Boolean(state.containerId && dockerContainerRunning(state.containerId))
|
|
651
|
+
: isProcessAlive(state.pid);
|
|
469
652
|
const payload = formatStatus(state, alive);
|
|
470
653
|
if (options?.json) {
|
|
471
654
|
console.log(JSON.stringify(payload));
|
|
472
655
|
return;
|
|
473
656
|
}
|
|
474
657
|
console.log(alive ? kleur.green("Runtime is running") : kleur.red("Runtime is not running"));
|
|
475
|
-
printStatus("
|
|
658
|
+
printStatus("Runner:", state.runner ?? "process");
|
|
659
|
+
if (state.runner === "docker") {
|
|
660
|
+
if (state.containerId)
|
|
661
|
+
printStatus("Container:", state.containerId);
|
|
662
|
+
if (state.containerName)
|
|
663
|
+
printStatus("Name:", state.containerName);
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
printStatus("PID:", String(state.pid));
|
|
667
|
+
}
|
|
476
668
|
printStatus("Project:", state.projectId);
|
|
477
669
|
printStatus("Workspace:", state.workspace);
|
|
478
670
|
if (state.controllerUrl)
|
|
@@ -482,13 +674,13 @@ export async function runtimeStatus(options) {
|
|
|
482
674
|
if (state.runtimeId)
|
|
483
675
|
printStatus("Runtime:", state.runtimeId);
|
|
484
676
|
if (state.displayName)
|
|
485
|
-
printStatus("
|
|
677
|
+
printStatus("Display:", state.displayName);
|
|
486
678
|
printStatus("Started:", state.startedAt);
|
|
487
679
|
if (state.logFile)
|
|
488
680
|
printStatus("Log:", state.logFile);
|
|
489
681
|
printStatus("Detached:", state.detached ? "yes" : "no");
|
|
490
682
|
if (!alive) {
|
|
491
|
-
console.log(kleur.yellow(
|
|
683
|
+
console.log(kleur.yellow(`State file exists but ${state.runner === "docker" ? "container" : "process"} is not alive.`));
|
|
492
684
|
}
|
|
493
685
|
}
|
|
494
686
|
export async function runtimeStop(options) {
|
|
@@ -502,6 +694,22 @@ export async function runtimeStop(options) {
|
|
|
502
694
|
}
|
|
503
695
|
return;
|
|
504
696
|
}
|
|
697
|
+
if (state.runner === "docker") {
|
|
698
|
+
const running = Boolean(state.containerId && dockerContainerRunning(state.containerId));
|
|
699
|
+
if (state.containerId) {
|
|
700
|
+
stopDockerContainer(state.containerId);
|
|
701
|
+
}
|
|
702
|
+
clearState();
|
|
703
|
+
await sendOfflineBeat(state);
|
|
704
|
+
const result = { stopped: running, containerId: state.containerId ?? null };
|
|
705
|
+
if (options?.json) {
|
|
706
|
+
console.log(JSON.stringify(result));
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
console.log(running ? kleur.green("Runtime stopped.") : kleur.yellow("Runtime not running."));
|
|
710
|
+
}
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
505
713
|
if (!isProcessAlive(state.pid)) {
|
|
506
714
|
clearState();
|
|
507
715
|
if (options?.json) {
|
|
@@ -552,9 +760,10 @@ export async function runtimeToken(options) {
|
|
|
552
760
|
const token = options.controllerAccessToken ??
|
|
553
761
|
process.env["INSTAFY_ACCESS_TOKEN"] ??
|
|
554
762
|
process.env["CONTROLLER_ACCESS_TOKEN"] ??
|
|
555
|
-
process.env["SUPABASE_ACCESS_TOKEN"]
|
|
763
|
+
process.env["SUPABASE_ACCESS_TOKEN"] ??
|
|
764
|
+
resolveConfiguredAccessToken();
|
|
556
765
|
if (!token) {
|
|
557
|
-
throw new Error("
|
|
766
|
+
throw new Error("Login required. Run `instafy login` or pass --access-token / set SUPABASE_ACCESS_TOKEN.");
|
|
558
767
|
}
|
|
559
768
|
const minted = await mintRuntimeAccessToken({
|
|
560
769
|
controllerUrl,
|