@abitat_reece/host-daemon 0.1.20 → 0.1.22
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/dist/local-control/codex-bridge.d.ts.map +1 -1
- package/dist/local-control/codex-bridge.js +177 -18
- package/dist/local-control/codex-bridge.js.map +1 -1
- package/dist/local-control/push-notifications.d.ts +2 -2
- package/dist/local-control/push-notifications.d.ts.map +1 -1
- package/dist/local-control/push-notifications.js +3 -1
- package/dist/local-control/push-notifications.js.map +1 -1
- package/dist/local-control/relay-client.d.ts +10 -3
- package/dist/local-control/relay-client.d.ts.map +1 -1
- package/dist/local-control/relay-client.js.map +1 -1
- package/dist/local-control/remote-control/macos-driver.d.ts +16 -0
- package/dist/local-control/remote-control/macos-driver.d.ts.map +1 -0
- package/dist/local-control/remote-control/macos-driver.js +440 -0
- package/dist/local-control/remote-control/macos-driver.js.map +1 -0
- package/dist/local-control/remote-control/routes.d.ts +20 -0
- package/dist/local-control/remote-control/routes.d.ts.map +1 -0
- package/dist/local-control/remote-control/routes.js +110 -0
- package/dist/local-control/remote-control/routes.js.map +1 -0
- package/dist/local-control/remote-control/session-manager.d.ts +10 -0
- package/dist/local-control/remote-control/session-manager.d.ts.map +1 -0
- package/dist/local-control/remote-control/session-manager.js +259 -0
- package/dist/local-control/remote-control/session-manager.js.map +1 -0
- package/dist/local-control/remote-control/types.d.ts +49 -0
- package/dist/local-control/remote-control/types.d.ts.map +1 -0
- package/dist/local-control/remote-control/types.js +2 -0
- package/dist/local-control/remote-control/types.js.map +1 -0
- package/dist/local-control/server.d.ts +7 -2
- package/dist/local-control/server.d.ts.map +1 -1
- package/dist/local-control/server.js +24 -86
- package/dist/local-control/server.js.map +1 -1
- package/dist/local-control/transport.d.ts +6 -2
- package/dist/local-control/transport.d.ts.map +1 -1
- package/dist/local-control/transport.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
const DEFAULT_FRAME_INTERVAL_MS = 120;
|
|
3
|
+
const stoppedStatuses = new Set(["ended", "failed"]);
|
|
4
|
+
export function createLocalRemoteControlManager(options) {
|
|
5
|
+
const states = new Map();
|
|
6
|
+
const now = options.now ?? (() => new Date());
|
|
7
|
+
const idGenerator = options.idGenerator ??
|
|
8
|
+
((prefix) => `${prefix}_${randomUUID().replaceAll("-", "").slice(0, 16)}`);
|
|
9
|
+
const frameIntervalMs = options.frameIntervalMs ?? DEFAULT_FRAME_INTERVAL_MS;
|
|
10
|
+
async function captureNextFrame(sessionId) {
|
|
11
|
+
const state = states.get(sessionId);
|
|
12
|
+
if (!state || stoppedStatuses.has(state.session.status)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (state.isFrameCaptureInFlight) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
state.isFrameCaptureInFlight = true;
|
|
19
|
+
try {
|
|
20
|
+
const nextFrame = await options.driver.captureFrame(state.session);
|
|
21
|
+
if (stoppedStatuses.has(state.session.status)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
state.latestFrame = nextFrame;
|
|
25
|
+
state.session = {
|
|
26
|
+
...state.session,
|
|
27
|
+
errorMessage: null,
|
|
28
|
+
permissionState: {
|
|
29
|
+
...state.session.permissionState,
|
|
30
|
+
screenRecording: "granted"
|
|
31
|
+
},
|
|
32
|
+
status: "active",
|
|
33
|
+
updatedAt: now().toISOString()
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (stoppedStatuses.has(state.session.status)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const permission = permissionKind(error);
|
|
41
|
+
state.session = {
|
|
42
|
+
...state.session,
|
|
43
|
+
errorMessage: error instanceof Error ? error.message : "Unable to capture Mac screen",
|
|
44
|
+
permissionState: {
|
|
45
|
+
...state.session.permissionState,
|
|
46
|
+
screenRecording: permission === "screenRecording" ? "needed" : state.session.permissionState.screenRecording
|
|
47
|
+
},
|
|
48
|
+
status: permission === "screenRecording" ? "failed" : state.session.status,
|
|
49
|
+
updatedAt: now().toISOString()
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
state.isFrameCaptureInFlight = false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function startFrameLoop(state) {
|
|
57
|
+
if (!state.session.screenEnabled || state.frameTimer) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
state.frameTimer = setInterval(() => {
|
|
61
|
+
void captureNextFrame(state.session.id);
|
|
62
|
+
}, frameIntervalMs);
|
|
63
|
+
state.frameTimer.unref?.();
|
|
64
|
+
void captureNextFrame(state.session.id);
|
|
65
|
+
}
|
|
66
|
+
function requireSession(sessionId, clientMachineId) {
|
|
67
|
+
const state = states.get(sessionId);
|
|
68
|
+
if (!state || state.session.clientMachineId !== clientMachineId) {
|
|
69
|
+
throw Object.assign(new Error("Remote-control session not found"), { statusCode: 404 });
|
|
70
|
+
}
|
|
71
|
+
return state;
|
|
72
|
+
}
|
|
73
|
+
function activeSessionFor(input) {
|
|
74
|
+
return [...states.values()].find((state) => state.session.clientMachineId === input.clientMachineId &&
|
|
75
|
+
state.session.hostMachineId === input.hostMachineId &&
|
|
76
|
+
!stoppedStatuses.has(state.session.status));
|
|
77
|
+
}
|
|
78
|
+
async function readCursorPosition() {
|
|
79
|
+
if (!options.driver.getCursorPosition) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
return await options.driver.getCursorPosition();
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function readTextInputTarget() {
|
|
90
|
+
if (!options.driver.getTextInputTarget) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return options.driver.getTextInputTarget();
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
async applyInput(sessionId, clientMachineId, event) {
|
|
97
|
+
const state = requireSession(sessionId, clientMachineId);
|
|
98
|
+
if (stoppedStatuses.has(state.session.status)) {
|
|
99
|
+
throw Object.assign(new Error("Remote-control session is not active"), {
|
|
100
|
+
statusCode: 409
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (!state.session.inputEnabled) {
|
|
104
|
+
throw Object.assign(new Error("Remote-control input is disabled for this session"), {
|
|
105
|
+
statusCode: 403
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const inputResult = await options.driver.applyInput(state.session, event);
|
|
110
|
+
const cursorPosition = inputResult && "cursorPosition" in inputResult
|
|
111
|
+
? inputResult.cursorPosition
|
|
112
|
+
: state.session.cursorPosition;
|
|
113
|
+
state.session = {
|
|
114
|
+
...state.session,
|
|
115
|
+
cursorPosition,
|
|
116
|
+
errorMessage: null,
|
|
117
|
+
permissionState: {
|
|
118
|
+
...state.session.permissionState,
|
|
119
|
+
accessibility: "granted"
|
|
120
|
+
},
|
|
121
|
+
updatedAt: now().toISOString()
|
|
122
|
+
};
|
|
123
|
+
return state.session;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
const permission = permissionKind(error);
|
|
127
|
+
state.session = {
|
|
128
|
+
...state.session,
|
|
129
|
+
errorMessage: error instanceof Error ? error.message : "Unable to send Mac input",
|
|
130
|
+
permissionState: {
|
|
131
|
+
...state.session.permissionState,
|
|
132
|
+
accessibility: permission === "accessibility" ? "needed" : state.session.permissionState.accessibility
|
|
133
|
+
},
|
|
134
|
+
updatedAt: now().toISOString()
|
|
135
|
+
};
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
async captureNextFrameForTest(sessionId) {
|
|
140
|
+
await captureNextFrame(sessionId);
|
|
141
|
+
},
|
|
142
|
+
async endSession(sessionId, clientMachineId) {
|
|
143
|
+
const state = requireSession(sessionId, clientMachineId);
|
|
144
|
+
if (state.frameTimer) {
|
|
145
|
+
clearInterval(state.frameTimer);
|
|
146
|
+
state.frameTimer = null;
|
|
147
|
+
}
|
|
148
|
+
state.session = {
|
|
149
|
+
...state.session,
|
|
150
|
+
status: "ended",
|
|
151
|
+
updatedAt: now().toISOString()
|
|
152
|
+
};
|
|
153
|
+
state.latestFrame = null;
|
|
154
|
+
await options.driver.closeSession(state.session);
|
|
155
|
+
return state.session;
|
|
156
|
+
},
|
|
157
|
+
getLatestFrame(sessionId, clientMachineId, afterSequence = -1) {
|
|
158
|
+
const state = requireSession(sessionId, clientMachineId);
|
|
159
|
+
return {
|
|
160
|
+
frame: state.latestFrame && state.latestFrame.sequence > afterSequence ? state.latestFrame : null,
|
|
161
|
+
session: state.session
|
|
162
|
+
};
|
|
163
|
+
},
|
|
164
|
+
getSession(sessionId, clientMachineId) {
|
|
165
|
+
return requireSession(sessionId, clientMachineId).session;
|
|
166
|
+
},
|
|
167
|
+
async getTextInputTarget(sessionId, clientMachineId) {
|
|
168
|
+
const state = requireSession(sessionId, clientMachineId);
|
|
169
|
+
if (stoppedStatuses.has(state.session.status)) {
|
|
170
|
+
throw Object.assign(new Error("Remote-control session is not active"), {
|
|
171
|
+
statusCode: 409
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const target = await readTextInputTarget();
|
|
176
|
+
state.session = {
|
|
177
|
+
...state.session,
|
|
178
|
+
errorMessage: null,
|
|
179
|
+
permissionState: {
|
|
180
|
+
...state.session.permissionState,
|
|
181
|
+
accessibility: options.driver.getTextInputTarget
|
|
182
|
+
? "granted"
|
|
183
|
+
: state.session.permissionState.accessibility
|
|
184
|
+
},
|
|
185
|
+
updatedAt: now().toISOString()
|
|
186
|
+
};
|
|
187
|
+
return target;
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
const permission = permissionKind(error);
|
|
191
|
+
state.session = {
|
|
192
|
+
...state.session,
|
|
193
|
+
errorMessage: error instanceof Error ? error.message : "Unable to inspect Mac text input focus",
|
|
194
|
+
permissionState: {
|
|
195
|
+
...state.session.permissionState,
|
|
196
|
+
accessibility: permission === "accessibility" ? "needed" : state.session.permissionState.accessibility
|
|
197
|
+
},
|
|
198
|
+
updatedAt: now().toISOString()
|
|
199
|
+
};
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
listSessions(clientMachineId) {
|
|
204
|
+
return [...states.values()]
|
|
205
|
+
.map((state) => state.session)
|
|
206
|
+
.filter((session) => session.clientMachineId === clientMachineId);
|
|
207
|
+
},
|
|
208
|
+
async startSession(input) {
|
|
209
|
+
const existing = activeSessionFor(input);
|
|
210
|
+
if (existing) {
|
|
211
|
+
return existing.session;
|
|
212
|
+
}
|
|
213
|
+
const timestamp = now().toISOString();
|
|
214
|
+
const cursorPosition = await readCursorPosition();
|
|
215
|
+
const session = {
|
|
216
|
+
id: idGenerator("remote"),
|
|
217
|
+
status: "connecting",
|
|
218
|
+
hostMachineId: input.hostMachineId,
|
|
219
|
+
clientMachineId: input.clientMachineId,
|
|
220
|
+
screenEnabled: input.screenEnabled,
|
|
221
|
+
inputEnabled: input.inputEnabled,
|
|
222
|
+
permissionState: {
|
|
223
|
+
accessibility: "unknown",
|
|
224
|
+
screenRecording: "unknown"
|
|
225
|
+
},
|
|
226
|
+
cursorPosition,
|
|
227
|
+
errorMessage: null,
|
|
228
|
+
createdAt: timestamp,
|
|
229
|
+
updatedAt: timestamp
|
|
230
|
+
};
|
|
231
|
+
const state = {
|
|
232
|
+
frameTimer: null,
|
|
233
|
+
isFrameCaptureInFlight: false,
|
|
234
|
+
latestFrame: null,
|
|
235
|
+
session
|
|
236
|
+
};
|
|
237
|
+
states.set(session.id, state);
|
|
238
|
+
startFrameLoop(state);
|
|
239
|
+
return session;
|
|
240
|
+
},
|
|
241
|
+
async stopAll() {
|
|
242
|
+
await Promise.all([...states.values()].map(async (state) => {
|
|
243
|
+
if (state.frameTimer) {
|
|
244
|
+
clearInterval(state.frameTimer);
|
|
245
|
+
state.frameTimer = null;
|
|
246
|
+
}
|
|
247
|
+
await options.driver.closeSession(state.session);
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function permissionKind(error) {
|
|
253
|
+
if (typeof error === "object" && error && "permission" in error) {
|
|
254
|
+
const value = error.permission;
|
|
255
|
+
return value === "screenRecording" || value === "accessibility" ? value : null;
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=session-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/local-control/remote-control/session-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { RemoteControlCursorPosition, RemoteControlFrame, RemoteControlStatus, RemoteControlTextTarget, RemoteInputEvent } from "@abitat_reece/shared";
|
|
2
|
+
export type RemoteControlPermissionState = "unknown" | "granted" | "needed";
|
|
3
|
+
export interface LocalRemoteControlPermissionState {
|
|
4
|
+
accessibility: RemoteControlPermissionState;
|
|
5
|
+
screenRecording: RemoteControlPermissionState;
|
|
6
|
+
}
|
|
7
|
+
export interface LocalRemoteControlSession {
|
|
8
|
+
id: string;
|
|
9
|
+
status: RemoteControlStatus;
|
|
10
|
+
hostMachineId: string;
|
|
11
|
+
clientMachineId: string;
|
|
12
|
+
screenEnabled: boolean;
|
|
13
|
+
inputEnabled: boolean;
|
|
14
|
+
permissionState: LocalRemoteControlPermissionState;
|
|
15
|
+
cursorPosition?: RemoteControlCursorPosition | null;
|
|
16
|
+
errorMessage?: string | null;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
}
|
|
20
|
+
export interface LocalRemoteControlStartInput {
|
|
21
|
+
hostMachineId: string;
|
|
22
|
+
clientMachineId: string;
|
|
23
|
+
screenEnabled: boolean;
|
|
24
|
+
inputEnabled: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface LocalRemoteControlDriver {
|
|
27
|
+
captureFrame(session: LocalRemoteControlSession): Promise<RemoteControlFrame>;
|
|
28
|
+
applyInput(session: LocalRemoteControlSession, event: RemoteInputEvent): Promise<{
|
|
29
|
+
cursorPosition?: RemoteControlCursorPosition | null;
|
|
30
|
+
} | void>;
|
|
31
|
+
closeSession(session: LocalRemoteControlSession): Promise<void>;
|
|
32
|
+
getCursorPosition?(): Promise<RemoteControlCursorPosition | null>;
|
|
33
|
+
getTextInputTarget?(): Promise<RemoteControlTextTarget | null>;
|
|
34
|
+
}
|
|
35
|
+
export interface LocalRemoteControlManager {
|
|
36
|
+
applyInput(sessionId: string, clientMachineId: string, event: RemoteInputEvent): Promise<LocalRemoteControlSession>;
|
|
37
|
+
captureNextFrameForTest(sessionId: string): Promise<void>;
|
|
38
|
+
endSession(sessionId: string, clientMachineId: string): Promise<LocalRemoteControlSession>;
|
|
39
|
+
getLatestFrame(sessionId: string, clientMachineId: string, afterSequence?: number): {
|
|
40
|
+
frame: RemoteControlFrame | null;
|
|
41
|
+
session: LocalRemoteControlSession;
|
|
42
|
+
};
|
|
43
|
+
getSession(sessionId: string, clientMachineId: string): LocalRemoteControlSession;
|
|
44
|
+
getTextInputTarget(sessionId: string, clientMachineId: string): Promise<RemoteControlTextTarget | null>;
|
|
45
|
+
listSessions(clientMachineId: string): LocalRemoteControlSession[];
|
|
46
|
+
startSession(input: LocalRemoteControlStartInput): Promise<LocalRemoteControlSession>;
|
|
47
|
+
stopAll(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/local-control/remote-control/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,2BAA2B,EAC3B,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5E,MAAM,WAAW,iCAAiC;IAChD,aAAa,EAAE,4BAA4B,CAAC;IAC5C,eAAe,EAAE,4BAA4B,CAAC;CAC/C;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,mBAAmB,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,iCAAiC,CAAC;IACnD,cAAc,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,YAAY,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC9E,UAAU,CACR,OAAO,EAAE,yBAAyB,EAClC,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC;QAAE,cAAc,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC3E,YAAY,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,CAAC,IAAI,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CAAC;IAClE,kBAAkB,CAAC,IAAI,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,CACR,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACtC,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC3F,cAAc,CACZ,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,EACvB,aAAa,CAAC,EAAE,MAAM,GACrB;QACD,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;QACjC,OAAO,EAAE,yBAAyB,CAAC;KACpC,CAAC;IACF,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,yBAAyB,CAAC;IAClF,kBAAkB,CAChB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;IAC3C,YAAY,CAAC,eAAe,EAAE,MAAM,GAAG,yBAAyB,EAAE,CAAC;IACnE,YAAY,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACtF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/local-control/remote-control/types.ts"],"names":[],"mappings":""}
|
|
@@ -3,6 +3,7 @@ import type { CodexMobileModelSettings, CodexModelOption, ConversationStatus } f
|
|
|
3
3
|
import { type LocalControlStore, type LocalControlTransport } from "./state.js";
|
|
4
4
|
import { type MobileControlDiagnosticsLogger } from "./diagnostics-log.js";
|
|
5
5
|
import { type CodexTokenUsageSummary } from "./token-usage.js";
|
|
6
|
+
import { type LocalRemoteControlManager } from "./remote-control/session-manager.js";
|
|
6
7
|
export interface LocalCodexProjectSummary {
|
|
7
8
|
id: string;
|
|
8
9
|
workspaceId: string;
|
|
@@ -67,6 +68,9 @@ export interface LocalCodexCompletionState {
|
|
|
67
68
|
updatedAt: string;
|
|
68
69
|
workspaceId: string;
|
|
69
70
|
}
|
|
71
|
+
export interface LocalCodexCompletionStateOptions {
|
|
72
|
+
hydrateIdleSummariesSince?: number;
|
|
73
|
+
}
|
|
70
74
|
export interface LocalCodexBridge {
|
|
71
75
|
bootstrap(): Promise<{
|
|
72
76
|
available: boolean;
|
|
@@ -97,7 +101,7 @@ export interface LocalCodexBridge {
|
|
|
97
101
|
status: ConversationStatus | string;
|
|
98
102
|
updated: boolean;
|
|
99
103
|
}>;
|
|
100
|
-
listCompletionStates(): Promise<LocalCodexCompletionState[]>;
|
|
104
|
+
listCompletionStates(options?: LocalCodexCompletionStateOptions): Promise<LocalCodexCompletionState[]>;
|
|
101
105
|
downloadGeneratedFile(conversationId: string, fileId: string): Promise<LocalGeneratedFileDownload>;
|
|
102
106
|
listMessages(conversationId: string, options?: {
|
|
103
107
|
afterSequence?: number;
|
|
@@ -129,6 +133,7 @@ interface StartLocalControlServerInput {
|
|
|
129
133
|
diagnostics?: MobileControlDiagnosticsLogger;
|
|
130
134
|
endpoint: string;
|
|
131
135
|
port: number;
|
|
136
|
+
remoteControl?: LocalRemoteControlManager;
|
|
132
137
|
store: LocalControlStore;
|
|
133
138
|
tokenUsageProvider?: () => Promise<CodexTokenUsageSummary>;
|
|
134
139
|
transport: LocalControlTransport;
|
|
@@ -136,7 +141,7 @@ interface StartLocalControlServerInput {
|
|
|
136
141
|
export declare function startLocalControlServer(input: StartLocalControlServerInput): Promise<{
|
|
137
142
|
readonly endpoint: string;
|
|
138
143
|
server: Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
139
|
-
close
|
|
144
|
+
close(): Promise<void>;
|
|
140
145
|
}>;
|
|
141
146
|
export {};
|
|
142
147
|
//# sourceMappingURL=server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/local-control/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAKjG,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/local-control/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,13 +5,18 @@ import { dirname, join } from "node:path";
|
|
|
5
5
|
import { defaultLocalAttachmentDirectory } from "./state.js";
|
|
6
6
|
import { attachmentDiagnostics, errorDiagnostics, logDiagnostics, mobileControlDiagnosticsLogPath, promptDiagnostics } from "./diagnostics-log.js";
|
|
7
7
|
import { readCodexTokenUsageSummary } from "./token-usage.js";
|
|
8
|
+
import { createMacOsRemoteControlDriver } from "./remote-control/macos-driver.js";
|
|
9
|
+
import { handleLocalRemoteControlRoute } from "./remote-control/routes.js";
|
|
10
|
+
import { createLocalRemoteControlManager } from "./remote-control/session-manager.js";
|
|
8
11
|
const LOCAL_WORKSPACE_ID = "local";
|
|
9
12
|
const MOBILE_DIAGNOSTICS_LOG_LIMIT_BYTES = 3 * 1024 * 1024;
|
|
10
13
|
export async function startLocalControlServer(input) {
|
|
11
14
|
const identity = await input.store.getMacIdentity();
|
|
12
15
|
const diagnostics = input.diagnostics;
|
|
13
|
-
const
|
|
14
|
-
|
|
16
|
+
const remoteControl = input.remoteControl ??
|
|
17
|
+
createLocalRemoteControlManager({
|
|
18
|
+
driver: createMacOsRemoteControlDriver()
|
|
19
|
+
});
|
|
15
20
|
let endpoint = input.endpoint;
|
|
16
21
|
const server = createServer(async (request, response) => {
|
|
17
22
|
const method = request.method ?? "GET";
|
|
@@ -377,77 +382,19 @@ export async function startLocalControlServer(input) {
|
|
|
377
382
|
writeJson(response, 201, { attachment });
|
|
378
383
|
return;
|
|
379
384
|
}
|
|
380
|
-
if (
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
-
if (method === "POST" &&
|
|
394
|
-
(path === "/api/remote-control/sessions" || path === "/remote-control/start")) {
|
|
395
|
-
const body = await readJson(request);
|
|
396
|
-
const hostMachineId = stringValue(body.hostMachineId) || identity.macId;
|
|
397
|
-
if (hostMachineId !== identity.macId) {
|
|
398
|
-
throw Object.assign(new Error("Phone is not paired to this Mac host"), {
|
|
399
|
-
statusCode: 403
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
const timestamp = new Date().toISOString();
|
|
403
|
-
const session = {
|
|
404
|
-
id: `remote_${randomBytes(8).toString("hex")}`,
|
|
405
|
-
status: "requested",
|
|
406
|
-
hostMachineId,
|
|
407
|
-
clientMachineId: actor.id,
|
|
408
|
-
screenEnabled: body.screenEnabled !== false,
|
|
409
|
-
inputEnabled: body.inputEnabled !== false,
|
|
410
|
-
errorMessage: null,
|
|
411
|
-
createdAt: timestamp,
|
|
412
|
-
updatedAt: timestamp
|
|
413
|
-
};
|
|
414
|
-
sessions.set(session.id, session);
|
|
415
|
-
writeJson(response, 201, { session });
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
const remoteSessionMatch = matchPath(path, "/api/remote-control/sessions/:sessionId");
|
|
419
|
-
if (remoteSessionMatch && method === "DELETE") {
|
|
420
|
-
const session = requireRemoteSession(sessions, remoteSessionMatch.sessionId, actor.id);
|
|
421
|
-
const ended = { ...session, status: "ended", updatedAt: new Date().toISOString() };
|
|
422
|
-
sessions.set(session.id, ended);
|
|
423
|
-
writeJson(response, 200, { session: ended });
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
const signalMatch = matchPath(path, "/api/remote-control/sessions/:sessionId/signals");
|
|
427
|
-
if (signalMatch && method === "GET") {
|
|
428
|
-
requireRemoteSession(sessions, signalMatch.sessionId, actor.id);
|
|
429
|
-
writeJson(response, 200, {
|
|
430
|
-
signals: signals.filter((signal) => signal.sessionId === signalMatch.sessionId &&
|
|
431
|
-
(!signal.recipientMachineId || signal.recipientMachineId === actor.id))
|
|
432
|
-
});
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
if ((signalMatch && method === "POST") ||
|
|
436
|
-
(path === "/remote-control/input" && method === "POST")) {
|
|
437
|
-
const body = await readJson(request);
|
|
438
|
-
const sessionId = signalMatch?.sessionId ?? stringValue(body.sessionId);
|
|
439
|
-
const session = requireRemoteSession(sessions, sessionId, actor.id);
|
|
440
|
-
const signal = {
|
|
441
|
-
id: `signal_${randomBytes(8).toString("hex")}`,
|
|
442
|
-
sessionId: session.id,
|
|
443
|
-
senderMachineId: actor.id,
|
|
444
|
-
recipientMachineId: stringValue(body.recipientMachineId) || identity.macId,
|
|
445
|
-
type: stringValue(body.type) || "input",
|
|
446
|
-
payload: recordValue(body.payload) ?? { event: body.event },
|
|
447
|
-
createdAt: new Date().toISOString()
|
|
448
|
-
};
|
|
449
|
-
signals.push(signal);
|
|
450
|
-
writeJson(response, 201, { signal });
|
|
385
|
+
if (await handleLocalRemoteControlRoute({
|
|
386
|
+
actor,
|
|
387
|
+
diagnostics,
|
|
388
|
+
hostMachineId: identity.macId,
|
|
389
|
+
manager: remoteControl,
|
|
390
|
+
method,
|
|
391
|
+
path,
|
|
392
|
+
readJson,
|
|
393
|
+
request,
|
|
394
|
+
response,
|
|
395
|
+
searchParams: url.searchParams,
|
|
396
|
+
writeJson
|
|
397
|
+
})) {
|
|
451
398
|
return;
|
|
452
399
|
}
|
|
453
400
|
writeJson(response, 404, { error: "Not found" });
|
|
@@ -487,7 +434,10 @@ export async function startLocalControlServer(input) {
|
|
|
487
434
|
return endpoint;
|
|
488
435
|
},
|
|
489
436
|
server,
|
|
490
|
-
close
|
|
437
|
+
async close() {
|
|
438
|
+
await remoteControl.stopAll();
|
|
439
|
+
await closeServer(server);
|
|
440
|
+
}
|
|
491
441
|
};
|
|
492
442
|
}
|
|
493
443
|
async function readAndClearMobileDiagnosticsLog(diagnostics) {
|
|
@@ -578,13 +528,6 @@ async function requireMobileDevice(request, store) {
|
|
|
578
528
|
function hasAuthorizationHeader(request) {
|
|
579
529
|
return typeof request.headers.authorization === "string" && request.headers.authorization !== "";
|
|
580
530
|
}
|
|
581
|
-
function requireRemoteSession(sessions, sessionId, clientMachineId) {
|
|
582
|
-
const session = sessions.get(sessionId);
|
|
583
|
-
if (!session || session.clientMachineId !== clientMachineId) {
|
|
584
|
-
throw Object.assign(new Error("Remote-control session not found"), { statusCode: 404 });
|
|
585
|
-
}
|
|
586
|
-
return session;
|
|
587
|
-
}
|
|
588
531
|
async function readJson(request) {
|
|
589
532
|
const chunks = [];
|
|
590
533
|
for await (const chunk of request) {
|
|
@@ -691,11 +634,6 @@ function requiredString(value, message) {
|
|
|
691
634
|
}
|
|
692
635
|
return parsed;
|
|
693
636
|
}
|
|
694
|
-
function recordValue(value) {
|
|
695
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
696
|
-
? value
|
|
697
|
-
: null;
|
|
698
|
-
}
|
|
699
637
|
function numberQuery(value) {
|
|
700
638
|
if (value === null) {
|
|
701
639
|
return undefined;
|