SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
4e23b01 verified
Raw
History Blame Contribute Delete
5.85 kB
import { assign, createActor, fromPromise, setup, waitFor } from '@moonshot-ai/agent-core-v2/human/xstate2';
import { startRemoteControl, type RemoteControlHandle } from './remote-control';
export type RemoteControlState = 'off' | 'starting' | 'on' | 'stopping';
export interface RemoteControlStatusInfo {
readonly enabled: boolean;
readonly state: RemoteControlState;
readonly url?: string;
readonly deviceId?: string;
readonly deviceName?: string;
readonly error?: string;
}
export interface RemoteControlManager {
status(): RemoteControlStatusInfo;
enable(): Promise<RemoteControlStatusInfo>;
disable(): Promise<RemoteControlStatusInfo>;
close(): Promise<void>;
}
export interface RemoteControlManagerOptions {
readonly homeDir: string;
readonly localOrigin: () => string;
readonly localServerToken: () => string;
readonly clientVersion: string;
readonly relayOrigin?: string;
readonly stderr?: Pick<NodeJS.WriteStream, 'write'>;
}
interface RemoteControlMachineContext {
readonly handle?: RemoteControlHandle;
readonly error?: unknown;
}
type RemoteControlMachineEvent = { type: 'enable' } | { type: 'disable' } | { type: 'tunnel.exited' };
function createRemoteControlMachine(
options: RemoteControlManagerOptions,
onTunnelStarted: (handle: RemoteControlHandle) => void,
) {
return setup({
types: {
context: {} as RemoteControlMachineContext,
events: {} as RemoteControlMachineEvent,
},
actors: {
startTunnel: fromPromise<RemoteControlHandle, void>(async () => {
const handle = await startRemoteControl({
homeDir: options.homeDir,
localOrigin: options.localOrigin(),
localServerToken: options.localServerToken,
clientVersion: options.clientVersion,
relayOrigin: options.relayOrigin,
stderr: options.stderr,
});
onTunnelStarted(handle);
return handle;
}),
stopTunnel: fromPromise<void, RemoteControlHandle | undefined>(async ({ input }) => {
await input?.close();
}),
},
}).createMachine({
id: 'remoteControl',
initial: 'off',
context: { handle: undefined, error: undefined },
states: {
off: {
on: { enable: 'starting', 'tunnel.exited': {} },
},
starting: {
on: { enable: {} },
invoke: {
src: 'startTunnel',
onDone: {
target: 'on',
actions: assign({ handle: ({ event }) => event.output, error: undefined }),
},
onError: {
target: 'off',
actions: assign({ handle: undefined, error: ({ event }) => event.error }),
},
},
},
on: {
on: {
disable: 'stopping',
'tunnel.exited': { target: 'off', actions: assign({ handle: undefined }) },
},
},
stopping: {
on: { disable: {}, 'tunnel.exited': {} },
invoke: {
src: 'stopTunnel',
input: ({ context }) => context.handle,
onDone: { target: 'off', actions: assign({ handle: undefined }) },
onError: {
target: 'off',
actions: assign({ handle: undefined, error: ({ event }) => event.error }),
},
},
},
},
});
}
export function createRemoteControlManager(
options: RemoteControlManagerOptions,
): RemoteControlManager {
const actor = createActor(
createRemoteControlMachine(options, (handle) => {
void handle.closed.then(
() => {
actor.send({ type: 'tunnel.exited' });
},
(error) => {
options.stderr?.write(`remote-control lock release failed: ${errorMessage(error)}\n`);
actor.send({ type: 'tunnel.exited' });
},
);
}),
);
actor.start();
const status = (): RemoteControlStatusInfo => {
const snap = actor.getSnapshot();
const state = snap.value as RemoteControlState;
const handle = snap.context.handle;
const error = snap.context.error;
return {
enabled: state === 'on',
state,
url: handle?.url,
deviceId: handle?.deviceId,
deviceName: handle?.deviceName,
error: error === undefined ? undefined : errorMessage(error),
};
};
const settle = () =>
waitFor(actor, (snap) => snap.value === 'on' || snap.value === 'off');
const enable = async (): Promise<RemoteControlStatusInfo> => {
const snap = actor.getSnapshot();
if (snap.value === 'on') return status();
if (snap.value === 'stopping') {
await waitFor(actor, (s) => s.value === 'off');
} else if (snap.value === 'starting') {
const settled = await settle();
if (settled.value === 'on') return status();
throw settled.context.error;
}
actor.send({ type: 'enable' });
const settled = await settle();
if (settled.value === 'on') return status();
throw settled.context.error;
};
const disable = async (): Promise<RemoteControlStatusInfo> => {
const snap = actor.getSnapshot();
if (snap.value === 'off') return status();
if (snap.value === 'starting') {
const settled = await settle();
if (settled.value === 'off') return status();
} else if (snap.value === 'stopping') {
await waitFor(actor, (s) => s.value === 'off');
return status();
}
actor.send({ type: 'disable' });
await waitFor(actor, (s) => s.value === 'off');
return status();
};
const close = async (): Promise<void> => {
try {
await disable();
} catch (error) {
options.stderr?.write(`remote-control shutdown failed: ${errorMessage(error)}\n`);
} finally {
actor.stop();
}
};
return { status, enable, disable, close };
}
function errorMessage(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}