@abitat_reece/host-daemon 0.1.5 → 0.1.7
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/cli/index.js +186 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/local-control/codex-bridge.d.ts +14 -0
- package/dist/local-control/codex-bridge.d.ts.map +1 -0
- package/dist/local-control/codex-bridge.js +778 -0
- package/dist/local-control/codex-bridge.js.map +1 -0
- package/dist/local-control/relay-client.d.ts +36 -0
- package/dist/local-control/relay-client.d.ts.map +1 -0
- package/dist/local-control/relay-client.js +164 -0
- package/dist/local-control/relay-client.js.map +1 -0
- package/dist/local-control/server.d.ts +107 -0
- package/dist/local-control/server.d.ts.map +1 -0
- package/dist/local-control/server.js +393 -0
- package/dist/local-control/server.js.map +1 -0
- package/dist/local-control/state.d.ts +85 -0
- package/dist/local-control/state.d.ts.map +1 -0
- package/dist/local-control/state.js +264 -0
- package/dist/local-control/state.js.map +1 -0
- package/dist/local-control/transport.d.ts +78 -0
- package/dist/local-control/transport.d.ts.map +1 -0
- package/dist/local-control/transport.js +408 -0
- package/dist/local-control/transport.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir, hostname } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
const DEFAULT_PAIRING_TTL_MS = 5 * 60 * 1000;
|
|
6
|
+
const LOCAL_WORKSPACE_ID = "local";
|
|
7
|
+
const PAIRING_CAPABILITIES = [
|
|
8
|
+
"codex_chat",
|
|
9
|
+
"codex_projects",
|
|
10
|
+
"attachments",
|
|
11
|
+
"screen_control"
|
|
12
|
+
];
|
|
13
|
+
export function defaultLocalControlStatePath() {
|
|
14
|
+
return join(homedir(), "Library", "Application Support", "Abitat", "local-control-state.json");
|
|
15
|
+
}
|
|
16
|
+
export function defaultLocalAttachmentDirectory() {
|
|
17
|
+
return join(homedir(), "Library", "Application Support", "Abitat", "attachments");
|
|
18
|
+
}
|
|
19
|
+
export function hashLocalControlToken(token) {
|
|
20
|
+
return createHash("sha256").update(token).digest("hex");
|
|
21
|
+
}
|
|
22
|
+
export function createLocalControlStore(options = {}) {
|
|
23
|
+
const statePath = options.statePath ??
|
|
24
|
+
process.env.ABITAT_LOCAL_CONTROL_STATE_PATH ??
|
|
25
|
+
defaultLocalControlStatePath();
|
|
26
|
+
const now = options.now ?? (() => new Date());
|
|
27
|
+
const randomSecret = options.randomSecret ?? (() => randomBytes(32).toString("base64url"));
|
|
28
|
+
const idGenerator = options.idGenerator ?? ((prefix) => `${prefix}_${randomBytes(8).toString("hex")}`);
|
|
29
|
+
let hostToken = null;
|
|
30
|
+
async function loadState() {
|
|
31
|
+
const existing = await readStateFile(statePath);
|
|
32
|
+
if (existing) {
|
|
33
|
+
return existing;
|
|
34
|
+
}
|
|
35
|
+
hostToken = randomSecret();
|
|
36
|
+
const created = {
|
|
37
|
+
version: 1,
|
|
38
|
+
macId: idGenerator("mac"),
|
|
39
|
+
macName: hostname() || "Abitat Mac",
|
|
40
|
+
hostTokenHash: hashLocalControlToken(hostToken),
|
|
41
|
+
pairedDevices: [],
|
|
42
|
+
activePairings: []
|
|
43
|
+
};
|
|
44
|
+
await saveState(created);
|
|
45
|
+
return created;
|
|
46
|
+
}
|
|
47
|
+
async function saveState(state) {
|
|
48
|
+
await mkdir(dirname(statePath), { recursive: true });
|
|
49
|
+
await writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`, "utf8");
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
statePath,
|
|
53
|
+
async getMacIdentity() {
|
|
54
|
+
const state = await loadState();
|
|
55
|
+
return {
|
|
56
|
+
macId: state.macId,
|
|
57
|
+
macName: state.macName
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
async getHostToken() {
|
|
61
|
+
const state = await loadState();
|
|
62
|
+
if (hostToken && tokenMatchesHash(hostToken, state.hostTokenHash)) {
|
|
63
|
+
return hostToken;
|
|
64
|
+
}
|
|
65
|
+
hostToken = randomSecret();
|
|
66
|
+
await saveState({
|
|
67
|
+
...state,
|
|
68
|
+
hostTokenHash: hashLocalControlToken(hostToken)
|
|
69
|
+
});
|
|
70
|
+
return hostToken;
|
|
71
|
+
},
|
|
72
|
+
async getRelayId() {
|
|
73
|
+
const state = await loadState();
|
|
74
|
+
const existingRelayId = state.relayId ?? latestStoredRelayId(state);
|
|
75
|
+
if (existingRelayId) {
|
|
76
|
+
if (!state.relayId) {
|
|
77
|
+
await saveState({
|
|
78
|
+
...state,
|
|
79
|
+
relayId: existingRelayId
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return existingRelayId;
|
|
83
|
+
}
|
|
84
|
+
const relayId = idGenerator("relay");
|
|
85
|
+
await saveState({
|
|
86
|
+
...state,
|
|
87
|
+
relayId
|
|
88
|
+
});
|
|
89
|
+
return relayId;
|
|
90
|
+
},
|
|
91
|
+
async createPairing(input) {
|
|
92
|
+
const state = await loadState();
|
|
93
|
+
const createdAt = now();
|
|
94
|
+
const pairingSecret = randomSecret();
|
|
95
|
+
const manualCode = manualCodeFromSeed(randomSecret());
|
|
96
|
+
const pairing = {
|
|
97
|
+
id: idGenerator("pairing"),
|
|
98
|
+
endpoint: input.endpoint,
|
|
99
|
+
secretHash: hashLocalControlToken(pairingSecret),
|
|
100
|
+
manualCodeHash: hashLocalControlToken(normalizeManualCode(manualCode)),
|
|
101
|
+
manualCode,
|
|
102
|
+
expiresAt: new Date(createdAt.getTime() + (input.ttlMs ?? DEFAULT_PAIRING_TTL_MS)).toISOString(),
|
|
103
|
+
consumedAt: null,
|
|
104
|
+
createdAt: createdAt.toISOString(),
|
|
105
|
+
relayId: input.relayId ?? null,
|
|
106
|
+
transport: input.transport
|
|
107
|
+
};
|
|
108
|
+
await saveState({
|
|
109
|
+
...state,
|
|
110
|
+
activePairings: [
|
|
111
|
+
...state.activePairings.filter((candidate) => !isExpired(candidate, createdAt)),
|
|
112
|
+
pairing
|
|
113
|
+
]
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
version: 1,
|
|
117
|
+
product: "abitat",
|
|
118
|
+
endpoint: input.endpoint,
|
|
119
|
+
macId: state.macId,
|
|
120
|
+
pairingSecret,
|
|
121
|
+
manualCode,
|
|
122
|
+
expiresAt: pairing.expiresAt,
|
|
123
|
+
transport: input.transport,
|
|
124
|
+
relayId: input.relayId,
|
|
125
|
+
capabilities: [...PAIRING_CAPABILITIES]
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
async consumePairing(input) {
|
|
129
|
+
const state = await loadState();
|
|
130
|
+
const pairedAt = now();
|
|
131
|
+
const manualCode = input.manualCode ?? input.code;
|
|
132
|
+
const pairing = state.activePairings.find((candidate) => {
|
|
133
|
+
if (input.pairingSecret && tokenMatchesHash(input.pairingSecret, candidate.secretHash)) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return Boolean(manualCode && tokenMatchesHash(normalizeManualCode(manualCode), candidate.manualCodeHash));
|
|
137
|
+
});
|
|
138
|
+
if (!pairing) {
|
|
139
|
+
throw new Error("Invalid pairing code");
|
|
140
|
+
}
|
|
141
|
+
if (pairing.consumedAt) {
|
|
142
|
+
throw new Error("Pairing code has already been used");
|
|
143
|
+
}
|
|
144
|
+
if (isExpired(pairing, pairedAt)) {
|
|
145
|
+
throw new Error("Pairing code has expired");
|
|
146
|
+
}
|
|
147
|
+
const clientToken = randomSecret();
|
|
148
|
+
const device = {
|
|
149
|
+
id: idGenerator("phone"),
|
|
150
|
+
name: input.deviceName,
|
|
151
|
+
platform: input.platform,
|
|
152
|
+
tokenHash: hashLocalControlToken(clientToken),
|
|
153
|
+
pairedAt: pairedAt.toISOString(),
|
|
154
|
+
lastSeenAt: pairedAt.toISOString(),
|
|
155
|
+
relayId: pairing.relayId ?? null,
|
|
156
|
+
revokedAt: null
|
|
157
|
+
};
|
|
158
|
+
const nextPairings = state.activePairings.map((candidate) => candidate.id === pairing.id
|
|
159
|
+
? { ...candidate, consumedAt: pairedAt.toISOString() }
|
|
160
|
+
: candidate);
|
|
161
|
+
await saveState({
|
|
162
|
+
...state,
|
|
163
|
+
activePairings: nextPairings,
|
|
164
|
+
pairedDevices: [...state.pairedDevices, device]
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
machineId: device.id,
|
|
168
|
+
workspaceId: LOCAL_WORKSPACE_ID,
|
|
169
|
+
hostMachineId: state.macId,
|
|
170
|
+
clientToken,
|
|
171
|
+
endpoint: pairing.endpoint,
|
|
172
|
+
macId: state.macId
|
|
173
|
+
};
|
|
174
|
+
},
|
|
175
|
+
async getRelayKeyMaterials(relayId) {
|
|
176
|
+
const state = await loadState();
|
|
177
|
+
const checkedAt = now();
|
|
178
|
+
const pairingMaterials = state.activePairings
|
|
179
|
+
.filter((pairing) => pairing.relayId === relayId && !pairing.consumedAt && !isExpired(pairing, checkedAt))
|
|
180
|
+
.map((pairing) => ({
|
|
181
|
+
id: pairing.id,
|
|
182
|
+
kind: "pairing",
|
|
183
|
+
keyMaterial: pairing.secretHash
|
|
184
|
+
}));
|
|
185
|
+
const deviceMaterials = state.pairedDevices
|
|
186
|
+
.filter((device) => device.relayId === relayId && !device.revokedAt)
|
|
187
|
+
.map((device) => ({
|
|
188
|
+
id: device.id,
|
|
189
|
+
kind: "device",
|
|
190
|
+
keyMaterial: device.tokenHash
|
|
191
|
+
}));
|
|
192
|
+
return [...pairingMaterials, ...deviceMaterials];
|
|
193
|
+
},
|
|
194
|
+
async requireDeviceByToken(token) {
|
|
195
|
+
const state = await loadState();
|
|
196
|
+
const device = state.pairedDevices.find((candidate) => !candidate.revokedAt && tokenMatchesHash(token, candidate.tokenHash));
|
|
197
|
+
if (!device) {
|
|
198
|
+
throw new Error("Invalid mobile token");
|
|
199
|
+
}
|
|
200
|
+
const seenAt = now().toISOString();
|
|
201
|
+
await saveState({
|
|
202
|
+
...state,
|
|
203
|
+
pairedDevices: state.pairedDevices.map((candidate) => candidate.id === device.id ? { ...candidate, lastSeenAt: seenAt } : candidate)
|
|
204
|
+
});
|
|
205
|
+
return { ...device, lastSeenAt: seenAt };
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function readStateFile(path) {
|
|
210
|
+
try {
|
|
211
|
+
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
212
|
+
if (parsed.version !== 1 || typeof parsed.macId !== "string") {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
version: 1,
|
|
217
|
+
macId: parsed.macId,
|
|
218
|
+
macName: typeof parsed.macName === "string" ? parsed.macName : hostname() || "Abitat Mac",
|
|
219
|
+
hostTokenHash: typeof parsed.hostTokenHash === "string" ? parsed.hostTokenHash : "",
|
|
220
|
+
relayId: typeof parsed.relayId === "string" ? parsed.relayId : undefined,
|
|
221
|
+
pairedDevices: Array.isArray(parsed.pairedDevices) ? parsed.pairedDevices : [],
|
|
222
|
+
activePairings: Array.isArray(parsed.activePairings) ? parsed.activePairings : []
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
if (isNotFoundError(error)) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function manualCodeFromSeed(seed) {
|
|
233
|
+
const digest = hashLocalControlToken(seed).slice(0, 8).toUpperCase();
|
|
234
|
+
return `ABITAT-${digest.slice(0, 4)}-${digest.slice(4, 8)}`;
|
|
235
|
+
}
|
|
236
|
+
function normalizeManualCode(code) {
|
|
237
|
+
return code
|
|
238
|
+
.trim()
|
|
239
|
+
.replace(/[\u2010-\u2015\u2212]/gu, "-")
|
|
240
|
+
.replace(/\s+/gu, "")
|
|
241
|
+
.toUpperCase();
|
|
242
|
+
}
|
|
243
|
+
function isExpired(pairing, now) {
|
|
244
|
+
return Date.parse(pairing.expiresAt) <= now.getTime();
|
|
245
|
+
}
|
|
246
|
+
function latestStoredRelayId(state) {
|
|
247
|
+
return [
|
|
248
|
+
...state.pairedDevices.flatMap((device) => device.relayId ? [{ relayId: device.relayId, timestamp: Date.parse(device.pairedAt) }] : []),
|
|
249
|
+
...state.activePairings.flatMap((pairing) => pairing.relayId
|
|
250
|
+
? [{ relayId: pairing.relayId, timestamp: Date.parse(pairing.createdAt) }]
|
|
251
|
+
: [])
|
|
252
|
+
]
|
|
253
|
+
.sort((left, right) => right.timestamp - left.timestamp)
|
|
254
|
+
.at(0)?.relayId;
|
|
255
|
+
}
|
|
256
|
+
function tokenMatchesHash(token, expectedHash) {
|
|
257
|
+
const actual = Buffer.from(hashLocalControlToken(token), "hex");
|
|
258
|
+
const expected = Buffer.from(expectedHash, "hex");
|
|
259
|
+
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
260
|
+
}
|
|
261
|
+
function isNotFoundError(error) {
|
|
262
|
+
return Boolean(error && typeof error === "object" && error.code === "ENOENT");
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/local-control/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
2
|
+
import type { LocalControlTransport } from "./state.js";
|
|
3
|
+
type ExecFile = (file: string, args: string[]) => Promise<{
|
|
4
|
+
stdout: string;
|
|
5
|
+
stderr: string;
|
|
6
|
+
}>;
|
|
7
|
+
interface QuickTunnelProcess {
|
|
8
|
+
kill(signal?: NodeJS.Signals | number): boolean;
|
|
9
|
+
killed: boolean;
|
|
10
|
+
off(event: string, listener: (...args: any[]) => void): QuickTunnelProcess;
|
|
11
|
+
once(event: string, listener: (...args: any[]) => void): QuickTunnelProcess;
|
|
12
|
+
stderr: Readable;
|
|
13
|
+
stdout: Readable;
|
|
14
|
+
}
|
|
15
|
+
type SpawnProcess = (file: string, args: string[]) => QuickTunnelProcess;
|
|
16
|
+
export interface LocalControlTransportResolution {
|
|
17
|
+
bindHost: string;
|
|
18
|
+
endpoint: string;
|
|
19
|
+
relayEndpoint?: string;
|
|
20
|
+
transport: LocalControlTransport;
|
|
21
|
+
warning?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface QuickTunnel {
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
endpoint: string;
|
|
26
|
+
}
|
|
27
|
+
export interface SshTunnel {
|
|
28
|
+
close(): Promise<void>;
|
|
29
|
+
endpoint: string;
|
|
30
|
+
}
|
|
31
|
+
interface WaitForQuickTunnelReadyInput {
|
|
32
|
+
fetch?: typeof fetch;
|
|
33
|
+
intervalMs?: number;
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface EndpointHealthMonitor {
|
|
37
|
+
stop(): void;
|
|
38
|
+
}
|
|
39
|
+
interface StartEndpointHealthMonitorInput {
|
|
40
|
+
fetch?: typeof fetch;
|
|
41
|
+
healthPath?: string;
|
|
42
|
+
intervalMs?: number;
|
|
43
|
+
maxFailures?: number;
|
|
44
|
+
onUnhealthy(error: Error): void;
|
|
45
|
+
}
|
|
46
|
+
interface ResolveLocalControlTransportInput {
|
|
47
|
+
endpoint?: string;
|
|
48
|
+
execFile?: ExecFile;
|
|
49
|
+
port: number;
|
|
50
|
+
relayEndpoint?: string;
|
|
51
|
+
requestedTransport: "auto" | LocalControlTransport | "temporary-tunnel";
|
|
52
|
+
}
|
|
53
|
+
export declare function resolveLocalControlTransport(input: ResolveLocalControlTransportInput): Promise<LocalControlTransportResolution>;
|
|
54
|
+
export declare function startQuickTunnel(input: {
|
|
55
|
+
localUrl: string;
|
|
56
|
+
spawnProcess?: SpawnProcess;
|
|
57
|
+
timeoutMs?: number;
|
|
58
|
+
}): Promise<QuickTunnel>;
|
|
59
|
+
export declare function startLocalhostRunTunnel(input: {
|
|
60
|
+
localUrl: string;
|
|
61
|
+
spawnProcess?: SpawnProcess;
|
|
62
|
+
timeoutMs?: number;
|
|
63
|
+
}): Promise<SshTunnel>;
|
|
64
|
+
export declare function startPinggyTunnel(input: {
|
|
65
|
+
localUrl: string;
|
|
66
|
+
spawnProcess?: SpawnProcess;
|
|
67
|
+
timeoutMs?: number;
|
|
68
|
+
}): Promise<SshTunnel>;
|
|
69
|
+
export declare function startTemporarySshTunnel(input: {
|
|
70
|
+
localUrl: string;
|
|
71
|
+
onFallback?(error: unknown): void;
|
|
72
|
+
spawnProcess?: SpawnProcess;
|
|
73
|
+
timeoutMs?: number;
|
|
74
|
+
}): Promise<SshTunnel>;
|
|
75
|
+
export declare function waitForQuickTunnelReady(endpoint: string, input?: WaitForQuickTunnelReadyInput): Promise<void>;
|
|
76
|
+
export declare function startEndpointHealthMonitor(endpoint: string, input: StartEndpointHealthMonitorInput): EndpointHealthMonitor;
|
|
77
|
+
export {};
|
|
78
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/local-control/transport.ts"],"names":[],"mappings":"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"}
|