mindwire 0.1.36 → 0.1.40
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 +16 -0
- package/dist/{chunk-RTGZDLSG.js → chunk-BJL5K6M7.js} +74 -21
- package/dist/chunk-BJL5K6M7.js.map +1 -0
- package/dist/chunk-ZP7F7LP7.js +306 -0
- package/dist/chunk-ZP7F7LP7.js.map +1 -0
- package/dist/cli.js +499 -250
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +6 -8
- 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-IBNL42BL.js → connection-change-7ZV6O75Q.js} +3 -3
- package/dist/{connection-change-IBNL42BL.js.map → connection-change-7ZV6O75Q.js.map} +1 -1
- package/dist/{controller-2SJLZMJZ.js → controller-FBMGMSLM.js} +67 -9
- package/dist/controller-FBMGMSLM.js.map +1 -0
- package/dist/{controller-handoff-RUUHODNC.js → controller-handoff-CJKXUFQI.js} +3 -3
- package/dist/{controller-handoff-RUUHODNC.js.map → controller-handoff-CJKXUFQI.js.map} +1 -1
- package/dist/conversations.d.ts +57 -0
- package/dist/daemon-binary.d.ts +2 -0
- package/dist/index.cjs +66 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +66 -13
- 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 +18 -0
- package/dist/workspace.d.ts +2 -0
- package/package.json +1 -1
- package/dist/chunk-67BNDGRK.js +0 -20
- package/dist/chunk-67BNDGRK.js.map +0 -1
- package/dist/chunk-RTGZDLSG.js.map +0 -1
- package/dist/controller-2SJLZMJZ.js.map +0 -1
package/dist/client.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { ExecutionApi } from "./execution.js";
|
|
|
7
7
|
import { ComputerApi } from "./computer.js";
|
|
8
8
|
import { type Target } from "./target/index.js";
|
|
9
9
|
import type { EnsureEvent } from "./target/host.js";
|
|
10
|
-
import type { AgentInfo, AuthMethod, AuthState, AuthStatus, Catalog, ChatSummary, CustomProvider, DeleteResult, DoctorReport, Health, MCPServer, MemoryDoc, MemoryScope, Message, MessagePage, ModelInfo, Notification, NotifyChannel, NotifyChannelInput, NotifyChannelTestResult, NotifyConfigInput, NotifyConfigStatus, NotifyRule, NotifyRuleInput, ProcessFrame, PromptTemplate, ResolveOptions, SetupStatus, HarnessSoftware, Stats, Subagent, TurnOptions } from "./types.js";
|
|
10
|
+
import type { AgentInfo, AuthMethod, AuthState, AuthStatus, Catalog, ChatSummary, ChatForkResult, ForkChatOptions, CustomProvider, DeleteResult, DoctorReport, Health, MCPServer, MemoryDoc, MemoryScope, Message, MessagePage, ModelInfo, Notification, NotifyChannel, NotifyChannelInput, NotifyChannelTestResult, NotifyConfigInput, NotifyConfigStatus, NotifyRule, NotifyRuleInput, ProcessFrame, PromptTemplate, ResolveOptions, SetupStatus, HarnessSoftware, Stats, Subagent, TurnOptions } from "./types.js";
|
|
11
11
|
export interface MindwireOptions {
|
|
12
12
|
/**
|
|
13
13
|
* Default agent type for agent-scoped calls (e.g. `"claude-code"`). When omitted, the daemon
|
|
@@ -172,14 +172,12 @@ export declare class Mindwire {
|
|
|
172
172
|
deleteChat(chatId: string): Promise<DeleteResult>;
|
|
173
173
|
/**
|
|
174
174
|
* `POST /chats/{id}/fork` — clone a chat into a new id (generated when `newChatId` is omitted).
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
175
|
+
* Codex and Claude preserve native context. `beforeMessageId` excludes that prompt and every
|
|
176
|
+
* later message; send the edited prompt to the returned chat with `turn`. Reuse `newChatId`
|
|
177
|
+
* and the turn's `requestId` on retries. The source chat and filesystem are unchanged.
|
|
178
|
+
* A source with a live turn returns 409; an unknown source returns 404.
|
|
179
179
|
*/
|
|
180
|
-
forkChat(chatId: string, opts?:
|
|
181
|
-
newChatId?: string;
|
|
182
|
-
}): Promise<ChatSummary>;
|
|
180
|
+
forkChat(chatId: string, opts?: ForkChatOptions): Promise<ChatForkResult>;
|
|
183
181
|
/**
|
|
184
182
|
* `GET /chats/{id}/messages` — a chat's transcript (native when the agent supports it, else
|
|
185
183
|
* the recorded fallback). `limit` caps to the newest N; `before` pages older history.
|
|
@@ -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-BJL5K6M7.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-7ZV6O75Q.js.map
|
|
41
|
+
//# sourceMappingURL=connection-change-7ZV6O75Q.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-7ZV6O75Q.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-ZP7F7LP7.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-BJL5K6M7.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-FBMGMSLM.js.map
|
|
771
|
+
//# sourceMappingURL=controller-FBMGMSLM.js.map
|