@mycadet/cli 0.12.9 → 0.12.11
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/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/package.json +4 -3
- package/src/__tests__/client-web-config.test.ts +0 -1
- package/src/__tests__/cloud-login-poll.test.ts +69 -0
- package/src/__tests__/devices.test.ts +62 -0
- package/src/__tests__/ensure-binary.test.ts +52 -0
- package/src/__tests__/hatch-next-steps.test.ts +38 -0
- package/src/__tests__/multi-local.test.ts +3 -3
- package/src/__tests__/nginx-ingress.test.ts +58 -26
- package/src/__tests__/pair.test.ts +149 -78
- package/src/__tests__/ps-cloud-status.test.ts +6 -4
- package/src/__tests__/setup.test.ts +14 -4
- package/src/__tests__/teleport.test.ts +0 -15
- package/src/__tests__/tunnel-startup-summary.test.ts +110 -0
- package/src/__tests__/tunnel-stop.test.ts +226 -0
- package/src/__tests__/tunnel.test.ts +265 -70
- package/src/__tests__/uninstall.test.ts +140 -8
- package/src/commands/client.ts +4 -6
- package/src/commands/devices.ts +66 -30
- package/src/commands/hatch.ts +14 -53
- package/src/commands/pair.ts +147 -38
- package/src/commands/ps.ts +10 -20
- package/src/commands/teleport.ts +2 -21
- package/src/commands/tunnel.ts +67 -28
- package/src/commands/uninstall.ts +106 -71
- package/src/commands/upgrade.ts +6 -1
- package/src/lib/__tests__/local-gateway-cli.test.ts +42 -0
- package/src/lib/assistant-config.ts +20 -5
- package/src/lib/cloud-client.ts +0 -3
- package/src/lib/cloud-login-poll.ts +75 -0
- package/src/lib/cloud-login.ts +3 -2
- package/src/lib/color.ts +4 -0
- package/src/lib/docker.ts +46 -70
- package/src/lib/ensure-binary.ts +65 -6
- package/src/lib/environments/__tests__/paths.test.ts +27 -1
- package/src/lib/environments/paths.ts +16 -8
- package/src/lib/environments/resolve.ts +2 -4
- package/src/lib/hatch-local.ts +16 -59
- package/src/lib/hatch-next-steps.ts +18 -9
- package/src/lib/live-voice/tunnel.ts +2 -2
- package/src/lib/local.ts +42 -9
- package/src/lib/nginx-ingress.ts +124 -24
- package/src/lib/step-runner.ts +6 -1
- package/src/lib/tunnel.ts +86 -34
- package/src/lib/tunnels/cadet.ts +12 -1
- package/src/lib/tunnels/cloudflare.ts +36 -1
- package/src/lib/tunnels/ngrok.ts +16 -2
- package/src/lib/tunnels/process-lifecycle.ts +26 -0
- package/src/lib/tunnels/tailscale.ts +79 -1
- package/src/lib/xdg-log.ts +11 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { clearIngressUrl } from "../ingress-config.js";
|
|
2
|
+
import { stopProcess } from "../process.js";
|
|
3
|
+
import type { ProviderStopOptions } from "../tunnel.js";
|
|
4
|
+
|
|
5
|
+
/** Stop only an identified provider process and retain state on termination failure. */
|
|
6
|
+
export async function stopOwnedTunnelAgent(
|
|
7
|
+
opts: ProviderStopOptions,
|
|
8
|
+
matches: (pid: number) => boolean,
|
|
9
|
+
label: string,
|
|
10
|
+
): Promise<boolean> {
|
|
11
|
+
let stopped = false;
|
|
12
|
+
if (matches(opts.record.pid)) {
|
|
13
|
+
stopped = await stopProcess(opts.record.pid, "tunnel");
|
|
14
|
+
if (!stopped && matches(opts.record.pid)) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Could not stop ${label} process ${opts.record.pid}; saved tunnel state was retained.`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (opts.workspaceDir)
|
|
21
|
+
clearIngressUrl(
|
|
22
|
+
opts.workspaceDir,
|
|
23
|
+
opts.assistantId ?? opts.record.assistantId,
|
|
24
|
+
);
|
|
25
|
+
return stopped;
|
|
26
|
+
}
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import {
|
|
3
|
+
clearRootProcess,
|
|
4
|
+
readRootProcesses,
|
|
5
|
+
stampRootProcess,
|
|
6
|
+
} from "../assistant-config.js";
|
|
7
|
+
import { readProcessCommandLine, stopProcess } from "../process.js";
|
|
8
|
+
import type {
|
|
9
|
+
TunnelProvider,
|
|
10
|
+
ProviderStopOptions,
|
|
11
|
+
ProviderMeta,
|
|
12
|
+
ProviderTunnelResult,
|
|
13
|
+
} from "../tunnel.js";
|
|
2
14
|
|
|
3
15
|
import { spawnSync } from "node:child_process";
|
|
4
16
|
import { win32 } from "node:path";
|
|
@@ -7,6 +19,7 @@ import { GATEWAY_PORT } from "../constants.js";
|
|
|
7
19
|
import { ensureBinaryInstalled } from "../ensure-binary.js";
|
|
8
20
|
import {
|
|
9
21
|
clearIngressUrl,
|
|
22
|
+
loadRawConfig,
|
|
10
23
|
getDefaultWorkspaceDir,
|
|
11
24
|
readLockfileIngressUrl,
|
|
12
25
|
saveIngressUrl,
|
|
@@ -418,6 +431,16 @@ export async function runTailscaleTunnel(
|
|
|
418
431
|
);
|
|
419
432
|
console.log("or stop it later with: tailscale serve --https=443 off");
|
|
420
433
|
|
|
434
|
+
const previous = opts.preserveIngressUrl
|
|
435
|
+
? readRootProcesses().tunnel
|
|
436
|
+
: undefined;
|
|
437
|
+
stampRootProcess("tunnel", {
|
|
438
|
+
...(previous?.provider !== "tailscale" ? { previous } : {}),
|
|
439
|
+
pid: process.pid,
|
|
440
|
+
provider: "tailscale",
|
|
441
|
+
assistantId: opts.assistantId,
|
|
442
|
+
startedAt: new Date().toISOString(),
|
|
443
|
+
});
|
|
421
444
|
const teardown = (): void => {
|
|
422
445
|
console.log(
|
|
423
446
|
`\nStopping tailscale serve and clearing the ${publishedLabel}...`,
|
|
@@ -441,6 +464,7 @@ export async function runTailscaleTunnel(
|
|
|
441
464
|
);
|
|
442
465
|
}
|
|
443
466
|
if (shouldClearIngressUrl(result)) {
|
|
467
|
+
clearRootProcess("tunnel", process.pid);
|
|
444
468
|
retractServeUrl(opts, workspaceDir, previousLockfileIngressUrl);
|
|
445
469
|
} else {
|
|
446
470
|
console.error(
|
|
@@ -475,3 +499,57 @@ export const TAILSCALE_TUNNEL_META: ProviderMeta = {
|
|
|
475
499
|
],
|
|
476
500
|
supportsReservedDomain: false,
|
|
477
501
|
};
|
|
502
|
+
|
|
503
|
+
const stoppedTailscaleStateSchema = z.object({
|
|
504
|
+
ingress: z
|
|
505
|
+
.object({
|
|
506
|
+
publicBaseUrl: z.string().optional(),
|
|
507
|
+
pairingTunnel: z.object({ provider: z.string() }).optional(),
|
|
508
|
+
})
|
|
509
|
+
.optional(),
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
export async function stopTailscaleTunnel(
|
|
513
|
+
opts: ProviderStopOptions,
|
|
514
|
+
deps: TailscaleDeps = {
|
|
515
|
+
findBinary: async () => probeTailscaleBinary(),
|
|
516
|
+
run: realRun,
|
|
517
|
+
},
|
|
518
|
+
): Promise<boolean> {
|
|
519
|
+
const binary = await deps.findBinary();
|
|
520
|
+
if (!binary) throw new Error(getTailscaleInstallMessage());
|
|
521
|
+
const result = stopTailscaleServe(binary, deps);
|
|
522
|
+
if (result.status !== 0)
|
|
523
|
+
throw new Error(`Could not stop tailscale serve: ${joinOutput(result)}`);
|
|
524
|
+
// The serve belongs to tailscaled; only the Cadet supervisor may be signaled.
|
|
525
|
+
let supervisor = false;
|
|
526
|
+
try {
|
|
527
|
+
const command = readProcessCommandLine(opts.record.pid);
|
|
528
|
+
supervisor =
|
|
529
|
+
/cadet/i.test(command) && /(?:^|\s)tunnel(?:\s|$)/.test(command);
|
|
530
|
+
} catch {
|
|
531
|
+
/* The supervisor may already have exited. */
|
|
532
|
+
}
|
|
533
|
+
if (supervisor && opts.record.pid !== process.pid)
|
|
534
|
+
await stopProcess(opts.record.pid, "tunnel supervisor");
|
|
535
|
+
if (opts.workspaceDir) {
|
|
536
|
+
const state = stoppedTailscaleStateSchema.parse(
|
|
537
|
+
loadRawConfig(opts.workspaceDir),
|
|
538
|
+
).ingress;
|
|
539
|
+
const assistantId = opts.assistantId ?? opts.record.assistantId;
|
|
540
|
+
retractServeUrl(
|
|
541
|
+
{
|
|
542
|
+
assistantId,
|
|
543
|
+
preserveIngressUrl: state?.pairingTunnel?.provider === "tailscale",
|
|
544
|
+
},
|
|
545
|
+
opts.workspaceDir,
|
|
546
|
+
state?.publicBaseUrl ?? null,
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
export const TAILSCALE_PROVIDER: TunnelProvider = {
|
|
553
|
+
run: runTailscaleTunnel,
|
|
554
|
+
stop: stopTailscaleTunnel,
|
|
555
|
+
};
|
package/src/lib/xdg-log.ts
CHANGED
|
@@ -142,3 +142,14 @@ export function pipeToLogFile(
|
|
|
142
142
|
stream.on("error", onDone);
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
|
|
146
|
+
/** Runtime output belongs to the instance, alongside its service state. */
|
|
147
|
+
export function openRuntimeLogFile(instanceDir: string, service: "assistant" | "gateway"): number | "ignore" {
|
|
148
|
+
try {
|
|
149
|
+
const dir = join(instanceDir, "logs");
|
|
150
|
+
mkdirSync(dir, { recursive: true });
|
|
151
|
+
return openSync(join(dir, `${service}-stdout.log`), "a", 0o600);
|
|
152
|
+
} catch {
|
|
153
|
+
return "ignore";
|
|
154
|
+
}
|
|
155
|
+
}
|