mindwire 0.1.38 → 0.1.41
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 +19 -0
- package/dist/chunk-4XNTGVCI.js +306 -0
- package/dist/chunk-4XNTGVCI.js.map +1 -0
- package/dist/{chunk-CKTVMUS4.js → chunk-T2ZIA4TK.js} +50 -16
- package/dist/chunk-T2ZIA4TK.js.map +1 -0
- package/dist/cli.js +525 -251
- package/dist/cli.js.map +1 -1
- package/dist/computer/dashboard.d.ts +1 -0
- package/dist/computer/desktop.d.ts +17 -0
- package/dist/computer/directory-http.d.ts +1 -1
- package/dist/computer/discovery.d.ts +22 -0
- package/dist/computer/inspection.d.ts +30 -0
- package/dist/computer/lifecycle.d.ts +4 -2
- package/dist/computer/runtime-version.d.ts +6 -0
- package/dist/computer/service-update.d.ts +26 -0
- package/dist/computer/setup-prompt.d.ts +2 -0
- package/dist/computer/startup.d.ts +7 -0
- package/dist/computer/terminal-ui.d.ts +9 -0
- package/dist/computer.d.ts +2 -0
- package/dist/{connection-change-5F4WNCYV.js → connection-change-RHY2OKFJ.js} +3 -3
- package/dist/{connection-change-5F4WNCYV.js.map → connection-change-RHY2OKFJ.js.map} +1 -1
- package/dist/{controller-3SZI7TBW.js → controller-G2T76QDM.js} +67 -9
- package/dist/controller-G2T76QDM.js.map +1 -0
- package/dist/{controller-handoff-KV7WRDAI.js → controller-handoff-CDPPQ2YH.js} +3 -3
- package/dist/{controller-handoff-KV7WRDAI.js.map → controller-handoff-CDPPQ2YH.js.map} +1 -1
- package/dist/daemon-binary.d.ts +2 -0
- package/dist/index.cjs +41 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +41 -7
- package/dist/index.js.map +1 -1
- package/dist/project-sync.d.ts +29 -0
- package/dist/surfaces.d.ts +20 -1
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
- package/dist/chunk-CKTVMUS4.js.map +0 -1
- package/dist/chunk-QODJKRFK.js +0 -20
- package/dist/chunk-QODJKRFK.js.map +0 -1
- package/dist/controller-3SZI7TBW.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function computerDashboard(directory: string, run: (args: string[]) => Promise<void>): Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Mindwire } from "../client.js";
|
|
2
|
+
import type { LocalDesktopInfo } from "../surfaces.js";
|
|
3
|
+
import { type SetupPrompt } from "./setup-prompt.js";
|
|
4
|
+
export declare function desktopSummary(info: LocalDesktopInfo): string;
|
|
5
|
+
export declare function openScreenSharingSettings(): void;
|
|
6
|
+
/** All activation happens here, on the Mac. Connecting/refreshing in the phone
|
|
7
|
+
* can only observe this state; it cannot enable sharing or retrieve a password. */
|
|
8
|
+
export declare function manageDesktop(options: {
|
|
9
|
+
client: Mindwire;
|
|
10
|
+
directory: string;
|
|
11
|
+
action?: string;
|
|
12
|
+
interactive: boolean;
|
|
13
|
+
json?: boolean;
|
|
14
|
+
prompt?: SetupPrompt;
|
|
15
|
+
openSettings?: () => void;
|
|
16
|
+
readControlToken?: () => Promise<string>;
|
|
17
|
+
}): Promise<LocalDesktopInfo>;
|
|
@@ -5,4 +5,4 @@ export declare class DirectoryRequestError extends Error {
|
|
|
5
5
|
constructor(status: number, code: string, retryAfter?: number);
|
|
6
6
|
}
|
|
7
7
|
/** Bounded, same-origin requests. No redirects, cookie jar or retained credentials. */
|
|
8
|
-
export declare function directoryRequest<T>(url: string, path: string, body: unknown): Promise<T>;
|
|
8
|
+
export declare function directoryRequest<T>(url: string, path: string, body: unknown, signal?: AbortSignal): Promise<T>;
|
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
import type { Mindwire } from "../client.js";
|
|
2
2
|
import type { ComputerDiscoveryStatus } from "../computer.js";
|
|
3
3
|
import type { SetupPrompt } from "./setup-prompt.js";
|
|
4
|
+
import { type ComputerConfig } from "./lifecycle.js";
|
|
4
5
|
export declare const DIRECTORY_API_PATH = "/api/computer-directory/v1";
|
|
5
6
|
export declare const DIRECTORY_URL = "https://console.mindwire.sh/api/computer-directory/v1";
|
|
7
|
+
export interface DiscoveryPreference {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
url?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const discoveryPreference: (directory: string) => Promise<DiscoveryPreference | undefined>;
|
|
12
|
+
/** Desired setup is durable even if enrollment is temporarily offline. The
|
|
13
|
+
* daemon remains the authority for signed publications and phone access. */
|
|
14
|
+
export declare function saveDiscoveryPreference(directory: string, value: DiscoveryPreference): Promise<void>;
|
|
6
15
|
export declare function directoryURL(value: string): string;
|
|
7
16
|
export declare function enableAddressDiscovery(options: {
|
|
8
17
|
directory: string;
|
|
9
18
|
computer: Mindwire;
|
|
10
19
|
prompt: SetupPrompt;
|
|
11
20
|
url?: string;
|
|
21
|
+
waitForPublication?: boolean;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
reconcile?: boolean;
|
|
12
24
|
}): Promise<ComputerDiscoveryStatus>;
|
|
25
|
+
export declare function disableAddressDiscovery(directory: string, computer: Mindwire, reconcile?: boolean): Promise<ComputerDiscoveryStatus>;
|
|
26
|
+
/** Runs once after startup and retries failed enrollment in the controller. A
|
|
27
|
+
* healthy setup makes only a local status read: publication/renewal stays in Go.
|
|
28
|
+
* Direct/VPN/custom connections never opt into a hosted directory implicitly. */
|
|
29
|
+
export declare function reconcileAddressDiscovery(options: {
|
|
30
|
+
directory: string;
|
|
31
|
+
config: ComputerConfig;
|
|
32
|
+
computer: Mindwire;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
}): Promise<void>;
|
|
13
35
|
export declare function discoveryDescription(status: ComputerDiscoveryStatus | undefined): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ComputerConnectionInfo, ComputerDevice, ComputerDiscoveryStatus, ComputerInfo, ComputerUpdate } from "../computer.js";
|
|
2
|
+
import { type StartupState } from "./startup.js";
|
|
3
|
+
import { type DiscoveryPreference } from "./discovery.js";
|
|
4
|
+
import type { ComputerConnectionChange } from "./connection-change.js";
|
|
5
|
+
export interface ComputerInspection {
|
|
6
|
+
name: string;
|
|
7
|
+
cliVersion: string;
|
|
8
|
+
service: "not-configured" | "stopped" | "starting" | "running" | "unavailable";
|
|
9
|
+
daemonVersion?: string;
|
|
10
|
+
online: boolean;
|
|
11
|
+
startup: StartupState;
|
|
12
|
+
connection?: ComputerConnectionInfo;
|
|
13
|
+
discovery?: ComputerDiscoveryStatus;
|
|
14
|
+
discoveryPreference?: DiscoveryPreference;
|
|
15
|
+
devices: ComputerDevice[];
|
|
16
|
+
update?: ComputerUpdate;
|
|
17
|
+
activeOperations?: number;
|
|
18
|
+
info?: ComputerInfo;
|
|
19
|
+
problem?: string;
|
|
20
|
+
recoveryProblem?: string;
|
|
21
|
+
recovering?: boolean;
|
|
22
|
+
relayError?: string;
|
|
23
|
+
relayErrorCode?: string;
|
|
24
|
+
connectionChange?: Pick<ComputerConnectionChange, "status" | "message">;
|
|
25
|
+
}
|
|
26
|
+
/** Inspection never starts a service or requires it to be reachable. Keep
|
|
27
|
+
* credentials/configuration files out of both human and JSON output. */
|
|
28
|
+
export declare function inspectComputer(directory: string): Promise<ComputerInspection>;
|
|
29
|
+
export declare function recoverySummary(state: ComputerInspection): string;
|
|
30
|
+
export declare function inspectionText(state: ComputerInspection, detailed?: boolean): string;
|
|
@@ -5,6 +5,7 @@ import { type ProcessState } from "./process.js";
|
|
|
5
5
|
export interface ComputerConfig {
|
|
6
6
|
daemonBin?: string;
|
|
7
7
|
version?: string;
|
|
8
|
+
versionPinned?: boolean;
|
|
8
9
|
directory: string;
|
|
9
10
|
host?: string;
|
|
10
11
|
bind: string;
|
|
@@ -12,7 +13,7 @@ export interface ComputerConfig {
|
|
|
12
13
|
websocketPort: number;
|
|
13
14
|
relay: RelayOptions;
|
|
14
15
|
}
|
|
15
|
-
export declare const CONTROLLER_PROTOCOL =
|
|
16
|
+
export declare const CONTROLLER_PROTOCOL = 4;
|
|
16
17
|
export interface ControllerState extends ProcessState {
|
|
17
18
|
protocol?: number;
|
|
18
19
|
cliVersion?: string;
|
|
@@ -25,12 +26,13 @@ export interface ControllerState extends ProcessState {
|
|
|
25
26
|
checkedAt?: number;
|
|
26
27
|
relayFailureSince?: number;
|
|
27
28
|
relayFailures?: number;
|
|
29
|
+
discoveryError?: string;
|
|
28
30
|
}
|
|
29
31
|
export declare const defaultStateDirectory: () => string;
|
|
30
32
|
export declare const defaultComputerConfig: () => ComputerConfig;
|
|
31
33
|
export declare function readJSON<T>(file: string): Promise<T | undefined>;
|
|
32
34
|
export declare function writeJSON(file: string, value: unknown): Promise<void>;
|
|
33
|
-
export declare function computerClient(directory: string): Promise<Mindwire>;
|
|
35
|
+
export declare function computerClient(directory: string, requestTimeoutMs?: number): Promise<Mindwire>;
|
|
34
36
|
export declare function directRoutes(config: ComputerConfig, port: number): ComputerRoute[];
|
|
35
37
|
/** Launch once; the daemon additionally owns an OS file lock over its identity/state. */
|
|
36
38
|
export declare function ensureComputer(directory: string, cliPath: string, patch?: Partial<ComputerConfig>, onProgress?: (message: string) => void, options?: {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ComputerConfig } from "./lifecycle.js";
|
|
2
|
+
/** The saved version is the last installed release, not an accidental permanent
|
|
3
|
+
* pin. Upgrading the CLI must also upgrade its managed service. Never downgrade a
|
|
4
|
+
* newer service or replace an explicitly supplied development binary. */
|
|
5
|
+
export declare function managedServiceVersion(config: ComputerConfig, cliVersion?: string): string;
|
|
6
|
+
export declare function serviceUpgradeVersion(config: ComputerConfig, installed: string, cliVersion?: string): string | undefined;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ComputerUpdate } from "../computer.js";
|
|
2
|
+
import type { Mindwire } from "../client.js";
|
|
3
|
+
type UpdateClient = Pick<Mindwire, "health" | "computer">;
|
|
4
|
+
export declare function activeUpdate(update: ComputerUpdate | undefined): update is ComputerUpdate;
|
|
5
|
+
/** The daemon arbitrates requests. Join an earlier version before requesting the
|
|
6
|
+
* next; promoting a request never creates a second download or bypasses its lease. */
|
|
7
|
+
export declare function queueServiceUpdate(client: UpdateClient, version: string, force?: boolean): Promise<ComputerUpdate>;
|
|
8
|
+
export interface ServiceUpdateResult {
|
|
9
|
+
version: string;
|
|
10
|
+
complete: boolean;
|
|
11
|
+
update?: ComputerUpdate;
|
|
12
|
+
}
|
|
13
|
+
/** A CLI may close after queuing: the controller owns download/restart. Human
|
|
14
|
+
* callers get a bounded result, including the exact older request being joined. */
|
|
15
|
+
export declare function updateComputer(options: {
|
|
16
|
+
directory: string;
|
|
17
|
+
version: string;
|
|
18
|
+
force?: boolean;
|
|
19
|
+
allowDowngrade?: boolean;
|
|
20
|
+
onProgress?: (update: ComputerUpdate) => void;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
connect?: () => Promise<UpdateClient>;
|
|
24
|
+
}): Promise<ServiceUpdateResult>;
|
|
25
|
+
export declare function updateProgress(update: ComputerUpdate): string;
|
|
26
|
+
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { type TerminalChoice } from "./terminal-ui.js";
|
|
1
2
|
export interface SetupPrompt {
|
|
2
3
|
question(text: string): Promise<string>;
|
|
3
4
|
secret(text: string): Promise<string>;
|
|
4
5
|
print(text: string): void;
|
|
5
6
|
open(url: string): void;
|
|
7
|
+
select?<T extends string>(title: string, choices: TerminalChoice<T>[]): Promise<T | undefined>;
|
|
6
8
|
}
|
|
7
9
|
/** No shell interpolation, even for a URL returned by a provider. */
|
|
8
10
|
export declare function openSetupURL(value: string): void;
|
|
@@ -11,10 +11,15 @@ export interface StartupPlan {
|
|
|
11
11
|
export interface StartupState {
|
|
12
12
|
enabled: boolean;
|
|
13
13
|
running?: boolean;
|
|
14
|
+
registered?: boolean;
|
|
14
15
|
kind?: StartupPlan["kind"];
|
|
15
16
|
name?: string;
|
|
16
17
|
file?: string;
|
|
17
18
|
}
|
|
19
|
+
/** Homebrew resolves execPath to a versioned Cellar file. Prefer a stable alias
|
|
20
|
+
* only after verifying it points at this exact interpreter. Never run a different
|
|
21
|
+
* executable just because it appeared first on PATH. */
|
|
22
|
+
export declare function startupExecutable(executable?: string, environmentPath?: string): Promise<string>;
|
|
18
23
|
/** Per-user startup, with no root service, password, or copied pairing secret. */
|
|
19
24
|
export declare function startupPlan(options: {
|
|
20
25
|
directory: string;
|
|
@@ -31,6 +36,8 @@ export declare function configureStartup(directory: string, cliPath: string, ena
|
|
|
31
36
|
plan?: StartupPlan;
|
|
32
37
|
run?: (command: Command) => Promise<void>;
|
|
33
38
|
verify?: () => Promise<void>;
|
|
39
|
+
isRunning?: () => Promise<boolean>;
|
|
40
|
+
repair?: boolean;
|
|
34
41
|
}): Promise<StartupState>;
|
|
35
42
|
/** Native startup managers supervise this small guardian. It adopts an existing
|
|
36
43
|
* controller and honours an explicit stop; it never owns or kills user work. */
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface TerminalChoice<T extends string = string> {
|
|
2
|
+
value: T;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const terminalText: (value: string) => string;
|
|
6
|
+
export declare function accent(value: string): string;
|
|
7
|
+
/** Small native-terminal selector, without a UI dependency or an alternate
|
|
8
|
+
* screen. Every exit restores raw mode, the cursor, listeners and input flow. */
|
|
9
|
+
export declare function chooseTerminal<T extends string>(title: string | string[], choices: TerminalChoice<T>[]): Promise<T | undefined>;
|
package/dist/computer.d.ts
CHANGED
|
@@ -107,6 +107,8 @@ export interface ComputerForwardRequest {
|
|
|
107
107
|
id: string;
|
|
108
108
|
deviceId: string;
|
|
109
109
|
port: number;
|
|
110
|
+
/** A live human surface session is required for the virtual Mac display destination (8794). */
|
|
111
|
+
desktopSessionId?: string;
|
|
110
112
|
}
|
|
111
113
|
export interface ComputerForward extends ComputerForwardRequest {
|
|
112
114
|
expiresAt: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { acquireProcessLock, readJSON, writeJSON } from './chunk-
|
|
1
|
+
import { acquireProcessLock, readJSON, writeJSON } from './chunk-T2ZIA4TK.js';
|
|
2
2
|
import './chunk-PFYKJ6LX.js';
|
|
3
3
|
import { randomUUID } from 'crypto';
|
|
4
4
|
import * as path from 'path';
|
|
@@ -37,5 +37,5 @@ async function changeComputerConnection(directory, patch, options = {}) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export { changeComputerConnection };
|
|
40
|
-
//# sourceMappingURL=connection-change-
|
|
41
|
-
//# sourceMappingURL=connection-change-
|
|
40
|
+
//# sourceMappingURL=connection-change-RHY2OKFJ.js.map
|
|
41
|
+
//# sourceMappingURL=connection-change-RHY2OKFJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/computer/connection-change.ts"],"names":["delay"],"mappings":";;;;;;AAeA,eAAsB,wBAAA,CAAyB,SAAA,EAAmB,KAAA,EAA0C,OAAA,GAExG,EAAC,EAAkB;AACrB,EAAA,MAAM,IAAA,GAAO,MAAM,kBAAA,CAAwB,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,wBAAwB,CAAA,EAAG,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AAChH,EAAA,MAAM,IAAA,GAAY,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,iCAAiC,CAAA;AACnE,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,MAAM,QAAA,CAA8B,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,sBAAsB,CAAC,CAAA;AACzF,IAAA,IAAI,MAAA,CAAO,QAAQ,KAAK,CAAA,CAAE,MAAM,CAAC,CAAC,KAAK,KAAK,CAAA,KAAM,KAAK,SAAA,CAAU,KAAA,GAAQ,GAA2B,CAAC,CAAA,KAAM,KAAK,SAAA,CAAU,KAAK,CAAC,CAAA,EAAG;AACnI,IAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAmC,IAAI,CAAA;AAC9D,IAAA,IAAI,YAAY,CAAC,QAAA,EAAU,YAAY,CAAA,CAAE,SAAS,QAAA,CAAS,MAAM,CAAA,IAAK,IAAA,CAAK,UAAU,QAAA,CAAS,KAAK,MAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG;AAC9H,MAAA,MAAM,IAAI,MAAM,8EAA8E,CAAA;AAAA,IAChG;AACA,IAAA,MAAM,UAAU,QAAA,IAAY,CAAC,QAAA,EAAU,YAAY,EAAE,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,GAAI,WAC7E,EAAE,EAAA,EAAI,YAAW,EAAG,KAAA,EAAO,QAAQ,QAAA,EAAkB;AACzD,IAAA,MAAM,SAAA,CAAU,MAAM,OAAO,CAAA;AAC7B,IAAA,IAAI,OAAA;AACJ,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA;AAC9B,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,MAAA,OAAA,CAAQ,QAAQ,cAAA,EAAe;AAC/B,MAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAmC,IAAI,CAAA;AAC7D,MAAA,IAAI,SAAS,EAAA,KAAO,OAAA,CAAQ,IAAI,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAC1G,MAAA,IAAI,OAAA,CAAQ,WAAW,UAAA,EAAY;AACnC,MAAA,IAAI,OAAA,CAAQ,WAAW,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,OAAA,CAAQ,WAAW,gEAAgE,CAAA;AACpI,MAAA,IAAI,OAAA,CAAQ,OAAA,IAAW,OAAA,KAAY,OAAA,CAAQ,OAAA,EAAS;AAAE,QAAA,OAAA,GAAU,OAAA,CAAQ,OAAA;AAAS,QAAA,OAAA,CAAQ,aAAa,OAAO,CAAA;AAAA,MAAG;AAChH,MAAA,MAAMA,WAAM,GAAA,EAAK,KAAA,CAAA,EAAW,EAAE,MAAA,EAAQ,OAAA,CAAQ,QAAQ,CAAA;AAAA,IACxD;AACA,IAAA,MAAM,IAAI,MAAM,0FAA0F,CAAA;AAAA,EAC5G,CAAA,SAAE;AAAU,IAAA,MAAM,MAAM,KAAA,EAAM;AAAA,EAAG;AACnC","file":"connection-change-
|
|
1
|
+
{"version":3,"sources":["../src/computer/connection-change.ts"],"names":["delay"],"mappings":";;;;;;AAeA,eAAsB,wBAAA,CAAyB,SAAA,EAAmB,KAAA,EAA0C,OAAA,GAExG,EAAC,EAAkB;AACrB,EAAA,MAAM,IAAA,GAAO,MAAM,kBAAA,CAAwB,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,wBAAwB,CAAA,EAAG,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AAChH,EAAA,MAAM,IAAA,GAAY,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,iCAAiC,CAAA;AACnE,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,MAAM,QAAA,CAA8B,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,sBAAsB,CAAC,CAAA;AACzF,IAAA,IAAI,MAAA,CAAO,QAAQ,KAAK,CAAA,CAAE,MAAM,CAAC,CAAC,KAAK,KAAK,CAAA,KAAM,KAAK,SAAA,CAAU,KAAA,GAAQ,GAA2B,CAAC,CAAA,KAAM,KAAK,SAAA,CAAU,KAAK,CAAC,CAAA,EAAG;AACnI,IAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAmC,IAAI,CAAA;AAC9D,IAAA,IAAI,YAAY,CAAC,QAAA,EAAU,YAAY,CAAA,CAAE,SAAS,QAAA,CAAS,MAAM,CAAA,IAAK,IAAA,CAAK,UAAU,QAAA,CAAS,KAAK,MAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG;AAC9H,MAAA,MAAM,IAAI,MAAM,8EAA8E,CAAA;AAAA,IAChG;AACA,IAAA,MAAM,UAAU,QAAA,IAAY,CAAC,QAAA,EAAU,YAAY,EAAE,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,GAAI,WAC7E,EAAE,EAAA,EAAI,YAAW,EAAG,KAAA,EAAO,QAAQ,QAAA,EAAkB;AACzD,IAAA,MAAM,SAAA,CAAU,MAAM,OAAO,CAAA;AAC7B,IAAA,IAAI,OAAA;AACJ,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA;AAC9B,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,MAAA,OAAA,CAAQ,QAAQ,cAAA,EAAe;AAC/B,MAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAmC,IAAI,CAAA;AAC7D,MAAA,IAAI,SAAS,EAAA,KAAO,OAAA,CAAQ,IAAI,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAC1G,MAAA,IAAI,OAAA,CAAQ,WAAW,UAAA,EAAY;AACnC,MAAA,IAAI,OAAA,CAAQ,WAAW,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,OAAA,CAAQ,WAAW,gEAAgE,CAAA;AACpI,MAAA,IAAI,OAAA,CAAQ,OAAA,IAAW,OAAA,KAAY,OAAA,CAAQ,OAAA,EAAS;AAAE,QAAA,OAAA,GAAU,OAAA,CAAQ,OAAA;AAAS,QAAA,OAAA,CAAQ,aAAa,OAAO,CAAA;AAAA,MAAG;AAChH,MAAA,MAAMA,WAAM,GAAA,EAAK,KAAA,CAAA,EAAW,EAAE,MAAA,EAAQ,OAAA,CAAQ,QAAQ,CAAA;AAAA,IACxD;AACA,IAAA,MAAM,IAAI,MAAM,0FAA0F,CAAA;AAAA,EAC5G,CAAA,SAAE;AAAU,IAAA,MAAM,MAAM,KAAA,EAAM;AAAA,EAAG;AACnC","file":"connection-change-RHY2OKFJ.js","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport * as path from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { acquireProcessLock } from \"./lock.js\";\nimport { readJSON, writeJSON, type ComputerConfig } from \"./lifecycle.js\";\n\nexport interface ComputerConnectionChange {\n id: string;\n patch: Pick<Partial<ComputerConfig>, \"relay\" | \"host\">;\n status: \"queued\" | \"connecting\" | \"complete\" | \"failed\";\n message?: string;\n}\n\n/** The controller verifies a replacement before committing it. Parallel CLI\n * invocations join the same settings change, or run one after the other. */\nexport async function changeComputerConnection(directory: string, patch: ComputerConnectionChange[\"patch\"], options: {\n signal?: AbortSignal; onProgress?: (message: string) => void;\n} = {}): Promise<void> {\n const lock = await acquireProcessLock(path.join(directory, \"connection-change.lock\"), { signal: options.signal });\n const file = path.join(directory, \"computer-connection-change.json\");\n try {\n const saved = await readJSON<ComputerConfig>(path.join(directory, \"computer-config.json\"));\n if (Object.entries(patch).every(([key, value]) => JSON.stringify(saved?.[key as keyof ComputerConfig]) === JSON.stringify(value))) return;\n const previous = await readJSON<ComputerConnectionChange>(file);\n if (previous && [\"queued\", \"connecting\"].includes(previous.status) && JSON.stringify(previous.patch) !== JSON.stringify(patch)) {\n throw new Error(\"Another connection change is still running. Run mindwire status, then retry.\");\n }\n const request = previous && [\"queued\", \"connecting\"].includes(previous.status) ? previous\n : { id: randomUUID(), patch, status: \"queued\" as const };\n await writeJSON(file, request);\n let message: string | undefined;\n const deadline = Date.now() + 130_000;\n while (Date.now() < deadline) {\n options.signal?.throwIfAborted();\n const current = await readJSON<ComputerConnectionChange>(file);\n if (current?.id !== request.id) throw new Error(\"The connection change was replaced. Run mindwire status.\");\n if (current.status === \"complete\") return;\n if (current.status === \"failed\") throw new Error(current.message ?? \"Connection setup failed. The previous connection is unchanged.\");\n if (current.message && message !== current.message) { message = current.message; options.onProgress?.(message); }\n await delay(250, undefined, { signal: options.signal });\n }\n throw new Error(\"Connection setup is still running in the background. Run mindwire status for its result.\");\n } finally { await lock?.close(); }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { connectionInfo } from './chunk-
|
|
2
|
-
import { readJSON, processStateAlive, currentProcessIdentity,
|
|
1
|
+
import { connectionInfo, queueServiceUpdate, reconcileAddressDiscovery, activeUpdate } from './chunk-4XNTGVCI.js';
|
|
2
|
+
import { readJSON, processStateAlive, currentProcessIdentity, computerClient, SDK_VERSION, ensureDaemonBinary, processIdentity, adoptProcess, writeJSON, adoptRelay, RelayOutput, startRelay, providerNeedsAction, directRoutes, ProviderConnectionError, CONTROLLER_PROTOCOL, ownChild, versionAtLeast, hasCertificateError } from './chunk-T2ZIA4TK.js';
|
|
3
3
|
import './chunk-PFYKJ6LX.js';
|
|
4
4
|
import { execFileSync, spawn } from 'child_process';
|
|
5
5
|
import { randomBytes } from 'crypto';
|
|
@@ -179,6 +179,18 @@ async function relayProviderReachable(options, signal) {
|
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
// src/computer/runtime-version.ts
|
|
183
|
+
function managedServiceVersion(config, cliVersion = SDK_VERSION) {
|
|
184
|
+
if (config.versionPinned && config.version) return config.version;
|
|
185
|
+
if (!/^\d+\.\d+\.\d+$/.test(cliVersion)) return config.version ?? cliVersion;
|
|
186
|
+
return versionAtLeast(config.version, cliVersion) ? config.version : cliVersion;
|
|
187
|
+
}
|
|
188
|
+
function serviceUpgradeVersion(config, installed, cliVersion = SDK_VERSION) {
|
|
189
|
+
const wanted = managedServiceVersion(config, cliVersion);
|
|
190
|
+
if (config.daemonBin || !/^\d+\.\d+\.\d+$/.test(wanted) || versionAtLeast(installed, wanted)) return;
|
|
191
|
+
return wanted;
|
|
192
|
+
}
|
|
193
|
+
|
|
182
194
|
// src/computer/controller.ts
|
|
183
195
|
async function saveRelay(file, handle, port, options) {
|
|
184
196
|
if (handle?.owner?.identity) await writeJSON(file, {
|
|
@@ -208,6 +220,7 @@ async function superviseComputer(directory) {
|
|
|
208
220
|
let child, relay, stopping = false;
|
|
209
221
|
let relayTask, updateTask;
|
|
210
222
|
let connectionTask;
|
|
223
|
+
let maintenanceTask;
|
|
211
224
|
let relayResult;
|
|
212
225
|
let checkTask;
|
|
213
226
|
let checkResult;
|
|
@@ -299,13 +312,21 @@ async function superviseComputer(directory) {
|
|
|
299
312
|
let relayReachable = false, relayWasReachable = false, relayHealthFailures = 0;
|
|
300
313
|
let relayFailedAt = 0;
|
|
301
314
|
let nextCheckAt = 0, checkedAt = 0;
|
|
315
|
+
let nextMaintenanceAt = 0, maintenanceCheckedAt = 0, maintenanceFailures = 0;
|
|
316
|
+
let discoveryError;
|
|
302
317
|
try {
|
|
303
318
|
await phase("Checking the Mindwire service\u2026");
|
|
304
|
-
let binary = config.daemonBin ?? await ensureDaemonBinary({ version: config.version ?? SDK_VERSION, cacheDir: process.env.MINDWIRE_RELEASE_CACHE_DIR });
|
|
305
319
|
try {
|
|
306
320
|
client = await computerClient(directory);
|
|
307
321
|
} catch {
|
|
308
322
|
}
|
|
323
|
+
const wantedVersion = managedServiceVersion(config);
|
|
324
|
+
const installedVersion = client ? (await client.health()).version : wantedVersion;
|
|
325
|
+
let binary = config.daemonBin ?? await ensureDaemonBinary({
|
|
326
|
+
version: installedVersion,
|
|
327
|
+
cacheDir: process.env.MINDWIRE_RELEASE_CACHE_DIR,
|
|
328
|
+
exactVersion: !!client || config.versionPinned
|
|
329
|
+
});
|
|
309
330
|
if (client) {
|
|
310
331
|
const info = await client.computer.info();
|
|
311
332
|
const identity = await processIdentity(info.pid);
|
|
@@ -316,6 +337,11 @@ async function superviseComputer(directory) {
|
|
|
316
337
|
} else {
|
|
317
338
|
await phase("Starting the Mindwire service\u2026");
|
|
318
339
|
client = await launch(binary);
|
|
340
|
+
const startedVersion = (await client.health()).version.replace(/^v/, "");
|
|
341
|
+
if (!config.daemonBin && config.version !== startedVersion) {
|
|
342
|
+
config = { ...config, version: startedVersion };
|
|
343
|
+
await writeJSON(path.join(directory, "computer-config.json"), config);
|
|
344
|
+
}
|
|
319
345
|
}
|
|
320
346
|
const saved = await readJSON(relayPath);
|
|
321
347
|
const candidatePath = path.join(directory, "computer-relay-candidate.json");
|
|
@@ -348,7 +374,7 @@ async function superviseComputer(directory) {
|
|
|
348
374
|
let lastController = "";
|
|
349
375
|
while (!stopping) {
|
|
350
376
|
const changePath = path.join(directory, "computer-connection-change.json");
|
|
351
|
-
const change = !connectionTask && !relayTask && !updateTask && !changingDaemon && client && child?.alive() ? await readJSON(changePath) : void 0;
|
|
377
|
+
const change = !connectionTask && !relayTask && !updateTask && !maintenanceTask && !changingDaemon && client && child?.alive() ? await readJSON(changePath) : void 0;
|
|
352
378
|
if (change && ["queued", "connecting"].includes(change.status)) {
|
|
353
379
|
connectionTask = (async () => {
|
|
354
380
|
const previousConfig = config;
|
|
@@ -485,6 +511,7 @@ async function superviseComputer(directory) {
|
|
|
485
511
|
published = "";
|
|
486
512
|
daemonError = void 0;
|
|
487
513
|
daemonReadyAt = Date.now();
|
|
514
|
+
nextMaintenanceAt = 0;
|
|
488
515
|
} catch (error) {
|
|
489
516
|
if (child) await child.close();
|
|
490
517
|
child = void 0;
|
|
@@ -494,6 +521,32 @@ async function superviseComputer(directory) {
|
|
|
494
521
|
}
|
|
495
522
|
}
|
|
496
523
|
const requestedCheck = await readJSON(path.join(directory, "computer-check.json"));
|
|
524
|
+
if (!maintenanceTask && !changingDaemon && !updateTask && !connectionTask && client && child?.alive() && (Date.now() >= nextMaintenanceAt || (requestedCheck?.requestedAt ?? 0) > maintenanceCheckedAt)) {
|
|
525
|
+
const maintaining = client;
|
|
526
|
+
maintenanceCheckedAt = Date.now();
|
|
527
|
+
maintenanceTask = (async () => {
|
|
528
|
+
try {
|
|
529
|
+
const upgrade = serviceUpgradeVersion(config, (await maintaining.health()).version);
|
|
530
|
+
if (upgrade) {
|
|
531
|
+
await queueServiceUpdate(maintaining, upgrade);
|
|
532
|
+
discoveryError = `Service update to ${upgrade} is pending. Automatic updates wait for active work to finish.`;
|
|
533
|
+
nextMaintenanceAt = Date.now() + 2e3;
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
await reconcileAddressDiscovery({ directory, config, computer: maintaining, signal: abort.signal });
|
|
537
|
+
discoveryError = void 0;
|
|
538
|
+
maintenanceFailures = 0;
|
|
539
|
+
nextMaintenanceAt = Date.now() + 6e4;
|
|
540
|
+
} catch (error) {
|
|
541
|
+
if (!stopping) {
|
|
542
|
+
discoveryError = error instanceof Error ? error.message : "Automatic reconnection setup will retry.";
|
|
543
|
+
nextMaintenanceAt = Date.now() + recoveryDelay(++maintenanceFailures);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
})().finally(() => {
|
|
547
|
+
maintenanceTask = void 0;
|
|
548
|
+
});
|
|
549
|
+
}
|
|
497
550
|
if (!connectionTask && relay?.owner && !relay.owner.alive()) {
|
|
498
551
|
await relay.close();
|
|
499
552
|
relay = void 0;
|
|
@@ -626,6 +679,7 @@ async function superviseComputer(directory) {
|
|
|
626
679
|
error: daemonError ?? relayError,
|
|
627
680
|
errorCode: daemonError ? void 0 : relayErrorCode,
|
|
628
681
|
recovering: !ready,
|
|
682
|
+
discoveryError,
|
|
629
683
|
relayFailureSince: relayFailedAt || void 0,
|
|
630
684
|
relayFailures: relayHealthFailures || void 0
|
|
631
685
|
};
|
|
@@ -635,8 +689,8 @@ async function superviseComputer(directory) {
|
|
|
635
689
|
lastController = serialized;
|
|
636
690
|
}
|
|
637
691
|
const updatePath = path.join(directory, "computer-update.json");
|
|
638
|
-
const update = !updateTask && !connectionTask && client && child?.alive() ? await readJSON(updatePath) : void 0;
|
|
639
|
-
if (
|
|
692
|
+
const update = !updateTask && !connectionTask && !maintenanceTask && client && child?.alive() ? await readJSON(updatePath) : void 0;
|
|
693
|
+
if (activeUpdate(update)) {
|
|
640
694
|
updateTask = (async () => {
|
|
641
695
|
const status = async (state2, error) => writeJSON(
|
|
642
696
|
updatePath,
|
|
@@ -644,7 +698,7 @@ async function superviseComputer(directory) {
|
|
|
644
698
|
);
|
|
645
699
|
try {
|
|
646
700
|
await status("downloading");
|
|
647
|
-
const replacement = await ensureDaemonBinary({ version: update.version, cacheDir: process.env.MINDWIRE_RELEASE_CACHE_DIR });
|
|
701
|
+
const replacement = await ensureDaemonBinary({ version: update.version, cacheDir: process.env.MINDWIRE_RELEASE_CACHE_DIR, exactVersion: true });
|
|
648
702
|
await status("waiting");
|
|
649
703
|
let lease;
|
|
650
704
|
while (!stopping && !lease) {
|
|
@@ -678,11 +732,14 @@ async function superviseComputer(directory) {
|
|
|
678
732
|
await client.computer.setRoutes(routes, connectionInfo(config.relay, config.host));
|
|
679
733
|
published = "";
|
|
680
734
|
await status("complete");
|
|
735
|
+
maintenanceFailures = 0;
|
|
681
736
|
} catch (error) {
|
|
737
|
+
maintenanceFailures++;
|
|
682
738
|
await status("failed", error instanceof Error ? error.message : "Service update failed.");
|
|
683
739
|
} finally {
|
|
684
740
|
changingDaemon = false;
|
|
685
741
|
published = "";
|
|
742
|
+
nextMaintenanceAt = Date.now() + recoveryDelay(maintenanceFailures);
|
|
686
743
|
}
|
|
687
744
|
})().finally(() => {
|
|
688
745
|
updateTask = void 0;
|
|
@@ -699,6 +756,7 @@ async function superviseComputer(directory) {
|
|
|
699
756
|
await checkTask;
|
|
700
757
|
await updateTask;
|
|
701
758
|
await connectionTask;
|
|
759
|
+
await maintenanceTask;
|
|
702
760
|
if (relayResult?.handle && relayResult.handle !== relay) await relayResult.handle.close();
|
|
703
761
|
await relay?.close();
|
|
704
762
|
if (child) await child.close();
|
|
@@ -709,5 +767,5 @@ async function superviseComputer(directory) {
|
|
|
709
767
|
}
|
|
710
768
|
|
|
711
769
|
export { recoveryDelay, superviseComputer };
|
|
712
|
-
//# sourceMappingURL=controller-
|
|
713
|
-
//# sourceMappingURL=controller-
|
|
770
|
+
//# sourceMappingURL=controller-G2T76QDM.js.map
|
|
771
|
+
//# sourceMappingURL=controller-G2T76QDM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/computer/relay-health.ts","../src/computer/runtime-version.ts","../src/computer/controller.ts"],"names":["family","address","resolve","process","client","delay","owner","state"],"mappings":"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","file":"controller-G2T76QDM.js","sourcesContent":["import { request } from \"node:https\";\nimport { lookup } from \"node:dns\";\nimport { Resolver } from \"node:dns/promises\";\nimport { isIP, type LookupFunction } from \"node:net\";\nimport WebSocket from \"ws\";\nimport type { ComputerRoute } from \"../computer.js\";\nimport type { RelayOptions } from \"./relay.js\";\nimport { hasCertificateError } from \"./provider-errors.js\";\n\nexport class RelayCheckError extends Error {\n constructor(readonly code: \"dns\" | \"timeout\" | \"proxy\" | \"connection\" | \"response\" | \"provider_certificate\", message: string, cause?: Error,\n readonly addressMissing = false) {\n super(message, cause ? { cause } : undefined);\n this.name = \"RelayCheckError\";\n }\n}\n\n/** Local NXDOMAIN can be a stale cache. A missing address confirmed by the\n * provider is different: its helper may stay alive after the quick tunnel expires.\n * Keep a grace period for newly allocated records and ordinary internet outages. */\nexport function relayNeedsRestart(error: unknown, failures: number, failedForMs: number): boolean {\n return failures >= 2 && failedForMs >= 90_000\n && !(error instanceof RelayCheckError && error.code === \"provider_certificate\")\n && (!(error instanceof RelayCheckError && error.code === \"dns\") || error.addressMissing);\n}\n\ntype RelayDNSResult = { addresses: { address: string; family: number }[]; missing: boolean };\nconst quickTunnelHost = /^[a-z0-9-]+\\.trycloudflare\\.com$/i;\n\n/** Use the tunnel provider's HTTPS resolver only after local DNS fails. This\n * bypasses router negative caches without another service or a persisted IP.\n * A DNS answer never replaces TLS hostname validation or the phone's SSH pin. */\nexport async function resolveCloudflareAddress(hostname: string, family = 0,\n options: { fetch?: typeof fetch; timeoutMs?: number } = {}): Promise<RelayDNSResult> {\n if (!quickTunnelHost.test(hostname)) return { addresses: [], missing: false };\n const abort = new AbortController();\n const timer = setTimeout(() => abort.abort(), options.timeoutMs ?? 3000);\n try {\n const types = family === 4 ? [1] : family === 6 ? [28] : [1, 28];\n const results = await Promise.all(types.map(async type => {\n try {\n const response = await (options.fetch ?? fetch)(\n `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(hostname)}&type=${type}`,\n { headers: { accept: \"application/dns-json\" }, redirect: \"error\", signal: abort.signal });\n if (response.status !== 200 || !response.body) { await response.body?.cancel(); return undefined; }\n const reader = response.body.getReader();\n let text = \"\", size = 0;\n const decoder = new TextDecoder();\n try {\n for (;;) {\n const chunk = await reader.read();\n if (chunk.done) break;\n size += chunk.value.length;\n if (size > 16_384) return undefined;\n text += decoder.decode(chunk.value, { stream: true });\n }\n } finally { await reader.cancel(); }\n const result = JSON.parse(text + decoder.decode()) as {\n Status?: number; Question?: { name?: string; type?: number }[];\n Answer?: { type?: number; data?: string }[];\n };\n if (!Array.isArray(result.Question) || !result.Question.some(question =>\n question.name?.replace(/\\.$/, \"\").toLowerCase() === hostname.toLowerCase() && question.type === type)) return undefined;\n if (result.Status === 3) return { addresses: [], missing: true };\n if (result.Status !== 0) return undefined;\n const addresses = (Array.isArray(result.Answer) ? result.Answer : []).flatMap(answer => {\n const family = answer.type === 1 ? 4 : answer.type === 28 ? 6 : 0;\n return family && answer.type === type && typeof answer.data === \"string\" && isIP(answer.data) === family\n ? [{ address: answer.data, family }] : [];\n });\n return { addresses, missing: false };\n } catch { return undefined; }\n }));\n return { addresses: results.flatMap(result => result?.addresses ?? []),\n missing: results.every(result => result?.missing === true) };\n } finally { clearTimeout(timer); }\n}\n\n/** Try OS DNS, then its uncached resolver, then the provider for quick tunnels.\n * TLS SNI/certificate validation still use the original hostname. */\nconst relayLookup: LookupFunction = (hostname, options, callback) => {\n lookup(hostname, options, (error, address, family) => {\n if (![\"ENOTFOUND\", \"EAI_AGAIN\"].includes((error as NodeJS.ErrnoException | null)?.code ?? \"\") || !quickTunnelHost.test(hostname)) {\n callback(error, address, family); return;\n }\n const resolver = new Resolver({ timeout: 3000, tries: 1 });\n const requestedFamily = options.family === \"IPv4\" ? 4 : options.family === \"IPv6\" ? 6 : options.family ?? 0;\n void Promise.all([\n requestedFamily === 6 ? [] : resolver.resolve4(hostname).then(addresses => addresses.map(address => ({ address, family: 4 })), () => []),\n requestedFamily === 4 ? [] : resolver.resolve6(hostname).then(addresses => addresses.map(address => ({ address, family: 6 })), () => []),\n ]).then(async results => {\n let addresses = results.flat();\n if (!addresses.length) {\n const provider = await resolveCloudflareAddress(hostname, requestedFamily);\n addresses = provider.addresses;\n if (!addresses.length) {\n callback(Object.assign(error!, { relayAddressMissing: provider.missing }), address, family); return;\n }\n }\n if (options.all) callback(null, addresses);\n else callback(null, addresses[0]!.address, addresses[0]!.family);\n });\n });\n};\n\n/** Check the actual WebSocket byte path, not just the helper's PID or its logs.\n * The phone still authenticates and pins the SSH host before sending secrets. */\nexport async function checkRelay(route: ComputerRoute, options: { signal?: AbortSignal; timeoutMs?: number; lookup?: LookupFunction } = {}): Promise<void> {\n options.signal?.throwIfAborted();\n if (route.kind !== \"websocket\") throw new Error(\"Expected an internet tunnel address.\");\n await new Promise<void>((resolve, reject) => {\n const socket = new WebSocket(route.url, { maxPayload: 4096, perMessageDeflate: false, followRedirects: false, lookup: options.lookup ?? relayLookup });\n let finished = false, banner = \"\";\n const finish = (error?: Error) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", aborted);\n socket.terminate();\n if (error) reject(error); else resolve();\n };\n const aborted = () => finish(options.signal?.reason ?? new Error(\"Connection check cancelled.\"));\n const timer = setTimeout(() => finish(new RelayCheckError(\"timeout\", \"The internet tunnel isn't responding. Retrying…\")), options.timeoutMs ?? 8000);\n socket.on(\"error\", error => {\n if (hasCertificateError(error)) {\n finish(new RelayCheckError(\"provider_certificate\", \"The tunnel's TLS certificate could not be verified. Check the provider's certificate and this computer's date and time.\", error));\n } else if ([\"ENOTFOUND\", \"EAI_AGAIN\"].includes((error as NodeJS.ErrnoException).code ?? \"\")) {\n const provider = new URL(route.url).hostname.endsWith(\".trycloudflare.com\") ? \"Cloudflare's\" : \"the tunnel's\";\n finish(new RelayCheckError(\"dns\", `Waiting for ${provider} internet address (DNS)…`, error,\n (error as Error & { relayAddressMissing?: boolean }).relayAddressMissing === true));\n } else if (/(?:[Uu]nexpected server response|[Ee]xpected 101)/.test(error.message)) {\n finish(new RelayCheckError(\"proxy\", \"The internet tunnel isn't reaching Mindwire. Retrying…\", error));\n } else {\n finish(new RelayCheckError(\"connection\", \"The internet tunnel couldn't connect. Retrying…\", error));\n }\n });\n socket.on(\"close\", () => finish(new RelayCheckError(\"connection\", \"The internet tunnel closed before reaching Mindwire. Retrying…\")));\n socket.on(\"message\", (data, binary) => {\n if (!binary) { finish(new RelayCheckError(\"response\", \"The internet tunnel returned an invalid SSH response.\")); return; }\n banner += data.toString();\n if (banner.length > 1024) { finish(new RelayCheckError(\"response\", \"The internet tunnel returned an invalid SSH response.\")); return; }\n if (banner.includes(\"\\n\")) {\n finish(banner.split(\"\\n\")[0]?.trim() === \"SSH-2.0-Mindwire\" ? undefined\n : new RelayCheckError(\"response\", \"The internet tunnel isn't connected to the Mindwire SSH service.\"));\n }\n });\n options.signal?.addEventListener(\"abort\", aborted, { once: true });\n if (options.signal?.aborted) aborted();\n });\n}\n\n/** Don't rotate a quick-tunnel address during an ordinary internet outage.\n * Let the provider reconnect with the same address until it is reachable again. */\nexport async function relayProviderReachable(options: RelayOptions, signal?: AbortSignal): Promise<boolean> {\n if (![\"cloudflare\", \"ngrok\", \"oblien\"].includes(options.kind)) return false;\n signal?.throwIfAborted();\n return new Promise<boolean>(resolve => {\n const url = options.kind === \"cloudflare\" ? \"https://api.trycloudflare.com/\"\n : options.kind === \"oblien\" ? \"https://api.oblien.com/\" : \"https://api.ngrok.com/\";\n let finished = false;\n const done = (reachable: boolean) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer);\n probe.destroy();\n resolve(reachable);\n };\n const probe = request(url, { method: \"HEAD\", signal }, response => {\n response.destroy();\n done(true);\n });\n const timer = setTimeout(() => done(false), 5000);\n probe.on(\"error\", () => done(false));\n probe.end();\n });\n}\n","import { SDK_VERSION, versionAtLeast } from \"../version.js\";\nimport type { ComputerConfig } from \"./lifecycle.js\";\n\n/** The saved version is the last installed release, not an accidental permanent\n * pin. Upgrading the CLI must also upgrade its managed service. Never downgrade a\n * newer service or replace an explicitly supplied development binary. */\nexport function managedServiceVersion(config: ComputerConfig, cliVersion = SDK_VERSION): string {\n if (config.versionPinned && config.version) return config.version;\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(cliVersion)) return config.version ?? cliVersion;\n return versionAtLeast(config.version, cliVersion) ? config.version! : cliVersion;\n}\n\nexport function serviceUpgradeVersion(config: ComputerConfig, installed: string, cliVersion = SDK_VERSION): string | undefined {\n const wanted = managedServiceVersion(config, cliVersion);\n if (config.daemonBin || !/^\\d+\\.\\d+\\.\\d+$/.test(wanted) || versionAtLeast(installed, wanted)) return;\n return wanted;\n}\n","import { spawn, execFileSync } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport type { Mindwire } from \"../client.js\";\nimport { ensureDaemonBinary } from \"../daemon-binary.js\";\nimport { SDK_VERSION } from \"../version.js\";\nimport type { ComputerInfo, ComputerRoute, ComputerUpdate } from \"../computer.js\";\nimport { computerClient, directRoutes, readJSON, writeJSON, CONTROLLER_PROTOCOL, type ComputerConfig, type ControllerState } from \"./lifecycle.js\";\nimport { adoptRelay, startRelay, type RelayHandle } from \"./relay.js\";\nimport { checkRelay, relayNeedsRestart, relayProviderReachable, RelayCheckError } from \"./relay-health.js\";\nimport { adoptProcess, ownChild, currentProcessIdentity, processStateAlive, processIdentity, type OwnedProcess, type ProcessIdentity } from \"./process.js\";\nimport { RelayOutput } from \"./relay-output.js\";\nimport { connectionInfo } from \"./provider-info.js\";\nimport type { ComputerConnectionChange } from \"./connection-change.js\";\nimport { ProviderConnectionError, providerNeedsAction } from \"./provider-errors.js\";\nimport { managedServiceVersion, serviceUpgradeVersion } from \"./runtime-version.js\";\nimport { reconcileAddressDiscovery } from \"./discovery.js\";\nimport { activeUpdate, queueServiceUpdate } from \"./service-update.js\";\n\ninterface SavedRelay { owner: ProcessIdentity; port: number; options: string; route?: ComputerRoute; outputFile?: string; configFile?: string }\nasync function saveRelay(file: string, handle: RelayHandle | undefined, port: number, options: ComputerConfig[\"relay\"]): Promise<void> {\n if (handle?.owner?.identity) await writeJSON(file, { owner: handle.owner.identity, port, options: JSON.stringify(options),\n route: handle.route, outputFile: handle.outputFile, configFile: handle.configFile } satisfies SavedRelay);\n else await fs.rm(file, { force: true });\n}\nexport function recoveryDelay(failures: number): number { return Math.min(60_000, 1000 * 2 ** Math.min(6, Math.max(0, failures - 1))); }\n\n/** Own process lifecycle separately from any mobile view or pairing command. */\nexport async function superviseComputer(directory: string): Promise<void> {\n if ((await readJSON<{ stopped: boolean }>(path.join(directory, \"computer-stopped.json\")))?.stopped) return;\n let config = await readJSON<ComputerConfig>(path.join(directory, \"computer-config.json\"));\n if (!config) throw new Error(\"Computer configuration is missing.\");\n const controllerPath = path.join(directory, \"computer-controller.json\");\n const relayPath = path.join(directory, \"computer-relay.json\");\n const previous = await readJSON<ControllerState>(controllerPath);\n if (await processStateAlive(previous)) throw new Error(\"The computer already has a service controller.\");\n const owner = await currentProcessIdentity();\n const phase = (message: string) => writeJSON(controllerPath, { ...owner, protocol: CONTROLLER_PROTOCOL, cliVersion: SDK_VERSION, ready: false, phase: message, recovering: true });\n await phase(\"Preparing Mindwire…\");\n let child: OwnedProcess | undefined, relay: RelayHandle | undefined, stopping = false;\n let relayTask: Promise<void> | undefined, updateTask: Promise<void> | undefined;\n let connectionTask: Promise<void> | undefined;\n let maintenanceTask: Promise<void> | undefined;\n let relayResult: { handle?: RelayHandle; error?: unknown } | undefined;\n let checkTask: Promise<void> | undefined;\n let checkResult: { relay: RelayHandle; error?: unknown; canRestart?: boolean } | undefined;\n const abort = new AbortController();\n const stop = () => { stopping = true; abort.abort(); };\n process.on(\"SIGTERM\", stop); process.on(\"SIGINT\", stop);\n\n let token: string;\n try { token = (await fs.readFile(path.join(directory, \"daemon.token\"), \"utf8\")).trim(); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n token = randomBytes(32).toString(\"hex\");\n await fs.writeFile(path.join(directory, \"daemon.token\"), token, { mode: 0o600, flag: \"wx\" });\n }\n const daemonEnv = { ...process.env };\n if (process.platform === \"win32\") {\n try {\n const git = execFileSync(\"where.exe\", [\"git\"], { encoding: \"utf8\", timeout: 3000, windowsHide: true }).split(/\\r?\\n/)[0];\n if (git) {\n const shellDirectory = path.resolve(path.dirname(git), \"..\", \"bin\");\n await fs.access(path.join(shellDirectory, \"bash.exe\"));\n const pathKey = Object.keys(daemonEnv).find(key => key.toLowerCase() === \"path\") ?? \"PATH\";\n daemonEnv[pathKey] = `${shellDirectory}${path.delimiter}${daemonEnv[pathKey] ?? \"\"}`;\n }\n } catch { /* Git/Bash are checked only when their capabilities are used. */ }\n }\n const oldRuntime = await readJSON<ComputerInfo>(path.join(directory, \"computer-runtime.json\"));\n // An automatically selected port remains stable across controller/release restarts.\n let sshPort = config.sshPort || oldRuntime?.sshPort || 0;\n let websocketPort = config.websocketPort || oldRuntime?.websocketPort || 0;\n const launch = async (binary: string): Promise<Mindwire> => {\n await fs.rm(path.join(directory, \"computer-runtime.json\"), { force: true });\n const process = spawn(binary, [\"--computer\"], {\n cwd: config!.directory, stdio: [\"ignore\", \"inherit\", \"inherit\"], windowsHide: true,\n env: { ...daemonEnv, DAEMON_TOKEN: token, ADDR: \"127.0.0.1:0\", STATE_PATH: path.join(directory, \"agent-state.json\"),\n WORKSPACE_DB_PATH: path.join(directory, \"workspace.db\"), AGENT_CWD: config!.directory,\n COMPUTER_SSH_ADDR: `${config!.bind.includes(\":\") ? `[${config!.bind}]` : config!.bind}:${sshPort}`,\n COMPUTER_WS_ADDR: `127.0.0.1:${websocketPort}`, MINDWIRE_COMPUTER_MANAGED: \"1\" },\n });\n let failure: Error | undefined;\n process.on(\"error\", error => { failure = error; });\n await new Promise<void>((resolve, reject) => { process.once(\"spawn\", resolve); process.once(\"error\", reject); });\n child = await ownChild(process);\n for (let attempt = 0; attempt < 100; attempt++) {\n if (stopping) throw new Error(\"Mindwire is stopping.\");\n if (failure) throw failure;\n if (!child.alive()) throw new Error(\"Mindwire exited during startup. Check computer.log and the installed release.\");\n try {\n const client = await computerClient(directory);\n const info = await client.computer.info();\n if (info.pid !== child.pid) throw new Error(\"Another service owns this computer's state.\");\n const health = await client.health();\n if ((health as { computerConnectionVersion?: number }).computerConnectionVersion !== 1) throw new Error(\"Update Mindwire to a release that supports computer connections.\");\n sshPort = info.sshPort; websocketPort = info.websocketPort;\n return client;\n } catch (error) { if (attempt === 99) throw error; }\n await delay(100);\n }\n throw new Error(\"Mindwire startup timed out.\");\n };\n\n let routes: ComputerRoute[] = [], published = \"\";\n let client: Mindwire | undefined;\n let relayMessage = \"Preparing your internet connection…\", relayError: string | undefined;\n let relayErrorCode: string | undefined;\n let daemonError: string | undefined, nextDaemonAt = 0, daemonFailures = 0;\n let nextRelayAt = 0, relayFailures = 0, changingDaemon = false;\n let daemonReadyAt = Date.now(), relayReadyAt = Date.now();\n let relayReachable = false, relayWasReachable = false, relayHealthFailures = 0;\n let relayFailedAt = 0;\n let nextCheckAt = 0, checkedAt = 0;\n let nextMaintenanceAt = 0, maintenanceCheckedAt = 0, maintenanceFailures = 0;\n let discoveryError: string | undefined;\n try {\n await phase(\"Checking the Mindwire service…\");\n // A killed controller must not restart a healthy daemon or lose its PTYs.\n try { client = await computerClient(directory); } catch { /* Cold start. */ }\n const wantedVersion = managedServiceVersion(config);\n const installedVersion = client ? (await client.health()).version : wantedVersion;\n let binary = config.daemonBin ?? await ensureDaemonBinary({ version: installedVersion,\n cacheDir: process.env.MINDWIRE_RELEASE_CACHE_DIR, exactVersion: !!client || config.versionPinned });\n if (client) {\n const info = await client.computer.info();\n const identity = await processIdentity(info.pid);\n child = identity ? await adoptProcess(identity) : undefined;\n if (!child) throw new Error(\"Couldn't verify the existing Mindwire process. Leave it running and retry.\");\n sshPort = info.sshPort; websocketPort = info.websocketPort;\n } else {\n await phase(\"Starting the Mindwire service…\");\n client = await launch(binary);\n const startedVersion = (await client.health()).version.replace(/^v/, \"\");\n if (!config.daemonBin && config.version !== startedVersion) {\n config = { ...config, version: startedVersion };\n await writeJSON(path.join(directory, \"computer-config.json\"), config);\n }\n }\n\n const saved = await readJSON<SavedRelay>(relayPath);\n const candidatePath = path.join(directory, \"computer-relay-candidate.json\");\n const abandonedCandidate = await readJSON<SavedRelay>(candidatePath);\n if (abandonedCandidate && (abandonedCandidate.owner.pid !== saved?.owner.pid || abandonedCandidate.owner.start !== saved?.owner.start)) {\n const abandonedOwner = await adoptProcess(abandonedCandidate.owner);\n if (abandonedOwner) await (await adoptRelay(abandonedOwner, abandonedCandidate.route, directory, abandonedCandidate.outputFile, abandonedCandidate.configFile)).close();\n }\n await fs.rm(candidatePath, { force: true });\n if (saved) {\n const owner = await adoptProcess(saved.owner);\n if (owner) {\n if (saved.outputFile && saved.route && saved.port === websocketPort && saved.options === JSON.stringify(config.relay)) {\n relay = await adoptRelay(owner, saved.route, directory, saved.outputFile, saved.configFile);\n relayWasReachable = !!previous?.routes?.some(route => JSON.stringify(route) === JSON.stringify(saved.route));\n if (previous?.relayFailureSince && relayWasReachable) {\n relayFailedAt = Math.min(Date.now(), previous.relayFailureSince);\n relayHealthFailures = previous.relayFailures ?? 0;\n }\n } else {\n // An old helper's pipes belonged to the controller we replaced. It\n // can still answer briefly, then die on its next log write. Migrate\n // it once before certifying a QR, keeping the daemon and phone keys.\n if (!saved.outputFile) await phase(\"Refreshing the internet tunnel for this update…\");\n const abandoned = await adoptRelay(owner, saved.route, directory, saved.outputFile, saved.configFile);\n await abandoned.close();\n await fs.rm(relayPath, { force: true });\n }\n } else if (saved.outputFile) {\n await (await RelayOutput.adopt(directory, saved.outputFile))?.close();\n }\n }\n\n let lastController = \"\";\n while (!stopping) {\n const changePath = path.join(directory, \"computer-connection-change.json\");\n const change = !connectionTask && !relayTask && !updateTask && !maintenanceTask && !changingDaemon && client && child?.alive()\n ? await readJSON<ComputerConnectionChange>(changePath) : undefined;\n if (change && [\"queued\", \"connecting\"].includes(change.status)) {\n connectionTask = (async () => {\n const previousConfig = config!;\n const next = { ...previousConfig, ...change.patch };\n let previousRelay = relay;\n let releasedPrevious = false;\n let candidate: RelayHandle | undefined;\n let committed = false;\n let lastVerificationError: Error | undefined;\n const changing = new AbortController();\n const cancel = () => changing.abort();\n abort.signal.addEventListener(\"abort\", cancel, { once: true });\n const timeout = setTimeout(cancel, 115_000);\n const report = (message: string) => writeJSON(changePath, { ...change, status: \"connecting\", message });\n try {\n await report(\"Preparing the new connection; your current service keeps running…\");\n if (JSON.stringify(next.relay) === JSON.stringify(previousConfig.relay) && previousRelay\n && (!previousRelay.owner || previousRelay.owner.alive())) candidate = previousRelay;\n else {\n // A reserved endpoint can have only one owner. Reauthentication\n // briefly replaces that carrier, keeping SSH identity and PTYs.\n if (previousRelay?.owner && [\"ngrok\", \"oblien\"].includes(next.relay.kind)\n && next.relay.kind === previousConfig.relay.kind && next.relay.url === previousConfig.relay.url) {\n await report(\"Refreshing the saved provider connection; your terminals keep running…\");\n releasedPrevious = true; relayReachable = false;\n await previousRelay.close();\n }\n candidate = await startRelay(next.relay, websocketPort, {\n cacheDir: path.join(directory, \"tools\"), outputDirectory: directory, cliPath: process.argv[1], signal: changing.signal,\n onProgress: report,\n onSpawn: async (owner, outputFile, configFile) => {\n if (owner.identity) await writeJSON(candidatePath, { owner: owner.identity, port: websocketPort,\n options: JSON.stringify(next.relay), outputFile, configFile } satisfies SavedRelay);\n },\n });\n }\n if (next.relay.kind !== \"none\") {\n if (!candidate?.route) throw new Error(\"The provider didn't return an address.\");\n await report(\"Verifying the new secure connection…\");\n for (;;) {\n changing.signal.throwIfAborted();\n try { await checkRelay(candidate.route, { signal: changing.signal }); break; }\n catch (error) {\n if (error instanceof Error) lastVerificationError = error;\n if (error instanceof RelayCheckError && providerNeedsAction(error.code)) throw error;\n await delay(2000, undefined, { signal: changing.signal });\n }\n }\n }\n changing.signal.throwIfAborted();\n const nextRoutes = directRoutes(next, sshPort);\n if (candidate?.route) nextRoutes.push(candidate.route);\n if (!nextRoutes.length) throw new Error(\"No reachable address was configured.\");\n await client!.computer.setRoutes(nextRoutes, connectionInfo(next.relay, next.host));\n await writeJSON(path.join(directory, \"computer-config.json\"), next);\n await saveRelay(relayPath, candidate, websocketPort, next.relay);\n config = next; relay = candidate; routes = nextRoutes; published = \"\";\n relayReachable = true; relayWasReachable = true; relayHealthFailures = 0; relayFailedAt = 0;\n relayError = undefined; relayErrorCode = undefined; checkedAt = Date.now(); nextCheckAt = checkedAt + 30_000;\n committed = true;\n if (previousRelay && previousRelay !== candidate) await previousRelay.close();\n await writeJSON(changePath, { ...change, status: \"complete\", message: \"Persistent connection is ready.\" });\n } catch (error) {\n if (!committed) {\n if (candidate && candidate !== previousRelay) await candidate.close();\n await writeJSON(path.join(directory, \"computer-config.json\"), previousConfig);\n if (releasedPrevious) {\n previousRelay = undefined;\n if (!stopping) {\n await report(\"Restoring the previous provider connection…\");\n try {\n previousRelay = await startRelay(previousConfig.relay, websocketPort, {\n cacheDir: path.join(directory, \"tools\"), outputDirectory: directory, cliPath: process.argv[1], signal: abort.signal,\n });\n } catch { /* Normal background recovery retries the original provider. */ }\n }\n relayReachable = false; nextCheckAt = 0; nextRelayAt = 0;\n }\n relay = previousRelay;\n await saveRelay(relayPath, previousRelay, websocketPort, previousConfig.relay);\n published = \"\"; // Re-publish the original routes if a disk write failed during commit.\n }\n await writeJSON(changePath, { ...change, status: committed ? \"complete\" : \"failed\",\n message: committed ? \"Connection is ready.\" : `Connection setup didn't finish. ${error instanceof Error && error.name !== \"AbortError\" ? error.message : lastVerificationError?.message ?? \"Check the provider configuration and internet connection.\"} The previous service keeps running.` });\n } finally {\n clearTimeout(timeout); abort.signal.removeEventListener(\"abort\", cancel);\n await fs.rm(candidatePath, { force: true });\n }\n })().catch(() => {\n relayError = \"The connection change could not be saved. Check free disk space, then run mindwire connection again.\";\n }).finally(() => { connectionTask = undefined; });\n }\n if (!changingDaemon && child && !child.alive()) {\n child = undefined; client = undefined;\n daemonError = \"The service stopped. Restarting it…\";\n nextDaemonAt = Date.now() + recoveryDelay(++daemonFailures);\n }\n if (child?.alive() && Date.now() - daemonReadyAt > 60_000) daemonFailures = 0;\n if (relayReachable && relay?.owner?.alive() && Date.now() - relayReadyAt > 60_000) relayFailures = 0;\n if (!changingDaemon && !child?.alive() && Date.now() >= nextDaemonAt) {\n daemonError = \"The service stopped. Restarting it…\";\n await phase(daemonError);\n try {\n client = await launch(binary); published = \"\"; daemonError = undefined; daemonReadyAt = Date.now();\n nextMaintenanceAt = 0;\n } catch (error) {\n if (child) await child.close();\n child = undefined; client = undefined;\n daemonError = error instanceof Error ? error.message : \"Service restart failed.\";\n nextDaemonAt = Date.now() + recoveryDelay(++daemonFailures);\n }\n }\n\n const requestedCheck = await readJSON<{ requestedAt: number }>(path.join(directory, \"computer-check.json\"));\n if (!maintenanceTask && !changingDaemon && !updateTask && !connectionTask && client && child?.alive()\n && (Date.now() >= nextMaintenanceAt || (requestedCheck?.requestedAt ?? 0) > maintenanceCheckedAt)) {\n const maintaining = client;\n maintenanceCheckedAt = Date.now();\n maintenanceTask = (async () => {\n try {\n const upgrade = serviceUpgradeVersion(config!, (await maintaining.health()).version);\n if (upgrade) {\n await queueServiceUpdate(maintaining, upgrade);\n discoveryError = `Service update to ${upgrade} is pending. Automatic updates wait for active work to finish.`;\n // Completion can race this read before updateTask observes it.\n // Recheck locally so an older completed request cannot strand the\n // desired release forever; waiting updates already gate this task.\n nextMaintenanceAt = Date.now() + 2000;\n return;\n }\n await reconcileAddressDiscovery({ directory, config: config!, computer: maintaining, signal: abort.signal });\n discoveryError = undefined; maintenanceFailures = 0;\n nextMaintenanceAt = Date.now() + 60_000;\n } catch (error) {\n if (!stopping) {\n discoveryError = error instanceof Error ? error.message : \"Automatic reconnection setup will retry.\";\n nextMaintenanceAt = Date.now() + recoveryDelay(++maintenanceFailures);\n }\n }\n })().finally(() => { maintenanceTask = undefined; });\n }\n if (!connectionTask && relay?.owner && !relay.owner.alive()) {\n await relay.close();\n relay = undefined;\n relayReachable = false; relayWasReachable = false;\n relayErrorCode = undefined;\n relayError = \"The internet tunnel disconnected. Reconnecting…\";\n nextRelayAt = Date.now() + recoveryDelay(++relayFailures);\n }\n if (relayResult) {\n const result = relayResult; relayResult = undefined; relayTask = undefined;\n if (result.handle) {\n relay = result.handle; relayError = undefined; relayErrorCode = undefined; relayReadyAt = Date.now();\n relayReachable = false; relayWasReachable = false; relayHealthFailures = 0; relayFailedAt = 0; nextCheckAt = 0;\n if (relay.owner?.identity) await writeJSON(relayPath, {\n owner: relay.owner.identity, port: websocketPort, options: JSON.stringify(config.relay), route: relay.route, outputFile: relay.outputFile, configFile: relay.configFile,\n } satisfies SavedRelay);\n } else {\n checkedAt = Date.now();\n relayError = result.error instanceof Error ? result.error.message : \"The internet tunnel couldn't connect.\";\n relayErrorCode = result.error instanceof ProviderConnectionError ? result.error.code : undefined;\n nextRelayAt = Date.now() + (providerNeedsAction(relayErrorCode) ? 60_000 : recoveryDelay(++relayFailures));\n }\n }\n if (!relay && !relayTask && !connectionTask && (Date.now() >= nextRelayAt || (requestedCheck?.requestedAt ?? 0) > checkedAt)) {\n relayError = undefined; relayErrorCode = undefined;\n relayMessage = \"Reconnecting your internet tunnel…\";\n relayTask = startRelay(config.relay, websocketPort, {\n cacheDir: path.join(directory, \"tools\"), outputDirectory: directory, cliPath: process.argv[1], signal: abort.signal,\n onProgress: message => { relayMessage = message; },\n onSpawn: async (owner, outputFile, configFile) => {\n if (owner.identity) await writeJSON(relayPath, {\n owner: owner.identity, port: websocketPort, options: JSON.stringify(config!.relay), outputFile, configFile,\n } satisfies SavedRelay);\n },\n }).then(handle => { relayResult = { handle }; }, error => { relayResult = { error }; });\n }\n\n if (checkResult) {\n const result = checkResult; checkResult = undefined; checkTask = undefined;\n // A late failure from a replaced helper cannot invalidate its successor.\n if (result.relay === relay) {\n checkedAt = Date.now();\n relayReachable = !result.error;\n if (!result.error) {\n relayWasReachable = true; relayHealthFailures = 0; relayFailedAt = 0; relayError = undefined; relayErrorCode = undefined;\n nextCheckAt = checkedAt + 30_000;\n } else {\n relayError = result.error instanceof Error ? result.error.message : \"The internet tunnel couldn't connect. Retrying…\";\n relayErrorCode = result.error instanceof RelayCheckError ? result.error.code : undefined;\n relayFailedAt ||= checkedAt;\n relayHealthFailures++;\n nextCheckAt = checkedAt + Math.min(15_000, recoveryDelay(relayHealthFailures));\n if (result.canRestart && !connectionTask) {\n // Only replace the tunnel after repeated failures with working\n // internet. The daemon, phone keys, chats and PTYs keep running.\n await phase(result.error instanceof RelayCheckError && result.error.addressMissing\n ? \"Cloudflare's address expired. Creating a new secure tunnel…\"\n : \"The internet tunnel stopped responding. Replacing it…\");\n await relay!.close(); relay = undefined;\n relayWasReachable = false; nextRelayAt = Date.now() + recoveryDelay(++relayFailures);\n await fs.rm(relayPath, { force: true });\n }\n }\n }\n }\n if (config.relay.kind === \"none\") checkedAt = Math.max(checkedAt, requestedCheck?.requestedAt ?? 0);\n if (relay?.route && !checkTask && (Date.now() >= nextCheckAt || (requestedCheck?.requestedAt ?? 0) > checkedAt)) {\n const checking = relay;\n checkTask = (async () => {\n try {\n await checkRelay(checking.route!, { signal: abort.signal });\n checkResult = { relay: checking };\n } catch (error) {\n const canRestart = !!checking.owner && relayFailedAt > 0\n && relayNeedsRestart(error, relayHealthFailures, Date.now() - relayFailedAt)\n && (error instanceof RelayCheckError && error.addressMissing\n || await relayProviderReachable(config!.relay, abort.signal).catch(() => false));\n checkResult = { relay: checking, error, canRestart };\n }\n })();\n }\n\n routes = directRoutes(config, sshPort);\n if (relay?.route && relayWasReachable) routes.push(relay.route);\n const metadata = connectionInfo(config.relay, config.host);\n const routeJSON = JSON.stringify({ routes, connection: metadata });\n if (!changingDaemon && client && child?.alive() && routeJSON !== published) {\n try { await client.computer.setRoutes(routes, metadata); published = routeJSON; }\n catch { /* Retry publication; never claim the new routes are ready yet. */ }\n }\n const ready = !!client && !!child?.alive() && !changingDaemon && routes.length > 0 && published === routeJSON\n && (config.relay.kind === \"none\" || relayReachable);\n const state: ControllerState = { ...owner, protocol: CONTROLLER_PROTOCOL, cliVersion: SDK_VERSION, ready, routes, checkedAt,\n phase: ready ? undefined : daemonError ?? relayError ?? relayMessage, error: daemonError ?? relayError,\n errorCode: daemonError ? undefined : relayErrorCode, recovering: !ready,\n discoveryError,\n relayFailureSince: relayFailedAt || undefined, relayFailures: relayHealthFailures || undefined };\n const serialized = JSON.stringify(state);\n if (serialized !== lastController) { await writeJSON(controllerPath, state); lastController = serialized; }\n\n const updatePath = path.join(directory, \"computer-update.json\");\n const update = !updateTask && !connectionTask && !maintenanceTask && client && child?.alive() ? await readJSON<ComputerUpdate>(updatePath) : undefined;\n if (activeUpdate(update)) {\n // Waiting for idle does not block relay recovery or address publication.\n updateTask = (async () => {\n const status = async (state: ComputerUpdate[\"status\"], error?: string) => writeJSON(updatePath,\n { ...update, status: state, error, updatedAt: new Date().toISOString() });\n try {\n await status(\"downloading\");\n const replacement = await ensureDaemonBinary({ version: update.version, cacheDir: process.env.MINDWIRE_RELEASE_CACHE_DIR, exactVersion: true });\n await status(\"waiting\");\n let lease: Awaited<ReturnType<Mindwire[\"service\"][\"acquireUpdate\"]>> | undefined;\n while (!stopping && !lease) {\n try { lease = await client!.service.acquireUpdate(); }\n catch (error) { if ((error as { status?: number }).status !== 409) throw error; await delay(2000); }\n }\n if (stopping || !lease) return;\n if (lease.pid !== child?.pid) { await client!.service.releaseUpdate(lease.id); throw new Error(\"The leased service process changed.\"); }\n changingDaemon = true;\n await status(\"restarting\");\n await child!.close();\n try {\n client = await launch(replacement);\n const health = await client.health();\n if (health.version.replace(/^v/, \"\") !== update.version) throw new Error(\"The replacement service reports a different release version.\");\n } catch (error) {\n if (child) await child.close();\n if (!stopping) client = await launch(binary);\n throw error;\n }\n binary = replacement;\n config = { ...config!, daemonBin: undefined, version: update.version };\n await writeJSON(path.join(directory, \"computer-config.json\"), config);\n await client.computer.setRoutes(routes, connectionInfo(config.relay, config.host)); published = \"\";\n await status(\"complete\");\n maintenanceFailures = 0;\n } catch (error) {\n maintenanceFailures++;\n await status(\"failed\", error instanceof Error ? error.message : \"Service update failed.\");\n }\n finally { changingDaemon = false; published = \"\"; nextMaintenanceAt = Date.now() + recoveryDelay(maintenanceFailures); }\n })().finally(() => { updateTask = undefined; });\n }\n await delay(500);\n }\n } catch (error) {\n await writeJSON(controllerPath, { ...owner, ready: false, error: error instanceof Error ? error.message : \"Computer service failed.\" });\n throw error;\n } finally {\n abort.abort();\n await relayTask; await checkTask; await updateTask; await connectionTask; await maintenanceTask;\n if (relayResult?.handle && relayResult.handle !== relay) await relayResult.handle.close();\n await relay?.close();\n if (child) await child.close();\n process.off(\"SIGTERM\", stop); process.off(\"SIGINT\", stop);\n if (stopping) await writeJSON(controllerPath, { pid: 0, ready: false });\n }\n}\n"]}
|