feat(ext/sw): device management — devices.ts + router handlers

Adds readDevices, addDevice, revokeDevice helpers that read/write
.relicario/devices.json. Router handlers: list_devices, add_device,
revoke_device.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-04-26 15:53:08 -04:00
parent 5a001a805c
commit 0003c3e658
3 changed files with 142 additions and 4 deletions

View File

@@ -0,0 +1,55 @@
/// Device management — reads/writes .relicario/devices.json
import type { GitHost } from './git-host';
import type { Device } from '../shared/types';
const DEVICES_PATH = '.relicario/devices.json';
interface DevicesFile {
devices: Device[];
}
export async function readDevices(gitHost: GitHost): Promise<Device[]> {
try {
const raw = await gitHost.readFile(DEVICES_PATH);
const text = new TextDecoder().decode(raw);
const parsed: DevicesFile = JSON.parse(text);
return parsed.devices ?? [];
} catch {
return [];
}
}
export async function writeDevices(
gitHost: GitHost,
devices: Device[],
message: string,
): Promise<void> {
const content: DevicesFile = { devices };
const bytes = new TextEncoder().encode(JSON.stringify(content, null, 2));
await gitHost.writeFile(DEVICES_PATH, bytes, message);
}
export async function addDevice(
gitHost: GitHost,
device: Device,
): Promise<void> {
const existing = await readDevices(gitHost);
if (existing.some((d) => d.name === device.name)) {
throw new Error(`device '${device.name}' already exists`);
}
existing.push(device);
await writeDevices(gitHost, existing, `device: add ${device.name}`);
}
export async function revokeDevice(
gitHost: GitHost,
name: string,
): Promise<void> {
const existing = await readDevices(gitHost);
const filtered = existing.filter((d) => d.name !== name);
if (filtered.length === existing.length) {
throw new Error(`device '${name}' not found`);
}
await writeDevices(gitHost, filtered, `device: revoke ${name}`);
}