@hermespilot/link 0.1.3 → 0.1.4

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.
@@ -4,7 +4,7 @@ import Router from "@koa/router";
4
4
  import { Readable } from "stream";
5
5
 
6
6
  // src/constants.ts
7
- var LINK_VERSION = "0.1.3";
7
+ var LINK_VERSION = "0.1.4";
8
8
  var LINK_COMMAND = "hermeslink";
9
9
  var LINK_DEFAULT_PORT = 52379;
10
10
  var LINK_RUNTIME_DIR_NAME = ".hermeslink";
@@ -1601,4 +1601,4 @@ export {
1601
1601
  getLinkLogFile,
1602
1602
  createApp
1603
1603
  };
1604
- //# sourceMappingURL=chunk-7M3UZCA7.js.map
1604
+ //# sourceMappingURL=chunk-T35GPRKF.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/http/app.ts","../src/constants.ts","../src/runtime/paths.ts","../src/storage/atomic-json.ts","../src/config/config.ts","../src/http/errors.ts","../src/hermes/api-server.ts","../src/hermes/config.ts","../src/hermes/profiles.ts","../src/identity/identity.ts","../src/security/devices.ts","../src/relay/bootstrap.ts","../src/topology/network.ts","../src/pairing/pairing.ts","../src/security/app-connect-token.ts","../src/runtime/logger.ts"],"sourcesContent":["import Koa from 'koa'\nimport Router from '@koa/router'\nimport { Readable } from 'node:stream'\nimport { LINK_VERSION } from '../constants.js'\nimport { loadConfig } from '../config/config.js'\nimport { LinkHttpError, isLinkHttpError } from './errors.js'\nimport {\n cancelHermesRun,\n createHermesRun,\n listHermesModels,\n streamHermesRunEvents,\n} from '../hermes/api-server.js'\nimport {\n createHermesProfile,\n deleteHermesProfile,\n getHermesProfileStatus,\n listHermesProfiles,\n renameHermesProfile,\n useHermesProfile,\n} from '../hermes/profiles.js'\nimport { loadIdentity } from '../identity/identity.js'\nimport { claimPairing } from '../pairing/pairing.js'\nimport {\n authenticateDeviceAccessToken,\n refreshDeviceSession,\n revokeDeviceRefreshToken,\n type DeviceRecord,\n} from '../security/devices.js'\nimport { verifyAppConnectToken } from '../security/app-connect-token.js'\nimport { createFileLogger, readRecentLogEntries, type FileLogger } from '../runtime/logger.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { discoverRouteCandidates } from '../topology/network.js'\n\ninterface AuthContext {\n kind: 'device' | 'app-connect'\n device?: DeviceRecord\n accountId?: string\n}\n\nexport interface CreateAppOptions {\n paths?: RuntimePaths\n logger?: FileLogger\n onPairingClaimed?: () => void | Promise<void>\n}\n\nexport async function createApp(options: CreateAppOptions = {}): Promise<Koa> {\n const paths = options.paths ?? resolveRuntimePaths()\n const logger = options.logger ?? createFileLogger({ paths })\n const app = new Koa()\n const router = new Router()\n\n app.use(async (ctx, next) => {\n const startedAt = Date.now()\n try {\n await next()\n } catch (error) {\n const profileError = error instanceof Error && error.message === 'invalid profile name'\n const status = isLinkHttpError(error) ? error.status : profileError ? 400 : 500\n ctx.status = status\n ctx.body = {\n ok: false,\n error: {\n code: isLinkHttpError(error) ? error.code : status === 400 ? 'invalid_profile_name' : 'internal_error',\n message: error instanceof Error ? error.message : 'Internal error',\n },\n }\n void logger.write(status >= 500 ? 'error' : 'warn', 'http_request_failed', {\n method: ctx.method,\n path: ctx.path,\n status,\n code: isLinkHttpError(error) ? error.code : status === 400 ? 'invalid_profile_name' : 'internal_error',\n error: error instanceof Error ? error.message : String(error),\n })\n } finally {\n void logger.info('http_request', {\n method: ctx.method,\n path: ctx.path,\n status: ctx.status,\n duration_ms: Date.now() - startedAt,\n })\n }\n })\n\n router.get('/api/v1/bootstrap', async (ctx) => {\n const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)])\n const routes = identity?.link_id\n ? await discoverRouteCandidates({\n port: config.port,\n relayBaseUrl: config.relayBaseUrl,\n linkId: identity.link_id,\n installId: identity.install_id,\n publicKeyPem: identity.public_key_pem,\n })\n : null\n ctx.set('cache-control', 'no-store')\n ctx.body = {\n link_id: identity?.link_id ?? null,\n display_name: identity?.link_id ? 'Hermes Link' : 'Unpaired Hermes Link',\n version: LINK_VERSION,\n api_version: 1,\n paired: Boolean(identity?.link_id),\n pairing_supported: Boolean(identity?.link_id),\n preferred_pairing_urls: routes?.preferredUrls ?? [],\n routes: routes ? routeObjects(routes.preferredUrls) : [],\n capabilities: {\n runs: true,\n sse: true,\n relay: true,\n profiles: true,\n logs: true,\n },\n }\n })\n\n router.post('/api/v1/pairing/claim', async (ctx) => {\n const body = await readJsonBody(ctx.req)\n const sessionId = readString(body, 'session_id') ?? readString(body, 'sessionId')\n const claimToken = readString(body, 'claim_token') ?? readString(body, 'claimToken')\n if (!sessionId || !claimToken) {\n throw new LinkHttpError(400, 'pairing_claim_invalid', 'session_id and claim_token are required')\n }\n const claimed = await claimPairing({\n sessionId,\n claimToken,\n deviceLabel: readString(body, 'device_label') ?? readString(body, 'deviceLabel') ?? 'HermesPilot App',\n devicePlatform: readString(body, 'device_platform') ?? readString(body, 'devicePlatform') ?? 'unknown',\n paths,\n })\n ctx.body = claimed\n void logger.info('pairing_claimed', {\n device_id: claimed.device.device_id,\n device_platform: claimed.device.platform,\n })\n if (options.onPairingClaimed) {\n const timer = setTimeout(() => {\n void options.onPairingClaimed?.()\n }, 250)\n timer.unref?.()\n }\n })\n\n router.get('/api/v1/auth/me', async (ctx) => {\n const auth = await authenticateRequest(ctx, paths)\n const identity = await loadRequiredIdentity(paths)\n ctx.body = {\n ok: true,\n auth: { kind: auth.kind, account_id: auth.accountId ?? null },\n link: {\n link_id: identity.link_id,\n display_name: 'Hermes Link',\n },\n device: auth.device\n ? {\n id: auth.device.id,\n device_id: auth.device.id,\n label: auth.device.label,\n platform: auth.device.platform,\n scope: auth.device.scope,\n }\n : null,\n }\n })\n\n router.post('/api/v1/auth/refresh', async (ctx) => {\n const body = await readJsonBody(ctx.req)\n const refreshToken = readString(body, 'refresh_token') ?? readString(body, 'refreshToken')\n if (!refreshToken) {\n throw new LinkHttpError(400, 'refresh_token_required', 'refresh_token is required')\n }\n const session = await refreshDeviceSession(refreshToken, paths)\n ctx.body = {\n ok: true,\n device: session.device,\n access_token: {\n token: session.accessToken.token,\n expires_at: session.accessToken.expiresAt,\n },\n refresh_token: {\n token: session.refreshToken.token,\n expires_at: session.refreshToken.expiresAt,\n },\n }\n })\n\n router.post('/api/v1/auth/logout', async (ctx) => {\n const body = await readJsonBody(ctx.req)\n const refreshToken = readString(body, 'refresh_token') ?? readString(body, 'refreshToken')\n if (refreshToken) {\n await revokeDeviceRefreshToken(refreshToken, paths)\n }\n ctx.body = { ok: true }\n })\n\n router.get('/api/v1/status', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)])\n ctx.body = {\n ok: true,\n version: LINK_VERSION,\n paired: Boolean(identity?.link_id),\n link_id: identity?.link_id ?? null,\n port: config.port,\n }\n })\n\n router.get('/api/v1/logs', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.set('cache-control', 'no-store')\n ctx.body = {\n ok: true,\n logs: await readRecentLogEntries({\n paths,\n limit: readLimit(ctx.query.limit),\n }),\n }\n })\n\n router.get('/api/v1/models', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.body = await listHermesModels()\n })\n\n router.post('/api/v1/runs', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const body = await readJsonBody(ctx.req)\n const input = readString(body, 'input')\n if (!input) {\n throw new LinkHttpError(400, 'run_input_required', 'input is required')\n }\n ctx.status = 202\n ctx.body = await createHermesRun({\n input,\n conversation_history: readConversationHistory(body.conversation_history ?? body.conversationHistory),\n session_id: readString(body, 'session_id') ?? readString(body, 'sessionId') ?? undefined,\n })\n })\n\n router.get('/api/v1/runs/:runId/events', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const response = await streamHermesRunEvents(ctx.params.runId)\n ctx.status = response.status\n for (const [key, value] of response.headers.entries()) {\n ctx.set(key, value)\n }\n ctx.respond = false\n const nodeResponse = ctx.res\n nodeResponse.statusCode = response.status\n for (const [key, value] of response.headers.entries()) {\n nodeResponse.setHeader(key, value)\n }\n if (response.body) {\n Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]).pipe(nodeResponse)\n } else {\n nodeResponse.end()\n }\n })\n\n router.post('/api/v1/runs/:runId/cancel', async (ctx) => {\n await authenticateRequest(ctx, paths)\n await cancelHermesRun(ctx.params.runId)\n ctx.body = { ok: true }\n })\n\n router.get('/api/v1/profiles', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.set('cache-control', 'no-store')\n ctx.body = {\n ok: true,\n profiles: await listHermesProfiles(),\n }\n })\n\n router.get('/api/v1/profiles/:name/status', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.set('cache-control', 'no-store')\n ctx.body = {\n ok: true,\n profile: await getHermesProfileStatus(ctx.params.name),\n }\n })\n\n router.post('/api/v1/profiles', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const body = await readJsonBody(ctx.req)\n const name = readProfileName(body)\n ctx.status = 201\n ctx.body = {\n ok: true,\n profile: await createHermesProfile(name),\n }\n })\n\n router.post('/api/v1/profiles/:name/use', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.body = {\n ok: true,\n profile: await useHermesProfile(ctx.params.name),\n }\n })\n\n router.patch('/api/v1/profiles/:name', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const body = await readJsonBody(ctx.req)\n const name = readProfileName(body)\n ctx.body = {\n ok: true,\n profile: await renameHermesProfile(ctx.params.name, name),\n }\n })\n\n router.delete('/api/v1/profiles/:name', async (ctx) => {\n await authenticateRequest(ctx, paths)\n await deleteHermesProfile(ctx.params.name)\n ctx.status = 204\n })\n\n app.use(router.routes())\n app.use(router.allowedMethods())\n return app\n}\n\nasync function readJsonBody(request: NodeJS.ReadableStream): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = []\n for await (const chunk of request) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n if (chunks.length === 0) {\n return {}\n }\n return JSON.parse(Buffer.concat(chunks).toString('utf8')) as Record<string, unknown>\n}\n\nfunction readProfileName(body: Record<string, unknown>): string {\n if (typeof body.name !== 'string') {\n throw new Error('invalid profile name')\n }\n return body.name\n}\n\nasync function authenticateRequest(ctx: Koa.ParameterizedContext, paths: RuntimePaths): Promise<AuthContext> {\n const token = readBearerToken(ctx.get('authorization'))\n if (!token) {\n throw new LinkHttpError(401, 'auth_required', 'Authorization bearer token is required')\n }\n const device = await authenticateDeviceAccessToken(token, paths)\n if (device) {\n return { kind: 'device', device }\n }\n const [identity, config] = await Promise.all([loadRequiredIdentity(paths), loadConfig(paths)])\n const claims = await verifyAppConnectToken(token, {\n config,\n linkId: identity.link_id,\n })\n return { kind: 'app-connect', accountId: claims.sub }\n}\n\nasync function loadRequiredIdentity(paths: RuntimePaths) {\n const identity = await loadIdentity(paths)\n if (!identity?.link_id) {\n throw new LinkHttpError(409, 'link_not_paired', 'Hermes Link is not paired')\n }\n return identity as NonNullable<typeof identity> & { link_id: string }\n}\n\nfunction readBearerToken(value: string): string | null {\n const trimmed = value.trim()\n if (!trimmed.toLowerCase().startsWith('bearer ')) {\n return null\n }\n const token = trimmed.slice(7).trim()\n return token || null\n}\n\nfunction readString(body: Record<string, unknown>, key: string): string | null {\n const value = body[key]\n return typeof value === 'string' && value.trim() ? value.trim() : null\n}\n\nfunction readLimit(value: unknown): number | undefined {\n const raw = Array.isArray(value) ? value[0] : value\n if (typeof raw !== 'string') {\n return undefined\n }\n const parsed = Number.parseInt(raw, 10)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nfunction readConversationHistory(value: unknown): Array<{ role: string; content: string }> {\n if (!Array.isArray(value)) {\n return []\n }\n return value\n .map((item) => {\n if (typeof item !== 'object' || item === null) {\n return null\n }\n const role = (item as { role?: unknown }).role\n const content = (item as { content?: unknown }).content\n if (typeof role !== 'string' || typeof content !== 'string') {\n return null\n }\n return { role, content }\n })\n .filter((item): item is { role: string; content: string } => Boolean(item))\n}\n\nfunction routeObjects(urls: string[]) {\n return urls.map((url) => ({\n kind: url.includes('/api/v1/relay/links/') ? 'relay' : 'lan',\n url,\n observed_at: new Date().toISOString(),\n }))\n}\n","export const LINK_VERSION = '0.1.3'\nexport const LINK_COMMAND = 'hermeslink'\nexport const LINK_DEFAULT_PORT = 52379\nexport const LINK_RUNTIME_DIR_NAME = '.hermeslink'\n","import os from 'node:os'\nimport path from 'node:path'\nimport { LINK_RUNTIME_DIR_NAME } from '../constants.js'\n\nexport interface RuntimePaths {\n homeDir: string\n identityFile: string\n configFile: string\n stateFile: string\n credentialsFile: string\n databaseFile: string\n logsDir: string\n runDir: string\n pairingDir: string\n}\n\nexport function resolveRuntimeHome(): string {\n return process.env.HERMESLINK_HOME?.trim()\n ? path.resolve(process.env.HERMESLINK_HOME)\n : path.join(os.homedir(), LINK_RUNTIME_DIR_NAME)\n}\n\nexport function resolveRuntimePaths(homeDir = resolveRuntimeHome()): RuntimePaths {\n return {\n homeDir,\n identityFile: path.join(homeDir, 'identity.json'),\n configFile: path.join(homeDir, 'config.json'),\n stateFile: path.join(homeDir, 'state.json'),\n credentialsFile: path.join(homeDir, 'credentials.json'),\n databaseFile: path.join(homeDir, 'link.db'),\n logsDir: path.join(homeDir, 'logs'),\n runDir: path.join(homeDir, 'run'),\n pairingDir: path.join(homeDir, 'pairing'),\n }\n}\n\n","import { mkdir, open, readFile, rename, rm } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport async function readJsonFile<T>(filePath: string): Promise<T | null> {\n try {\n const raw = await readFile(filePath, 'utf8')\n return JSON.parse(raw) as T\n } catch (error) {\n if (isNodeError(error, 'ENOENT')) {\n return null\n }\n throw error\n }\n}\n\nexport async function writeJsonFile(filePath: string, value: unknown, mode = 0o600): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 })\n const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`\n const payload = `${JSON.stringify(value, null, 2)}\\n`\n const handle = await open(tmpPath, 'w', mode)\n try {\n await handle.writeFile(payload, 'utf8')\n await handle.sync()\n } finally {\n await handle.close()\n }\n try {\n await rename(tmpPath, filePath)\n } catch (error) {\n await rm(tmpPath, { force: true })\n throw error\n }\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code\n}\n\n","import { LINK_DEFAULT_PORT } from '../constants.js'\nimport type { ConfiguredLanguage } from '../i18n.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { readJsonFile, writeJsonFile } from '../storage/atomic-json.js'\n\nexport interface LinkConfig {\n port: number\n serverBaseUrl: string\n relayBaseUrl: string\n appConnectTokenIssuer: string\n appConnectTokenAudience: string\n language: ConfiguredLanguage\n}\n\nexport const defaultLinkConfig: LinkConfig = {\n port: LINK_DEFAULT_PORT,\n serverBaseUrl: 'https://hermes-server.clawpilot.me',\n relayBaseUrl: 'https://hermes-relay.clawpilot.me',\n appConnectTokenIssuer: 'https://hermes-server.clawpilot.me',\n appConnectTokenAudience: 'hermes-link',\n language: 'auto',\n}\n\nexport async function loadConfig(paths: RuntimePaths = resolveRuntimePaths()): Promise<LinkConfig> {\n const existing = await readJsonFile<Partial<LinkConfig>>(paths.configFile)\n const language = normalizeConfiguredLanguage(existing?.language)\n return {\n ...defaultLinkConfig,\n ...(existing ?? {}),\n language,\n }\n}\n\nexport async function saveConfig(\n patch: Partial<LinkConfig>,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<LinkConfig> {\n const current = await loadConfig(paths)\n const next = { ...current, ...patch }\n await writeJsonFile(paths.configFile, next)\n return next\n}\n\nfunction normalizeConfiguredLanguage(language: unknown): ConfiguredLanguage {\n if (language === 'zh-CN' || language === 'en' || language === 'auto') {\n return language\n }\n return defaultLinkConfig.language\n}\n","export class LinkHttpError extends Error {\n constructor(\n readonly status: number,\n readonly code: string,\n message: string,\n ) {\n super(message)\n }\n}\n\nexport function isLinkHttpError(error: unknown): error is LinkHttpError {\n return error instanceof LinkHttpError\n}\n","import { randomUUID } from 'node:crypto'\nimport { readHermesApiServerConfig } from './config.js'\nimport { LinkHttpError } from '../http/errors.js'\n\nexport interface HermesRunRequest {\n input: string\n conversation_history?: Array<{ role: string; content: string }>\n session_id?: string\n}\n\nexport interface HermesApiClientOptions {\n fetchImpl?: typeof fetch\n}\n\nconst fallbackRuns = new Map<string, { input: string; createdAt: string }>()\n\nexport async function listHermesModels(options: HermesApiClientOptions = {}): Promise<unknown> {\n const response = await callHermesApi('/v1/models', { method: 'GET' }, options)\n if (response.status === 404) {\n return { models: [] }\n }\n return await readJsonResponse(response)\n}\n\nexport async function createHermesRun(\n input: HermesRunRequest,\n options: HermesApiClientOptions = {},\n): Promise<{ run_id: string; fallback: boolean }> {\n const response = await callHermesApi(\n '/v1/runs',\n {\n method: 'POST',\n body: JSON.stringify(input),\n headers: { 'content-type': 'application/json' },\n },\n options,\n )\n if (response.status === 404 || response.status === 503) {\n const runId = `run_${randomUUID().replaceAll('-', '')}`\n fallbackRuns.set(runId, { input: input.input, createdAt: new Date().toISOString() })\n return { run_id: runId, fallback: true }\n }\n const payload = await readJsonResponse(response)\n const runId = readString(payload, 'run_id') ?? readString(payload, 'runId') ?? readString(payload, 'id')\n if (!runId) {\n throw new LinkHttpError(502, 'hermes_run_invalid', 'Hermes API Server did not return a run id')\n }\n return { run_id: runId, fallback: false }\n}\n\nexport async function streamHermesRunEvents(\n runId: string,\n options: HermesApiClientOptions = {},\n): Promise<Response> {\n const fallback = fallbackRuns.get(runId)\n if (fallback) {\n fallbackRuns.delete(runId)\n return new Response(createFallbackSseStream(fallback.input), {\n headers: {\n 'content-type': 'text/event-stream; charset=utf-8',\n 'cache-control': 'no-store',\n },\n })\n }\n const response = await callHermesApi(`/v1/runs/${encodeURIComponent(runId)}/events`, { method: 'GET' }, options)\n if (!response.ok || !response.body) {\n throw new LinkHttpError(502, 'hermes_events_unavailable', 'Hermes run event stream is unavailable')\n }\n return new Response(response.body, {\n status: response.status,\n headers: {\n 'content-type': response.headers.get('content-type') ?? 'text/event-stream; charset=utf-8',\n 'cache-control': 'no-store',\n },\n })\n}\n\nexport async function cancelHermesRun(runId: string, options: HermesApiClientOptions = {}): Promise<void> {\n const response = await callHermesApi(\n `/v1/runs/${encodeURIComponent(runId)}/cancel`,\n { method: 'POST' },\n options,\n )\n if (!response.ok && response.status !== 404) {\n throw new LinkHttpError(502, 'hermes_cancel_failed', 'Hermes run cancel failed')\n }\n fallbackRuns.delete(runId)\n}\n\nasync function callHermesApi(\n path: string,\n init: RequestInit,\n options: HermesApiClientOptions,\n): Promise<Response> {\n const config = await readHermesApiServerConfig()\n if (!config.port || !config.key) {\n return new Response(null, { status: 503 })\n }\n const fetcher = options.fetchImpl ?? fetch\n const headers = new Headers(init.headers)\n headers.set('accept', headers.get('accept') ?? 'application/json')\n headers.set('x-api-key', config.key)\n headers.set('authorization', `Bearer ${config.key}`)\n return await fetcher(`http://127.0.0.1:${config.port}${path}`, {\n ...init,\n headers,\n }).catch(() => new Response(null, { status: 503 }))\n}\n\nasync function readJsonResponse(response: Response): Promise<Record<string, unknown>> {\n const payload = (await response.json().catch(() => null)) as unknown\n if (!response.ok || typeof payload !== 'object' || payload === null) {\n throw new LinkHttpError(502, 'hermes_response_invalid', 'Hermes API Server returned an invalid response')\n }\n return payload as Record<string, unknown>\n}\n\nfunction createFallbackSseStream(input: string): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder()\n return new ReadableStream<Uint8Array>({\n start(controller) {\n const message = `Hermes API Server is not running yet. Link received: ${input}`\n controller.enqueue(encoder.encode(`event: message.delta\\ndata: ${JSON.stringify({ type: 'message.delta', delta: message })}\\n\\n`))\n controller.enqueue(encoder.encode(`event: run.completed\\ndata: ${JSON.stringify({ type: 'run.completed' })}\\n\\n`))\n controller.close()\n },\n })\n}\n\nfunction readString(payload: Record<string, unknown>, key: string): string | null {\n const value = payload[key]\n return typeof value === 'string' && value.trim() ? value.trim() : null\n}\n","import { randomBytes } from 'node:crypto'\nimport { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport YAML from 'yaml'\n\nexport interface HermesApiServerConfig {\n host?: string\n port?: number\n key?: string\n}\n\nexport interface EnsureHermesConfigResult {\n configPath: string\n apiServer: HermesApiServerConfig\n changed: boolean\n keyAdded: boolean\n backupPath: string | null\n notice: string | null\n}\n\nexport function resolveHermesProfileDir(profileName = 'default'): string {\n if (profileName === 'default') {\n return path.join(os.homedir(), '.hermes')\n }\n return path.join(os.homedir(), '.hermes', 'profiles', profileName)\n}\n\nexport function resolveHermesConfigPath(profileName = 'default'): string {\n return path.join(resolveHermesProfileDir(profileName), 'config.yaml')\n}\n\nexport async function readHermesApiServerConfig(\n profileName = 'default',\n configPath = resolveHermesConfigPath(profileName),\n): Promise<HermesApiServerConfig> {\n const existingRaw = await readFile(configPath, 'utf8').catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return null\n }\n throw error\n })\n if (!existingRaw) {\n return {}\n }\n const config = toRecord(YAML.parse(existingRaw))\n const platforms = toRecord(config.platforms)\n const apiServer = toRecord(platforms.api_server)\n return readApiServerConfig(toRecord(apiServer.extra))\n}\n\nexport async function ensureHermesApiServerKey(\n profileName = 'default',\n configPath = resolveHermesConfigPath(profileName),\n): Promise<EnsureHermesConfigResult> {\n const existingRaw = await readFile(configPath, 'utf8').catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return null\n }\n throw error\n })\n const document = existingRaw ? YAML.parseDocument(existingRaw) : new YAML.Document({})\n const config = toRecord(document.toJSON())\n const platforms = ensureRecord(config, 'platforms')\n const apiServer = ensureRecord(platforms, 'api_server')\n const extra = ensureRecord(apiServer, 'extra')\n const beforeKey = typeof extra.key === 'string' && extra.key.length > 0 ? extra.key : null\n\n let changed = false\n if (!beforeKey) {\n extra.key = randomBytes(32).toString('base64url')\n changed = true\n }\n\n if (!changed) {\n return {\n configPath,\n apiServer: readApiServerConfig(extra),\n changed: false,\n keyAdded: false,\n backupPath: null,\n notice: null,\n }\n }\n\n const backupPath = existingRaw ? `${configPath}.bak.${Date.now()}` : null\n await mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 })\n if (backupPath) {\n await copyFile(configPath, backupPath)\n }\n document.contents = document.createNode(config)\n await writeFile(configPath, document.toString(), { mode: 0o600 })\n\n return {\n configPath,\n apiServer: readApiServerConfig(extra),\n changed: true,\n keyAdded: true,\n backupPath,\n notice: '已为 Hermes API Server 自动补充 key;未覆盖已有 port/host/key。',\n }\n}\n\nfunction readApiServerConfig(extra: Record<string, unknown>): HermesApiServerConfig {\n return {\n host: typeof extra.host === 'string' ? extra.host : undefined,\n port: typeof extra.port === 'number' ? extra.port : undefined,\n key: typeof extra.key === 'string' ? extra.key : undefined,\n }\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : {}\n}\n\nfunction ensureRecord(parent: Record<string, unknown>, key: string): Record<string, unknown> {\n const value = parent[key]\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n return value as Record<string, unknown>\n }\n const next: Record<string, unknown> = {}\n parent[key] = next\n return next\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code\n}\n","import { mkdir, readdir, rename, rm, stat } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { readJsonFile, writeJsonFile } from '../storage/atomic-json.js'\nimport {\n ensureHermesApiServerKey,\n readHermesApiServerConfig,\n resolveHermesConfigPath,\n resolveHermesProfileDir,\n} from './config.js'\n\nexport interface HermesProfile {\n name: string\n active: boolean\n path: string\n configPath: string\n}\n\ninterface ProfileState {\n activeProfile: string\n}\n\nconst DEFAULT_PROFILE = 'default'\nconst PROFILE_NAME_PATTERN = /^[a-zA-Z0-9._-]{1,64}$/\n\nexport async function listHermesProfiles(paths: RuntimePaths = resolveRuntimePaths()): Promise<HermesProfile[]> {\n const activeProfile = await getActiveProfile(paths)\n const profiles = new Map<string, HermesProfile>()\n profiles.set(DEFAULT_PROFILE, profileInfo(DEFAULT_PROFILE, activeProfile))\n\n const profilesDir = path.join(os.homedir(), '.hermes', 'profiles')\n const entries = await readdir(profilesDir, { withFileTypes: true }).catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return []\n }\n throw error\n })\n for (const entry of entries) {\n if (entry.isDirectory() && PROFILE_NAME_PATTERN.test(entry.name)) {\n profiles.set(entry.name, profileInfo(entry.name, activeProfile))\n }\n }\n\n return [...profiles.values()].sort((left, right) => {\n if (left.name === DEFAULT_PROFILE) {\n return -1\n }\n if (right.name === DEFAULT_PROFILE) {\n return 1\n }\n return left.name.localeCompare(right.name)\n })\n}\n\nexport async function getHermesProfileStatus(\n name: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<HermesProfile & { exists: boolean; apiKeyConfigured: boolean }> {\n assertProfileName(name)\n const profile = profileInfo(name, await getActiveProfile(paths))\n const exists = await stat(profile.path)\n .then((value) => value.isDirectory())\n .catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return false\n }\n throw error\n })\n const config = await readHermesApiServerConfig(name, profile.configPath)\n return {\n ...profile,\n exists,\n apiKeyConfigured: Boolean(config.key),\n }\n}\n\nexport async function createHermesProfile(name: string): Promise<HermesProfile> {\n assertProfileName(name)\n if (name === DEFAULT_PROFILE) {\n throw new Error('default profile already exists')\n }\n const profile = profileInfo(name, DEFAULT_PROFILE)\n if (await pathExists(profile.path)) {\n throw new Error('profile already exists')\n }\n await mkdir(profile.path, { recursive: true, mode: 0o700 })\n await ensureHermesApiServerKey(name, profile.configPath)\n return profile\n}\n\nexport async function useHermesProfile(\n name: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<HermesProfile> {\n assertProfileName(name)\n const profile = profileInfo(name, name)\n await mkdir(profile.path, { recursive: true, mode: 0o700 })\n const current = (await readJsonFile<Record<string, unknown>>(paths.stateFile)) ?? {}\n await writeJsonFile(paths.stateFile, { ...current, activeProfile: name } satisfies ProfileState)\n return profile\n}\n\nexport async function renameHermesProfile(oldName: string, newName: string): Promise<HermesProfile> {\n assertMutableProfile(oldName)\n assertMutableProfile(newName)\n const oldProfile = profileInfo(oldName, DEFAULT_PROFILE)\n const newProfile = profileInfo(newName, DEFAULT_PROFILE)\n await rename(oldProfile.path, newProfile.path)\n return newProfile\n}\n\nexport async function deleteHermesProfile(name: string): Promise<void> {\n assertMutableProfile(name)\n await rm(resolveHermesProfileDir(name), { recursive: true, force: true })\n}\n\nasync function getActiveProfile(paths: RuntimePaths): Promise<string> {\n const state = await readJsonFile<Partial<ProfileState>>(paths.stateFile)\n return typeof state?.activeProfile === 'string' && PROFILE_NAME_PATTERN.test(state.activeProfile)\n ? state.activeProfile\n : DEFAULT_PROFILE\n}\n\nfunction profileInfo(name: string, activeProfile: string): HermesProfile {\n return {\n name,\n active: name === activeProfile,\n path: resolveHermesProfileDir(name),\n configPath: resolveHermesConfigPath(name),\n }\n}\n\nfunction assertMutableProfile(name: string): void {\n assertProfileName(name)\n if (name === DEFAULT_PROFILE) {\n throw new Error('default profile cannot be renamed or deleted')\n }\n}\n\nfunction assertProfileName(name: string): void {\n if (!PROFILE_NAME_PATTERN.test(name)) {\n throw new Error('invalid profile name')\n }\n}\n\nasync function pathExists(targetPath: string): Promise<boolean> {\n return await stat(targetPath)\n .then(() => true)\n .catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return false\n }\n throw error\n })\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code\n}\n","import { generateKeyPairSync, randomUUID, sign } from 'node:crypto'\nimport { mkdir, chmod } from 'node:fs/promises'\nimport { z } from 'zod'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { readJsonFile, writeJsonFile } from '../storage/atomic-json.js'\n\nconst linkIdentitySchema = z.object({\n install_id: z.string().min(1),\n link_id: z.string().min(1).nullable().optional(),\n public_key_pem: z.string().min(1),\n private_key_pem: z.string().min(1),\n created_at: z.string().min(1),\n updated_at: z.string().min(1),\n})\n\nexport type LinkIdentity = z.infer<typeof linkIdentitySchema>\n\nexport interface IdentityStatus {\n installId: string\n linkId: string | null\n hasPrivateKey: boolean\n publicKeyPem: string\n}\n\nexport async function loadIdentity(paths: RuntimePaths = resolveRuntimePaths()): Promise<LinkIdentity | null> {\n const value = await readJsonFile<unknown>(paths.identityFile)\n if (value === null) {\n return null\n }\n return linkIdentitySchema.parse(value)\n}\n\nexport async function ensureIdentity(paths: RuntimePaths = resolveRuntimePaths()): Promise<LinkIdentity> {\n const existing = await loadIdentity(paths)\n if (existing) {\n return existing\n }\n\n await mkdir(paths.homeDir, { recursive: true, mode: 0o700 })\n await chmod(paths.homeDir, 0o700).catch(() => undefined)\n\n const { publicKey, privateKey } = generateKeyPairSync('ed25519')\n const now = new Date().toISOString()\n const identity: LinkIdentity = {\n install_id: `install_${randomUUID().replaceAll('-', '')}`,\n link_id: null,\n public_key_pem: publicKey.export({ type: 'spki', format: 'pem' }).toString(),\n private_key_pem: privateKey.export({ type: 'pkcs8', format: 'pem' }).toString(),\n created_at: now,\n updated_at: now,\n }\n await writeJsonFile(paths.identityFile, identity)\n return identity\n}\n\nexport async function saveAssignedLinkId(\n linkId: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<LinkIdentity> {\n const identity = await ensureIdentity(paths)\n const next: LinkIdentity = {\n ...identity,\n link_id: linkId,\n updated_at: new Date().toISOString(),\n }\n await writeJsonFile(paths.identityFile, next)\n return next\n}\n\nexport function signRelayNonce(identity: LinkIdentity, nonce: string): string {\n const signature = sign(null, Buffer.from(nonce, 'utf8'), identity.private_key_pem)\n return signature.toString('base64url')\n}\n\nexport function getIdentityStatus(identity: LinkIdentity): IdentityStatus {\n return {\n installId: identity.install_id,\n linkId: identity.link_id ?? null,\n hasPrivateKey: identity.private_key_pem.trim().length > 0,\n publicKeyPem: identity.public_key_pem,\n }\n}\n\n","import { randomBytes, randomUUID, timingSafeEqual, createHash } from 'node:crypto'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { readJsonFile, writeJsonFile } from '../storage/atomic-json.js'\nimport { LinkHttpError } from '../http/errors.js'\n\nexport interface DeviceRecord {\n id: string\n label: string\n platform: string\n scope: 'admin'\n access_token_hash: string\n access_expires_at: string\n refresh_token_hash: string\n refresh_expires_at: string\n created_at: string\n updated_at: string\n revoked_at: string | null\n}\n\ninterface CredentialStore {\n devices: DeviceRecord[]\n}\n\nexport interface CreatedDeviceSession {\n device: {\n id: string\n device_id: string\n label: string\n platform: string\n scope: 'admin'\n }\n accessToken: {\n token: string\n expiresAt: string\n }\n refreshToken: {\n token: string\n expiresAt: string\n }\n}\n\nconst ACCESS_TOKEN_TTL_MS = 15 * 60 * 1000\nconst REFRESH_TOKEN_TTL_MS = 90 * 24 * 60 * 60 * 1000\n\nexport async function createDeviceSession(\n input: { label: string; platform: string },\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<CreatedDeviceSession> {\n const store = await readCredentialStore(paths)\n const now = new Date()\n const accessToken = randomToken('hpat_')\n const refreshToken = randomToken('hprt_')\n const device: DeviceRecord = {\n id: `dev_${randomUUID().replaceAll('-', '')}`,\n label: input.label,\n platform: input.platform,\n scope: 'admin',\n access_token_hash: sha256(accessToken),\n access_expires_at: new Date(now.getTime() + ACCESS_TOKEN_TTL_MS).toISOString(),\n refresh_token_hash: sha256(refreshToken),\n refresh_expires_at: new Date(now.getTime() + REFRESH_TOKEN_TTL_MS).toISOString(),\n created_at: now.toISOString(),\n updated_at: now.toISOString(),\n revoked_at: null,\n }\n store.devices.push(device)\n await writeCredentialStore(paths, store)\n return formatDeviceSession(device, accessToken, refreshToken)\n}\n\nexport async function authenticateDeviceAccessToken(\n token: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<DeviceRecord | null> {\n const tokenHash = sha256(token)\n const store = await readCredentialStore(paths)\n const device = store.devices.find((item) => safeEqual(item.access_token_hash, tokenHash))\n if (!device || device.revoked_at || Date.parse(device.access_expires_at) <= Date.now()) {\n return null\n }\n return device\n}\n\nexport async function refreshDeviceSession(\n refreshToken: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<CreatedDeviceSession> {\n const tokenHash = sha256(refreshToken)\n const store = await readCredentialStore(paths)\n const device = store.devices.find((item) => safeEqual(item.refresh_token_hash, tokenHash))\n if (!device || device.revoked_at || Date.parse(device.refresh_expires_at) <= Date.now()) {\n throw new LinkHttpError(401, 'refresh_token_invalid', 'Refresh token is invalid or expired')\n }\n\n const now = new Date()\n const nextAccessToken = randomToken('hpat_')\n const nextRefreshToken = randomToken('hprt_')\n device.access_token_hash = sha256(nextAccessToken)\n device.access_expires_at = new Date(now.getTime() + ACCESS_TOKEN_TTL_MS).toISOString()\n device.refresh_token_hash = sha256(nextRefreshToken)\n device.refresh_expires_at = new Date(now.getTime() + REFRESH_TOKEN_TTL_MS).toISOString()\n device.updated_at = now.toISOString()\n await writeCredentialStore(paths, store)\n return formatDeviceSession(device, nextAccessToken, nextRefreshToken)\n}\n\nexport async function revokeDeviceRefreshToken(\n refreshToken: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<void> {\n const tokenHash = sha256(refreshToken)\n const store = await readCredentialStore(paths)\n const device = store.devices.find((item) => safeEqual(item.refresh_token_hash, tokenHash))\n if (!device || device.revoked_at) {\n return\n }\n device.revoked_at = new Date().toISOString()\n device.updated_at = device.revoked_at\n await writeCredentialStore(paths, store)\n}\n\nasync function readCredentialStore(paths: RuntimePaths): Promise<CredentialStore> {\n const existing = await readJsonFile<Partial<CredentialStore>>(paths.credentialsFile)\n return {\n devices: Array.isArray(existing?.devices) ? existing.devices.filter(isDeviceRecord) : [],\n }\n}\n\nasync function writeCredentialStore(paths: RuntimePaths, store: CredentialStore): Promise<void> {\n await writeJsonFile(paths.credentialsFile, store)\n}\n\nfunction formatDeviceSession(device: DeviceRecord, accessToken: string, refreshToken: string): CreatedDeviceSession {\n return {\n device: {\n id: device.id,\n device_id: device.id,\n label: device.label,\n platform: device.platform,\n scope: device.scope,\n },\n accessToken: {\n token: accessToken,\n expiresAt: device.access_expires_at,\n },\n refreshToken: {\n token: refreshToken,\n expiresAt: device.refresh_expires_at,\n },\n }\n}\n\nfunction isDeviceRecord(value: unknown): value is DeviceRecord {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as DeviceRecord).id === 'string' &&\n typeof (value as DeviceRecord).access_token_hash === 'string' &&\n typeof (value as DeviceRecord).refresh_token_hash === 'string'\n )\n}\n\nfunction randomToken(prefix: string): string {\n return `${prefix}${randomBytes(24).toString('base64url')}`\n}\n\nfunction sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex')\n}\n\nfunction safeEqual(left: string, right: string): boolean {\n const leftBytes = Buffer.from(left)\n const rightBytes = Buffer.from(right)\n return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes)\n}\n","import { saveAssignedLinkId, signRelayNonce, type LinkIdentity } from '../identity/identity.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\n\nexport interface RelayBootstrapOptions {\n relayBaseUrl: string\n relayBootstrapToken: string\n identity: LinkIdentity\n paths?: RuntimePaths\n fetchImpl?: typeof fetch\n}\n\nexport interface RelayBootstrapResult {\n linkId: string\n reused: boolean\n}\n\ninterface RelayChallengeResponse {\n ok?: unknown\n nonce?: unknown\n expires_at?: unknown\n}\n\ninterface RelayBootstrapResponse {\n ok?: unknown\n link_id?: unknown\n reused?: unknown\n}\n\nexport async function bootstrapRelayLink(options: RelayBootstrapOptions): Promise<RelayBootstrapResult> {\n const fetcher = options.fetchImpl ?? fetch\n const baseUrl = options.relayBaseUrl.replace(/\\/+$/u, '')\n const commonPayload = {\n install_id: options.identity.install_id,\n link_id: options.identity.link_id ?? undefined,\n public_key_pem: options.identity.public_key_pem,\n }\n const challenge = await postJson<RelayChallengeResponse>(\n fetcher,\n `${baseUrl}/api/v1/relay/link/challenge`,\n options.relayBootstrapToken,\n commonPayload,\n )\n if (challenge.ok !== true || typeof challenge.nonce !== 'string') {\n throw new Error('Relay did not return a valid install challenge')\n }\n\n const proof = {\n nonce: challenge.nonce,\n signature: signRelayNonce(options.identity, challenge.nonce),\n }\n const assigned = await postJson<RelayBootstrapResponse>(\n fetcher,\n `${baseUrl}/api/v1/relay/link/bootstrap`,\n options.relayBootstrapToken,\n {\n ...commonPayload,\n proof,\n },\n )\n if (assigned.ok !== true || typeof assigned.link_id !== 'string') {\n throw new Error('Relay did not return a valid link_id')\n }\n\n await saveAssignedLinkId(assigned.link_id, options.paths ?? resolveRuntimePaths())\n return {\n linkId: assigned.link_id,\n reused: assigned.reused === true,\n }\n}\n\nasync function postJson<T>(\n fetcher: typeof fetch,\n url: string,\n token: string,\n body: Record<string, unknown>,\n): Promise<T> {\n const response = await fetcher(url, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n const payload = (await response.json().catch(() => null)) as T | null\n if (!response.ok) {\n const message = readErrorMessage(payload) ?? `Relay request failed with HTTP ${response.status}`\n throw new Error(message)\n }\n if (!payload) {\n throw new Error('Relay returned an empty response')\n }\n return payload\n}\n\nfunction readErrorMessage(payload: unknown): string | null {\n if (typeof payload !== 'object' || payload === null) {\n return null\n }\n const error = (payload as { error?: unknown }).error\n if (typeof error !== 'object' || error === null) {\n return null\n }\n const message = (error as { message?: unknown }).message\n return typeof message === 'string' ? message : null\n}\n","import os from 'node:os'\nimport type { NetworkInterfaceInfo } from 'node:os'\n\nexport interface RouteDiscoveryResult {\n lanIps: string[]\n publicIpv4s: string[]\n publicIpv6s: string[]\n preferredUrls: string[]\n}\n\nconst VIRTUAL_INTERFACE_NAME_PATTERN =\n /(docker|veth|vmnet|vmenet|vbox|virtualbox|vmware|tailscale|zerotier|wireguard|utun|virbr|hyper-v|vethernet|loopback|\\blo\\b|^lo\\d*$|^br-|^bridge\\d+$|^zt|^tun|^tap|awdl|llw|anpi|gif|stf|ipsec|ppp)/iu\n\nconst MAX_LAN_IPS = 4\nconst MAX_PUBLIC_IPV4S = 2\nconst MAX_PUBLIC_IPV6S = 2\n\nexport async function discoverRouteCandidates(options: {\n port: number\n relayBaseUrl: string\n linkId: string\n installId: string\n publicKeyPem: string\n relayBootstrapToken?: string\n fetchImpl?: typeof fetch\n}): Promise<RouteDiscoveryResult> {\n const lanIps = discoverLanIps()\n const publicIps = options.relayBootstrapToken\n ? await observePublicRoute(options).catch(() => ({ publicIpv4s: [], publicIpv6s: [] }))\n : { publicIpv4s: [], publicIpv6s: [] }\n const publicIpv4s = unique(publicIps.publicIpv4s.filter(isUsablePublicIpv4)).slice(0, MAX_PUBLIC_IPV4S)\n const publicIpv6s = unique(publicIps.publicIpv6s.filter(isUsablePublicIpv6)).slice(0, MAX_PUBLIC_IPV6S)\n const preferredUrls = [\n ...lanIps.map((ip) => buildDirectUrl(ip, options.port)),\n ...publicIpv4s.map((ip) => buildDirectUrl(ip, options.port)),\n ...publicIpv6s.map((ip) => buildDirectUrl(ip, options.port)),\n `${options.relayBaseUrl.replace(/\\/+$/u, '')}/api/v1/relay/links/${options.linkId}`,\n ]\n return {\n lanIps,\n publicIpv4s,\n publicIpv6s,\n preferredUrls,\n }\n}\n\nfunction discoverLanIps(): string[] {\n return discoverLanIpsFromInterfaces(os.networkInterfaces())\n}\n\nexport function discoverLanIpsFromInterfaces(interfaces: NodeJS.Dict<NetworkInterfaceInfo[]>): string[] {\n const result = new Set<string>()\n const candidates: Array<{ name: string; address: string }> = []\n for (const [name, items] of Object.entries(interfaces)) {\n if (shouldIgnoreInterface(name)) {\n continue\n }\n for (const item of items ?? []) {\n if (!item.internal && item.address && item.family === 'IPv4' && isUsableLanIpv4(item.address, item.netmask)) {\n candidates.push({ name, address: item.address })\n }\n }\n }\n for (const candidate of candidates.sort(compareLanCandidate)) {\n result.add(candidate.address)\n }\n return [...result].slice(0, MAX_LAN_IPS)\n}\n\nasync function observePublicRoute(options: {\n relayBaseUrl: string\n installId: string\n linkId: string\n publicKeyPem: string\n relayBootstrapToken?: string\n fetchImpl?: typeof fetch\n}): Promise<{ publicIpv4s: string[]; publicIpv6s: string[] }> {\n const fetcher = options.fetchImpl ?? fetch\n const response = await fetcher(`${options.relayBaseUrl.replace(/\\/+$/u, '')}/api/v1/relay/public-route/observe`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${options.relayBootstrapToken}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n install_id: options.installId,\n link_id: options.linkId,\n public_key_pem: options.publicKeyPem,\n }),\n })\n const payload = (await response.json().catch(() => null)) as Record<string, unknown> | null\n const record = typeof payload?.record === 'object' && payload.record !== null\n ? (payload.record as Record<string, unknown>)\n : null\n const observed = typeof payload?.observed === 'object' && payload.observed !== null\n ? (payload.observed as Record<string, unknown>)\n : null\n const values = [\n readIpRecord(record?.ipv4),\n readIpRecord(record?.ipv6),\n typeof observed?.ip === 'string' ? observed.ip : null,\n ].filter((value): value is string => Boolean(value))\n return {\n publicIpv4s: unique(values.filter(isUsablePublicIpv4)),\n publicIpv6s: unique(values.filter(isUsablePublicIpv6)),\n }\n}\n\nfunction readIpRecord(value: unknown): string | null {\n if (typeof value !== 'object' || value === null) {\n return null\n }\n const ip = (value as { ip?: unknown }).ip\n return typeof ip === 'string' && ip.trim() ? ip.trim() : null\n}\n\nfunction buildDirectUrl(ip: string, port: number): string {\n return `http://${ip.includes(':') ? `[${ip}]` : ip}:${port}`\n}\n\nfunction shouldIgnoreInterface(name: string): boolean {\n return !name.trim() || VIRTUAL_INTERFACE_NAME_PATTERN.test(name)\n}\n\nfunction compareLanCandidate(left: { name: string; address: string }, right: { name: string; address: string }): number {\n const priority = interfacePriority(left.name) - interfacePriority(right.name)\n return priority || left.name.localeCompare(right.name) || left.address.localeCompare(right.address)\n}\n\nfunction interfacePriority(name: string): number {\n if (/^(en|eth|wlan|wi-fi|wifi)/iu.test(name)) {\n return 0\n }\n return 1\n}\n\nfunction isUsableLanIpv4(address: string, netmask?: string): boolean {\n return isPrivateIpv4(address) && !isNetworkOrBroadcastIpv4Address(address, netmask)\n}\n\nfunction isUsablePublicIpv4(address: string): boolean {\n return isValidIpv4(address) && !isSpecialIpv4(address)\n}\n\nfunction isUsablePublicIpv6(address: string): boolean {\n const normalized = address.toLowerCase()\n return (\n normalized.includes(':') &&\n !normalized.startsWith('fe80:') &&\n !normalized.startsWith('fc') &&\n !normalized.startsWith('fd') &&\n !normalized.startsWith('ff') &&\n normalized !== '::' &&\n normalized !== '::1'\n )\n}\n\nfunction isPrivateIpv4(address: string): boolean {\n const parts = parseIpv4Segments(address)\n if (!parts) {\n return false\n }\n const [first, second] = parts\n return first === 10 || (first === 172 && second >= 16 && second <= 31) || (first === 192 && second === 168)\n}\n\nfunction isSpecialIpv4(address: string): boolean {\n const parts = parseIpv4Segments(address)\n if (!parts) {\n return true\n }\n const [first, second, third, fourth] = parts\n return (\n first === 0 ||\n first === 10 ||\n first === 127 ||\n first >= 224 ||\n (first === 100 && second >= 64 && second <= 127) ||\n (first === 169 && second === 254) ||\n (first === 172 && second >= 16 && second <= 31) ||\n (first === 192 && second === 168) ||\n (first === 192 && second === 0 && third === 2) ||\n (first === 198 && (second === 18 || second === 19)) ||\n (first === 198 && second === 51 && third === 100) ||\n (first === 203 && second === 0 && third === 113) ||\n (first === 255 && second === 255 && third === 255 && fourth === 255)\n )\n}\n\nfunction isNetworkOrBroadcastIpv4Address(address: string, netmask?: string): boolean {\n const addressParts = parseIpv4Segments(address)\n const netmaskParts = netmask ? parseIpv4Segments(netmask) : null\n if (!addressParts) {\n return true\n }\n if (!netmaskParts) {\n const last = addressParts[3]\n return last === 0 || last === 255\n }\n const addressInt = ipv4SegmentsToInt(addressParts)\n const netmaskInt = ipv4SegmentsToInt(netmaskParts)\n const hostMask = (~netmaskInt) >>> 0\n if (hostMask === 0) {\n return false\n }\n const networkInt = addressInt & netmaskInt\n const broadcastInt = (networkInt | hostMask) >>> 0\n return addressInt === networkInt || addressInt === broadcastInt\n}\n\nfunction isValidIpv4(address: string): boolean {\n return Boolean(parseIpv4Segments(address))\n}\n\nfunction parseIpv4Segments(address: string): [number, number, number, number] | null {\n if (!/^\\d{1,3}(?:\\.\\d{1,3}){3}$/u.test(address)) {\n return null\n }\n const parts = address.split('.').map((part) => Number.parseInt(part, 10))\n if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {\n return null\n }\n return parts as [number, number, number, number]\n}\n\nfunction ipv4SegmentsToInt(parts: [number, number, number, number]): number {\n return (((parts[0] << 24) >>> 0) | (parts[1] << 16) | (parts[2] << 8) | parts[3]) >>> 0\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)]\n}\n","import { loadConfig } from '../config/config.js'\nimport { createDeviceSession } from '../security/devices.js'\nimport { ensureIdentity, loadIdentity, type LinkIdentity } from '../identity/identity.js'\nimport { bootstrapRelayLink } from '../relay/bootstrap.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { discoverRouteCandidates, type RouteDiscoveryResult } from '../topology/network.js'\nimport { LinkHttpError } from '../http/errors.js'\n\nexport interface PreparedPairing {\n sessionId: string\n code: string\n pairingToken: string\n relayBootstrapToken: string\n relayBaseUrl: string\n displayName: string\n linkId: string\n routes: RouteDiscoveryResult\n qrPayload: Record<string, unknown>\n}\n\nexport async function preparePairing(paths: RuntimePaths = resolveRuntimePaths()): Promise<PreparedPairing> {\n const config = await loadConfig(paths)\n const identity = await ensureIdentity(paths)\n const created = await postServerJson<{\n sessionId: string\n code: string\n pairingToken: string\n relayBootstrapToken: string\n relayBaseUrl: string\n }>(config.serverBaseUrl, '/api/v1/link-pairings', {\n install_id: identity.install_id,\n link_id: identity.link_id ?? undefined,\n display_name: defaultDisplayName(),\n public_key_pem: identity.public_key_pem,\n })\n const relayBaseUrl = created.relayBaseUrl || config.relayBaseUrl\n const assigned = await bootstrapRelayLink({\n relayBaseUrl,\n relayBootstrapToken: created.relayBootstrapToken,\n identity,\n paths,\n })\n const updatedIdentity = (await loadIdentity(paths)) ?? identity\n const routes = await discoverRouteCandidates({\n port: config.port,\n relayBaseUrl,\n relayBootstrapToken: created.relayBootstrapToken,\n linkId: assigned.linkId,\n installId: updatedIdentity.install_id,\n publicKeyPem: updatedIdentity.public_key_pem,\n })\n await patchServerJson(config.serverBaseUrl, `/api/v1/link-pairings/${created.sessionId}/link`, created.pairingToken, {\n install_id: updatedIdentity.install_id,\n link_id: assigned.linkId,\n display_name: defaultDisplayName(),\n lan_ips: routes.lanIps,\n public_ipv4s: routes.publicIpv4s,\n public_ipv6s: routes.publicIpv6s,\n preferred_urls: routes.preferredUrls,\n })\n const qrPayload = {\n kind: 'hermes_link_pairing',\n version: 1,\n link_id: assigned.linkId,\n display_name: defaultDisplayName(),\n session_id: created.sessionId,\n code: created.code,\n preferred_urls: qrPreferredUrls(routes),\n }\n return {\n sessionId: created.sessionId,\n code: created.code,\n pairingToken: created.pairingToken,\n relayBootstrapToken: created.relayBootstrapToken,\n relayBaseUrl,\n displayName: defaultDisplayName(),\n linkId: assigned.linkId,\n routes,\n qrPayload,\n }\n}\n\nexport async function claimPairing(input: {\n sessionId: string\n claimToken: string\n deviceLabel: string\n devicePlatform: string\n paths?: RuntimePaths\n}): Promise<{\n link: { link_id: string; display_name: string }\n device: ReturnType<typeof formatDevice>\n access_token: { token: string; expires_at: string }\n refresh_token: { token: string; expires_at: string }\n}> {\n const paths = input.paths ?? resolveRuntimePaths()\n const [identity, config] = await Promise.all([loadRequiredIdentity(paths), loadConfig(paths)])\n const verified = await postServerJson<{ ok: boolean; linkId: string }>(\n config.serverBaseUrl,\n `/api/v1/link-pairings/${input.sessionId}/claim/verify`,\n {\n claim_token: input.claimToken,\n },\n )\n if (verified.ok !== true || verified.linkId !== identity.link_id) {\n throw new LinkHttpError(409, 'pairing_claim_mismatch', 'Pairing claim does not match this Link')\n }\n const session = await createDeviceSession(\n {\n label: input.deviceLabel || 'HermesPilot App',\n platform: input.devicePlatform || 'unknown',\n },\n paths,\n )\n return {\n link: {\n link_id: identity.link_id,\n display_name: defaultDisplayName(),\n },\n device: formatDevice(session.device),\n access_token: {\n token: session.accessToken.token,\n expires_at: session.accessToken.expiresAt,\n },\n refresh_token: {\n token: session.refreshToken.token,\n expires_at: session.refreshToken.expiresAt,\n },\n }\n}\n\nasync function loadRequiredIdentity(paths: RuntimePaths): Promise<LinkIdentity & { link_id: string }> {\n const identity = await loadIdentity(paths)\n if (!identity?.link_id) {\n throw new LinkHttpError(409, 'link_not_paired', 'Hermes Link is not paired')\n }\n return identity as LinkIdentity & { link_id: string }\n}\n\nasync function postServerJson<T>(serverBaseUrl: string, path: string, body: Record<string, unknown>): Promise<T> {\n const response = await fetch(`${serverBaseUrl.replace(/\\/+$/u, '')}${path}`, {\n method: 'POST',\n headers: {\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n return readJsonResponse<T>(response)\n}\n\nasync function patchServerJson<T>(\n serverBaseUrl: string,\n path: string,\n token: string,\n body: Record<string, unknown>,\n): Promise<T> {\n const response = await fetch(`${serverBaseUrl.replace(/\\/+$/u, '')}${path}`, {\n method: 'PATCH',\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n return readJsonResponse<T>(response)\n}\n\nasync function readJsonResponse<T>(response: Response): Promise<T> {\n const payload = (await response.json().catch(() => null)) as T | null\n if (!response.ok || !payload) {\n const message = readErrorMessage(payload) ?? `HermesPilot Server request failed with HTTP ${response.status}`\n throw new LinkHttpError(response.status, 'server_request_failed', message)\n }\n return payload\n}\n\nfunction readErrorMessage(payload: unknown): string | null {\n if (typeof payload !== 'object' || payload === null) {\n return null\n }\n const error = (payload as { error?: unknown }).error\n if (typeof error !== 'object' || error === null) {\n return null\n }\n const message = (error as { message?: unknown }).message\n return typeof message === 'string' ? message : null\n}\n\nfunction defaultDisplayName(): string {\n return `Hermes Link ${process.platform}`\n}\n\nfunction qrPreferredUrls(routes: RouteDiscoveryResult): string[] {\n return routes.preferredUrls.filter((url) => !url.includes('/api/v1/relay/links/')).slice(0, 1)\n}\n\nfunction formatDevice(device: { id: string; device_id: string; label: string; platform: string; scope: 'admin' }) {\n return {\n id: device.id,\n device_id: device.device_id,\n label: device.label,\n platform: device.platform,\n scope: device.scope,\n }\n}\n","import { createPublicKey, verify, type JsonWebKey as NodeJsonWebKey } from 'node:crypto'\nimport { LinkConfig } from '../config/config.js'\nimport { LinkHttpError } from '../http/errors.js'\n\ninterface JwksResponse {\n keys?: ServerJwk[]\n}\n\ninterface JwtHeader {\n alg?: string\n kid?: string\n typ?: string\n}\n\nexport interface AppConnectClaims {\n token_type: 'hermes_app_connect'\n iss: string\n aud: string\n sub: string\n link_id: string\n exp: number\n iat?: number\n jti?: string\n}\n\ntype ServerJwk = NodeJsonWebKey & { kid?: string }\n\nlet cachedJwks: { expiresAt: number; keys: ServerJwk[] } | null = null\n\nexport async function verifyAppConnectToken(\n token: string,\n options: {\n config: LinkConfig\n linkId: string\n fetchImpl?: typeof fetch\n },\n): Promise<AppConnectClaims> {\n const segments = token.split('.')\n if (segments.length !== 3) {\n throw new LinkHttpError(401, 'app_connect_token_invalid', 'App connect token is malformed')\n }\n const [encodedHeader, encodedPayload, encodedSignature] = segments\n const header = decodeJson<JwtHeader>(encodedHeader)\n const payload = decodeJson<AppConnectClaims>(encodedPayload)\n if (header.alg !== 'ES256' || header.typ !== 'JWT') {\n throw new LinkHttpError(401, 'app_connect_token_invalid', 'App connect token algorithm is unsupported')\n }\n if (\n payload.token_type !== 'hermes_app_connect' ||\n payload.iss !== options.config.appConnectTokenIssuer ||\n payload.aud !== options.config.appConnectTokenAudience ||\n payload.link_id !== options.linkId ||\n !Number.isFinite(payload.exp) ||\n payload.exp <= Math.floor(Date.now() / 1000)\n ) {\n throw new LinkHttpError(401, 'app_connect_token_invalid', 'App connect token claims are invalid')\n }\n\n const jwks = await getJwks(options.config, options.fetchImpl ?? fetch)\n const key = jwks.find((item) => item.kid === header.kid) ?? jwks[0]\n if (!key) {\n throw new LinkHttpError(503, 'app_connect_jwks_unavailable', 'App connect token key is unavailable')\n }\n const publicKey = createPublicKey({ key, format: 'jwk' })\n const ok = verify(\n 'sha256',\n Buffer.from(`${encodedHeader}.${encodedPayload}`),\n { key: publicKey, dsaEncoding: 'ieee-p1363' },\n Buffer.from(base64UrlToBase64(encodedSignature), 'base64'),\n )\n if (!ok) {\n throw new LinkHttpError(401, 'app_connect_token_invalid', 'App connect token signature is invalid')\n }\n return payload\n}\n\nasync function getJwks(config: LinkConfig, fetcher: typeof fetch): Promise<ServerJwk[]> {\n if (cachedJwks && cachedJwks.expiresAt > Date.now()) {\n return cachedJwks.keys\n }\n const response = await fetcher(`${config.serverBaseUrl.replace(/\\/+$/u, '')}/api/v1/app-connect/jwks.json`, {\n headers: { accept: 'application/json' },\n })\n if (!response.ok) {\n throw new LinkHttpError(503, 'app_connect_jwks_unavailable', 'Unable to load app connect JWKS')\n }\n const payload = (await response.json()) as JwksResponse\n const keys = Array.isArray(payload.keys) ? payload.keys : []\n cachedJwks = {\n keys,\n expiresAt: Date.now() + 5 * 60 * 1000,\n }\n return keys\n}\n\nfunction decodeJson<T>(value: string): T {\n return JSON.parse(Buffer.from(base64UrlToBase64(value), 'base64').toString('utf8')) as T\n}\n\nfunction base64UrlToBase64(value: string): string {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/')\n return normalized + '='.repeat((4 - (normalized.length % 4)) % 4)\n}\n","import { appendFile, mkdir, open, readFile, rename, rm, stat } from 'node:fs/promises'\nimport path from 'node:path'\nimport { resolveRuntimePaths, type RuntimePaths } from './paths.js'\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\nexport interface LogEntry {\n ts: string\n level: LogLevel\n message: string\n fields?: Record<string, JsonValue>\n}\n\ntype JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }\n\nexport interface FileLoggerOptions {\n paths?: RuntimePaths\n fileName?: string\n maxFileBytes?: number\n maxFiles?: number\n now?: () => Date\n}\n\nexport interface ReadLogOptions {\n paths?: RuntimePaths\n fileName?: string\n limit?: number\n maxFiles?: number\n maxBytesPerFile?: number\n}\n\nconst DEFAULT_LOG_FILE = 'hermeslink.log'\nconst DEFAULT_MAX_FILE_BYTES = 1024 * 1024\nconst DEFAULT_MAX_FILES = 5\nconst DEFAULT_READ_LIMIT = 200\nconst MAX_READ_LIMIT = 1000\nconst DEFAULT_MAX_BYTES_PER_FILE = 512 * 1024\n\nexport class FileLogger {\n readonly filePath: string\n private readonly paths: RuntimePaths\n private readonly maxFileBytes: number\n private readonly maxFiles: number\n private readonly now: () => Date\n private queue = Promise.resolve()\n\n constructor(options: FileLoggerOptions = {}) {\n this.paths = options.paths ?? resolveRuntimePaths()\n this.filePath = getLinkLogFile(this.paths, options.fileName)\n this.maxFileBytes = Math.max(256, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES))\n this.maxFiles = Math.max(0, Math.floor(options.maxFiles ?? DEFAULT_MAX_FILES))\n this.now = options.now ?? (() => new Date())\n }\n\n debug(message: string, fields?: Record<string, unknown>): Promise<void> {\n return this.write('debug', message, fields)\n }\n\n info(message: string, fields?: Record<string, unknown>): Promise<void> {\n return this.write('info', message, fields)\n }\n\n warn(message: string, fields?: Record<string, unknown>): Promise<void> {\n return this.write('warn', message, fields)\n }\n\n error(message: string, fields?: Record<string, unknown>): Promise<void> {\n return this.write('error', message, fields)\n }\n\n write(level: LogLevel, message: string, fields?: Record<string, unknown>): Promise<void> {\n const entry: LogEntry = {\n ts: this.now().toISOString(),\n level,\n message,\n ...(fields ? { fields: sanitizeFields(fields) } : {}),\n }\n const next = this.queue.then(() => this.appendEntry(entry)).catch(() => undefined)\n this.queue = next\n return next\n }\n\n flush(): Promise<void> {\n return this.queue\n }\n\n private async appendEntry(entry: LogEntry): Promise<void> {\n await mkdir(this.paths.logsDir, { recursive: true, mode: 0o700 })\n const line = `${JSON.stringify(entry)}\\n`\n await this.rotateIfNeeded(Buffer.byteLength(line, 'utf8'))\n await appendFile(this.filePath, line, { mode: 0o600 })\n }\n\n private async rotateIfNeeded(nextBytes: number): Promise<void> {\n const current = await stat(this.filePath).catch(() => null)\n if (!current || current.size === 0 || current.size + nextBytes <= this.maxFileBytes) {\n return\n }\n if (this.maxFiles === 0) {\n await rm(this.filePath, { force: true }).catch(() => undefined)\n return\n }\n await rm(rotatedLogFile(this.filePath, this.maxFiles), { force: true }).catch(() => undefined)\n for (let index = this.maxFiles - 1; index >= 1; index -= 1) {\n await moveIfExists(rotatedLogFile(this.filePath, index), rotatedLogFile(this.filePath, index + 1))\n }\n await moveIfExists(this.filePath, rotatedLogFile(this.filePath, 1))\n }\n}\n\nexport function createFileLogger(options: FileLoggerOptions = {}): FileLogger {\n return new FileLogger(options)\n}\n\nexport function getLinkLogFile(paths: RuntimePaths = resolveRuntimePaths(), fileName = DEFAULT_LOG_FILE): string {\n return path.join(paths.logsDir, fileName)\n}\n\nexport async function readRecentLogEntries(options: ReadLogOptions = {}): Promise<LogEntry[]> {\n const paths = options.paths ?? resolveRuntimePaths()\n const filePath = getLinkLogFile(paths, options.fileName)\n const limit = clampLimit(options.limit)\n const maxFiles = Math.max(0, Math.floor(options.maxFiles ?? DEFAULT_MAX_FILES))\n const maxBytesPerFile = Math.max(1024, Math.floor(options.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE))\n const files = [filePath, ...Array.from({ length: maxFiles }, (_, index) => rotatedLogFile(filePath, index + 1))]\n const entries: LogEntry[] = []\n\n for (const file of files) {\n const raw = await readTail(file, maxBytesPerFile)\n if (!raw) {\n continue\n }\n const lines = raw.split(/\\r?\\n/u).filter(Boolean)\n for (let index = lines.length - 1; index >= 0 && entries.length < limit; index -= 1) {\n const entry = parseLogLine(lines[index])\n if (entry) {\n entries.push(entry)\n }\n }\n if (entries.length >= limit) {\n break\n }\n }\n\n return entries.reverse()\n}\n\nfunction clampLimit(value: number | undefined): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return DEFAULT_READ_LIMIT\n }\n return Math.min(MAX_READ_LIMIT, Math.max(1, Math.floor(value)))\n}\n\nfunction sanitizeFields(fields: Record<string, unknown>): Record<string, JsonValue> {\n return sanitizeObject(fields, 0)\n}\n\nfunction sanitizeValue(value: unknown, depth: number): JsonValue {\n if (value === null || typeof value === 'boolean') {\n return value\n }\n if (typeof value === 'number') {\n return Number.isFinite(value) ? value : null\n }\n if (typeof value === 'string') {\n return value.length > 2000 ? `${value.slice(0, 2000)}...` : value\n }\n if (Array.isArray(value)) {\n if (depth >= 3) {\n return '[array]'\n }\n return value.slice(0, 20).map((item) => sanitizeValue(item, depth + 1))\n }\n if (typeof value === 'object' && value !== null) {\n if (depth >= 3) {\n return '[object]'\n }\n return sanitizeObject(value as Record<string, unknown>, depth + 1)\n }\n return String(value)\n}\n\nfunction sanitizeObject(value: Record<string, unknown>, depth: number): Record<string, JsonValue> {\n const result: Record<string, JsonValue> = {}\n for (const [key, child] of Object.entries(value).slice(0, 50)) {\n if (isSensitiveKey(key)) {\n result[key] = '[redacted]'\n continue\n }\n result[key] = sanitizeValue(child, depth)\n }\n return result\n}\n\nfunction isSensitiveKey(key: string): boolean {\n return /(authorization|cookie|token|secret|password|private[_-]?key|api[_-]?key)/iu.test(key)\n}\n\nfunction parseLogLine(line: string): LogEntry | null {\n try {\n const value = JSON.parse(line) as Partial<LogEntry>\n if (!value || typeof value.ts !== 'string' || !isLogLevel(value.level) || typeof value.message !== 'string') {\n return null\n }\n return {\n ts: value.ts,\n level: value.level,\n message: value.message,\n ...(value.fields && typeof value.fields === 'object' ? { fields: value.fields as Record<string, JsonValue> } : {}),\n }\n } catch {\n return null\n }\n}\n\nfunction isLogLevel(value: unknown): value is LogLevel {\n return value === 'debug' || value === 'info' || value === 'warn' || value === 'error'\n}\n\nasync function readTail(filePath: string, maxBytes: number): Promise<string | null> {\n const info = await stat(filePath).catch(() => null)\n if (!info || info.size <= 0) {\n return null\n }\n if (info.size <= maxBytes) {\n return await readFile(filePath, 'utf8').catch(() => null)\n }\n const handle = await open(filePath, 'r').catch(() => null)\n if (!handle) {\n return null\n }\n try {\n const length = Math.min(info.size, maxBytes)\n const buffer = Buffer.alloc(length)\n await handle.read(buffer, 0, length, info.size - length)\n return buffer.toString('utf8')\n } finally {\n await handle.close()\n }\n}\n\nasync function moveIfExists(from: string, to: string): Promise<void> {\n await rm(to, { force: true }).catch(() => undefined)\n await rename(from, to).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error\n }\n })\n}\n\nfunction rotatedLogFile(filePath: string, index: number): string {\n return `${filePath}.${index}`\n}\n"],"mappings":"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","names":["path","mkdir","readFile","os","path","isNodeError","runId","path","mkdir","rename","rm","os","path","path","os","isNodeError","mkdir","rename","rm","randomUUID","mkdir","mkdir","randomUUID","randomBytes","randomUUID","randomUUID","randomBytes","os","path","readJsonResponse","readErrorMessage","mkdir","open","readFile","rename","rm","stat","path","mkdir","stat","rm","path","readFile","open","rename","readString","loadRequiredIdentity"]}
1
+ {"version":3,"sources":["../src/http/app.ts","../src/constants.ts","../src/runtime/paths.ts","../src/storage/atomic-json.ts","../src/config/config.ts","../src/http/errors.ts","../src/hermes/api-server.ts","../src/hermes/config.ts","../src/hermes/profiles.ts","../src/identity/identity.ts","../src/security/devices.ts","../src/relay/bootstrap.ts","../src/topology/network.ts","../src/pairing/pairing.ts","../src/security/app-connect-token.ts","../src/runtime/logger.ts"],"sourcesContent":["import Koa from 'koa'\nimport Router from '@koa/router'\nimport { Readable } from 'node:stream'\nimport { LINK_VERSION } from '../constants.js'\nimport { loadConfig } from '../config/config.js'\nimport { LinkHttpError, isLinkHttpError } from './errors.js'\nimport {\n cancelHermesRun,\n createHermesRun,\n listHermesModels,\n streamHermesRunEvents,\n} from '../hermes/api-server.js'\nimport {\n createHermesProfile,\n deleteHermesProfile,\n getHermesProfileStatus,\n listHermesProfiles,\n renameHermesProfile,\n useHermesProfile,\n} from '../hermes/profiles.js'\nimport { loadIdentity } from '../identity/identity.js'\nimport { claimPairing } from '../pairing/pairing.js'\nimport {\n authenticateDeviceAccessToken,\n refreshDeviceSession,\n revokeDeviceRefreshToken,\n type DeviceRecord,\n} from '../security/devices.js'\nimport { verifyAppConnectToken } from '../security/app-connect-token.js'\nimport { createFileLogger, readRecentLogEntries, type FileLogger } from '../runtime/logger.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { discoverRouteCandidates } from '../topology/network.js'\n\ninterface AuthContext {\n kind: 'device' | 'app-connect'\n device?: DeviceRecord\n accountId?: string\n}\n\nexport interface CreateAppOptions {\n paths?: RuntimePaths\n logger?: FileLogger\n onPairingClaimed?: () => void | Promise<void>\n}\n\nexport async function createApp(options: CreateAppOptions = {}): Promise<Koa> {\n const paths = options.paths ?? resolveRuntimePaths()\n const logger = options.logger ?? createFileLogger({ paths })\n const app = new Koa()\n const router = new Router()\n\n app.use(async (ctx, next) => {\n const startedAt = Date.now()\n try {\n await next()\n } catch (error) {\n const profileError = error instanceof Error && error.message === 'invalid profile name'\n const status = isLinkHttpError(error) ? error.status : profileError ? 400 : 500\n ctx.status = status\n ctx.body = {\n ok: false,\n error: {\n code: isLinkHttpError(error) ? error.code : status === 400 ? 'invalid_profile_name' : 'internal_error',\n message: error instanceof Error ? error.message : 'Internal error',\n },\n }\n void logger.write(status >= 500 ? 'error' : 'warn', 'http_request_failed', {\n method: ctx.method,\n path: ctx.path,\n status,\n code: isLinkHttpError(error) ? error.code : status === 400 ? 'invalid_profile_name' : 'internal_error',\n error: error instanceof Error ? error.message : String(error),\n })\n } finally {\n void logger.info('http_request', {\n method: ctx.method,\n path: ctx.path,\n status: ctx.status,\n duration_ms: Date.now() - startedAt,\n })\n }\n })\n\n router.get('/api/v1/bootstrap', async (ctx) => {\n const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)])\n const routes = identity?.link_id\n ? await discoverRouteCandidates({\n port: config.port,\n relayBaseUrl: config.relayBaseUrl,\n linkId: identity.link_id,\n installId: identity.install_id,\n publicKeyPem: identity.public_key_pem,\n })\n : null\n ctx.set('cache-control', 'no-store')\n ctx.body = {\n link_id: identity?.link_id ?? null,\n display_name: identity?.link_id ? 'Hermes Link' : 'Unpaired Hermes Link',\n version: LINK_VERSION,\n api_version: 1,\n paired: Boolean(identity?.link_id),\n pairing_supported: Boolean(identity?.link_id),\n preferred_pairing_urls: routes?.preferredUrls ?? [],\n routes: routes ? routeObjects(routes.preferredUrls) : [],\n capabilities: {\n runs: true,\n sse: true,\n relay: true,\n profiles: true,\n logs: true,\n },\n }\n })\n\n router.post('/api/v1/pairing/claim', async (ctx) => {\n const body = await readJsonBody(ctx.req)\n const sessionId = readString(body, 'session_id') ?? readString(body, 'sessionId')\n const claimToken = readString(body, 'claim_token') ?? readString(body, 'claimToken')\n if (!sessionId || !claimToken) {\n throw new LinkHttpError(400, 'pairing_claim_invalid', 'session_id and claim_token are required')\n }\n const claimed = await claimPairing({\n sessionId,\n claimToken,\n deviceLabel: readString(body, 'device_label') ?? readString(body, 'deviceLabel') ?? 'HermesPilot App',\n devicePlatform: readString(body, 'device_platform') ?? readString(body, 'devicePlatform') ?? 'unknown',\n paths,\n })\n ctx.body = claimed\n void logger.info('pairing_claimed', {\n device_id: claimed.device.device_id,\n device_platform: claimed.device.platform,\n })\n if (options.onPairingClaimed) {\n const timer = setTimeout(() => {\n void options.onPairingClaimed?.()\n }, 250)\n timer.unref?.()\n }\n })\n\n router.get('/api/v1/auth/me', async (ctx) => {\n const auth = await authenticateRequest(ctx, paths)\n const identity = await loadRequiredIdentity(paths)\n ctx.body = {\n ok: true,\n auth: { kind: auth.kind, account_id: auth.accountId ?? null },\n link: {\n link_id: identity.link_id,\n display_name: 'Hermes Link',\n },\n device: auth.device\n ? {\n id: auth.device.id,\n device_id: auth.device.id,\n label: auth.device.label,\n platform: auth.device.platform,\n scope: auth.device.scope,\n }\n : null,\n }\n })\n\n router.post('/api/v1/auth/refresh', async (ctx) => {\n const body = await readJsonBody(ctx.req)\n const refreshToken = readString(body, 'refresh_token') ?? readString(body, 'refreshToken')\n if (!refreshToken) {\n throw new LinkHttpError(400, 'refresh_token_required', 'refresh_token is required')\n }\n const session = await refreshDeviceSession(refreshToken, paths)\n ctx.body = {\n ok: true,\n device: session.device,\n access_token: {\n token: session.accessToken.token,\n expires_at: session.accessToken.expiresAt,\n },\n refresh_token: {\n token: session.refreshToken.token,\n expires_at: session.refreshToken.expiresAt,\n },\n }\n })\n\n router.post('/api/v1/auth/logout', async (ctx) => {\n const body = await readJsonBody(ctx.req)\n const refreshToken = readString(body, 'refresh_token') ?? readString(body, 'refreshToken')\n if (refreshToken) {\n await revokeDeviceRefreshToken(refreshToken, paths)\n }\n ctx.body = { ok: true }\n })\n\n router.get('/api/v1/status', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)])\n ctx.body = {\n ok: true,\n version: LINK_VERSION,\n paired: Boolean(identity?.link_id),\n link_id: identity?.link_id ?? null,\n port: config.port,\n }\n })\n\n router.get('/api/v1/logs', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.set('cache-control', 'no-store')\n ctx.body = {\n ok: true,\n logs: await readRecentLogEntries({\n paths,\n limit: readLimit(ctx.query.limit),\n }),\n }\n })\n\n router.get('/api/v1/models', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.body = await listHermesModels()\n })\n\n router.post('/api/v1/runs', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const body = await readJsonBody(ctx.req)\n const input = readString(body, 'input')\n if (!input) {\n throw new LinkHttpError(400, 'run_input_required', 'input is required')\n }\n ctx.status = 202\n ctx.body = await createHermesRun({\n input,\n conversation_history: readConversationHistory(body.conversation_history ?? body.conversationHistory),\n session_id: readString(body, 'session_id') ?? readString(body, 'sessionId') ?? undefined,\n })\n })\n\n router.get('/api/v1/runs/:runId/events', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const response = await streamHermesRunEvents(ctx.params.runId)\n ctx.status = response.status\n for (const [key, value] of response.headers.entries()) {\n ctx.set(key, value)\n }\n ctx.respond = false\n const nodeResponse = ctx.res\n nodeResponse.statusCode = response.status\n for (const [key, value] of response.headers.entries()) {\n nodeResponse.setHeader(key, value)\n }\n if (response.body) {\n Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]).pipe(nodeResponse)\n } else {\n nodeResponse.end()\n }\n })\n\n router.post('/api/v1/runs/:runId/cancel', async (ctx) => {\n await authenticateRequest(ctx, paths)\n await cancelHermesRun(ctx.params.runId)\n ctx.body = { ok: true }\n })\n\n router.get('/api/v1/profiles', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.set('cache-control', 'no-store')\n ctx.body = {\n ok: true,\n profiles: await listHermesProfiles(),\n }\n })\n\n router.get('/api/v1/profiles/:name/status', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.set('cache-control', 'no-store')\n ctx.body = {\n ok: true,\n profile: await getHermesProfileStatus(ctx.params.name),\n }\n })\n\n router.post('/api/v1/profiles', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const body = await readJsonBody(ctx.req)\n const name = readProfileName(body)\n ctx.status = 201\n ctx.body = {\n ok: true,\n profile: await createHermesProfile(name),\n }\n })\n\n router.post('/api/v1/profiles/:name/use', async (ctx) => {\n await authenticateRequest(ctx, paths)\n ctx.body = {\n ok: true,\n profile: await useHermesProfile(ctx.params.name),\n }\n })\n\n router.patch('/api/v1/profiles/:name', async (ctx) => {\n await authenticateRequest(ctx, paths)\n const body = await readJsonBody(ctx.req)\n const name = readProfileName(body)\n ctx.body = {\n ok: true,\n profile: await renameHermesProfile(ctx.params.name, name),\n }\n })\n\n router.delete('/api/v1/profiles/:name', async (ctx) => {\n await authenticateRequest(ctx, paths)\n await deleteHermesProfile(ctx.params.name)\n ctx.status = 204\n })\n\n app.use(router.routes())\n app.use(router.allowedMethods())\n return app\n}\n\nasync function readJsonBody(request: NodeJS.ReadableStream): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = []\n for await (const chunk of request) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n if (chunks.length === 0) {\n return {}\n }\n return JSON.parse(Buffer.concat(chunks).toString('utf8')) as Record<string, unknown>\n}\n\nfunction readProfileName(body: Record<string, unknown>): string {\n if (typeof body.name !== 'string') {\n throw new Error('invalid profile name')\n }\n return body.name\n}\n\nasync function authenticateRequest(ctx: Koa.ParameterizedContext, paths: RuntimePaths): Promise<AuthContext> {\n const token = readBearerToken(ctx.get('authorization'))\n if (!token) {\n throw new LinkHttpError(401, 'auth_required', 'Authorization bearer token is required')\n }\n const device = await authenticateDeviceAccessToken(token, paths)\n if (device) {\n return { kind: 'device', device }\n }\n const [identity, config] = await Promise.all([loadRequiredIdentity(paths), loadConfig(paths)])\n const claims = await verifyAppConnectToken(token, {\n config,\n linkId: identity.link_id,\n })\n return { kind: 'app-connect', accountId: claims.sub }\n}\n\nasync function loadRequiredIdentity(paths: RuntimePaths) {\n const identity = await loadIdentity(paths)\n if (!identity?.link_id) {\n throw new LinkHttpError(409, 'link_not_paired', 'Hermes Link is not paired')\n }\n return identity as NonNullable<typeof identity> & { link_id: string }\n}\n\nfunction readBearerToken(value: string): string | null {\n const trimmed = value.trim()\n if (!trimmed.toLowerCase().startsWith('bearer ')) {\n return null\n }\n const token = trimmed.slice(7).trim()\n return token || null\n}\n\nfunction readString(body: Record<string, unknown>, key: string): string | null {\n const value = body[key]\n return typeof value === 'string' && value.trim() ? value.trim() : null\n}\n\nfunction readLimit(value: unknown): number | undefined {\n const raw = Array.isArray(value) ? value[0] : value\n if (typeof raw !== 'string') {\n return undefined\n }\n const parsed = Number.parseInt(raw, 10)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nfunction readConversationHistory(value: unknown): Array<{ role: string; content: string }> {\n if (!Array.isArray(value)) {\n return []\n }\n return value\n .map((item) => {\n if (typeof item !== 'object' || item === null) {\n return null\n }\n const role = (item as { role?: unknown }).role\n const content = (item as { content?: unknown }).content\n if (typeof role !== 'string' || typeof content !== 'string') {\n return null\n }\n return { role, content }\n })\n .filter((item): item is { role: string; content: string } => Boolean(item))\n}\n\nfunction routeObjects(urls: string[]) {\n return urls.map((url) => ({\n kind: url.includes('/api/v1/relay/links/') ? 'relay' : 'lan',\n url,\n observed_at: new Date().toISOString(),\n }))\n}\n","export const LINK_VERSION = '0.1.4'\nexport const LINK_COMMAND = 'hermeslink'\nexport const LINK_DEFAULT_PORT = 52379\nexport const LINK_RUNTIME_DIR_NAME = '.hermeslink'\n","import os from 'node:os'\nimport path from 'node:path'\nimport { LINK_RUNTIME_DIR_NAME } from '../constants.js'\n\nexport interface RuntimePaths {\n homeDir: string\n identityFile: string\n configFile: string\n stateFile: string\n credentialsFile: string\n databaseFile: string\n logsDir: string\n runDir: string\n pairingDir: string\n}\n\nexport function resolveRuntimeHome(): string {\n return process.env.HERMESLINK_HOME?.trim()\n ? path.resolve(process.env.HERMESLINK_HOME)\n : path.join(os.homedir(), LINK_RUNTIME_DIR_NAME)\n}\n\nexport function resolveRuntimePaths(homeDir = resolveRuntimeHome()): RuntimePaths {\n return {\n homeDir,\n identityFile: path.join(homeDir, 'identity.json'),\n configFile: path.join(homeDir, 'config.json'),\n stateFile: path.join(homeDir, 'state.json'),\n credentialsFile: path.join(homeDir, 'credentials.json'),\n databaseFile: path.join(homeDir, 'link.db'),\n logsDir: path.join(homeDir, 'logs'),\n runDir: path.join(homeDir, 'run'),\n pairingDir: path.join(homeDir, 'pairing'),\n }\n}\n\n","import { mkdir, open, readFile, rename, rm } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport async function readJsonFile<T>(filePath: string): Promise<T | null> {\n try {\n const raw = await readFile(filePath, 'utf8')\n return JSON.parse(raw) as T\n } catch (error) {\n if (isNodeError(error, 'ENOENT')) {\n return null\n }\n throw error\n }\n}\n\nexport async function writeJsonFile(filePath: string, value: unknown, mode = 0o600): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 })\n const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`\n const payload = `${JSON.stringify(value, null, 2)}\\n`\n const handle = await open(tmpPath, 'w', mode)\n try {\n await handle.writeFile(payload, 'utf8')\n await handle.sync()\n } finally {\n await handle.close()\n }\n try {\n await rename(tmpPath, filePath)\n } catch (error) {\n await rm(tmpPath, { force: true })\n throw error\n }\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code\n}\n\n","import { LINK_DEFAULT_PORT } from '../constants.js'\nimport type { ConfiguredLanguage } from '../i18n.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { readJsonFile, writeJsonFile } from '../storage/atomic-json.js'\n\nexport interface LinkConfig {\n port: number\n serverBaseUrl: string\n relayBaseUrl: string\n appConnectTokenIssuer: string\n appConnectTokenAudience: string\n language: ConfiguredLanguage\n}\n\nexport const defaultLinkConfig: LinkConfig = {\n port: LINK_DEFAULT_PORT,\n serverBaseUrl: 'https://hermes-server.clawpilot.me',\n relayBaseUrl: 'https://hermes-relay.clawpilot.me',\n appConnectTokenIssuer: 'https://hermes-server.clawpilot.me',\n appConnectTokenAudience: 'hermes-link',\n language: 'auto',\n}\n\nexport async function loadConfig(paths: RuntimePaths = resolveRuntimePaths()): Promise<LinkConfig> {\n const existing = await readJsonFile<Partial<LinkConfig>>(paths.configFile)\n const language = normalizeConfiguredLanguage(existing?.language)\n return {\n ...defaultLinkConfig,\n ...(existing ?? {}),\n language,\n }\n}\n\nexport async function saveConfig(\n patch: Partial<LinkConfig>,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<LinkConfig> {\n const current = await loadConfig(paths)\n const next = { ...current, ...patch }\n await writeJsonFile(paths.configFile, next)\n return next\n}\n\nfunction normalizeConfiguredLanguage(language: unknown): ConfiguredLanguage {\n if (language === 'zh-CN' || language === 'en' || language === 'auto') {\n return language\n }\n return defaultLinkConfig.language\n}\n","export class LinkHttpError extends Error {\n constructor(\n readonly status: number,\n readonly code: string,\n message: string,\n ) {\n super(message)\n }\n}\n\nexport function isLinkHttpError(error: unknown): error is LinkHttpError {\n return error instanceof LinkHttpError\n}\n","import { randomUUID } from 'node:crypto'\nimport { readHermesApiServerConfig } from './config.js'\nimport { LinkHttpError } from '../http/errors.js'\n\nexport interface HermesRunRequest {\n input: string\n conversation_history?: Array<{ role: string; content: string }>\n session_id?: string\n}\n\nexport interface HermesApiClientOptions {\n fetchImpl?: typeof fetch\n}\n\nconst fallbackRuns = new Map<string, { input: string; createdAt: string }>()\n\nexport async function listHermesModels(options: HermesApiClientOptions = {}): Promise<unknown> {\n const response = await callHermesApi('/v1/models', { method: 'GET' }, options)\n if (response.status === 404) {\n return { models: [] }\n }\n return await readJsonResponse(response)\n}\n\nexport async function createHermesRun(\n input: HermesRunRequest,\n options: HermesApiClientOptions = {},\n): Promise<{ run_id: string; fallback: boolean }> {\n const response = await callHermesApi(\n '/v1/runs',\n {\n method: 'POST',\n body: JSON.stringify(input),\n headers: { 'content-type': 'application/json' },\n },\n options,\n )\n if (response.status === 404 || response.status === 503) {\n const runId = `run_${randomUUID().replaceAll('-', '')}`\n fallbackRuns.set(runId, { input: input.input, createdAt: new Date().toISOString() })\n return { run_id: runId, fallback: true }\n }\n const payload = await readJsonResponse(response)\n const runId = readString(payload, 'run_id') ?? readString(payload, 'runId') ?? readString(payload, 'id')\n if (!runId) {\n throw new LinkHttpError(502, 'hermes_run_invalid', 'Hermes API Server did not return a run id')\n }\n return { run_id: runId, fallback: false }\n}\n\nexport async function streamHermesRunEvents(\n runId: string,\n options: HermesApiClientOptions = {},\n): Promise<Response> {\n const fallback = fallbackRuns.get(runId)\n if (fallback) {\n fallbackRuns.delete(runId)\n return new Response(createFallbackSseStream(fallback.input), {\n headers: {\n 'content-type': 'text/event-stream; charset=utf-8',\n 'cache-control': 'no-store',\n },\n })\n }\n const response = await callHermesApi(`/v1/runs/${encodeURIComponent(runId)}/events`, { method: 'GET' }, options)\n if (!response.ok || !response.body) {\n throw new LinkHttpError(502, 'hermes_events_unavailable', 'Hermes run event stream is unavailable')\n }\n return new Response(response.body, {\n status: response.status,\n headers: {\n 'content-type': response.headers.get('content-type') ?? 'text/event-stream; charset=utf-8',\n 'cache-control': 'no-store',\n },\n })\n}\n\nexport async function cancelHermesRun(runId: string, options: HermesApiClientOptions = {}): Promise<void> {\n const response = await callHermesApi(\n `/v1/runs/${encodeURIComponent(runId)}/cancel`,\n { method: 'POST' },\n options,\n )\n if (!response.ok && response.status !== 404) {\n throw new LinkHttpError(502, 'hermes_cancel_failed', 'Hermes run cancel failed')\n }\n fallbackRuns.delete(runId)\n}\n\nasync function callHermesApi(\n path: string,\n init: RequestInit,\n options: HermesApiClientOptions,\n): Promise<Response> {\n const config = await readHermesApiServerConfig()\n if (!config.port || !config.key) {\n return new Response(null, { status: 503 })\n }\n const fetcher = options.fetchImpl ?? fetch\n const headers = new Headers(init.headers)\n headers.set('accept', headers.get('accept') ?? 'application/json')\n headers.set('x-api-key', config.key)\n headers.set('authorization', `Bearer ${config.key}`)\n return await fetcher(`http://127.0.0.1:${config.port}${path}`, {\n ...init,\n headers,\n }).catch(() => new Response(null, { status: 503 }))\n}\n\nasync function readJsonResponse(response: Response): Promise<Record<string, unknown>> {\n const payload = (await response.json().catch(() => null)) as unknown\n if (!response.ok || typeof payload !== 'object' || payload === null) {\n throw new LinkHttpError(502, 'hermes_response_invalid', 'Hermes API Server returned an invalid response')\n }\n return payload as Record<string, unknown>\n}\n\nfunction createFallbackSseStream(input: string): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder()\n return new ReadableStream<Uint8Array>({\n start(controller) {\n const message = `Hermes API Server is not running yet. Link received: ${input}`\n controller.enqueue(encoder.encode(`event: message.delta\\ndata: ${JSON.stringify({ type: 'message.delta', delta: message })}\\n\\n`))\n controller.enqueue(encoder.encode(`event: run.completed\\ndata: ${JSON.stringify({ type: 'run.completed' })}\\n\\n`))\n controller.close()\n },\n })\n}\n\nfunction readString(payload: Record<string, unknown>, key: string): string | null {\n const value = payload[key]\n return typeof value === 'string' && value.trim() ? value.trim() : null\n}\n","import { randomBytes } from 'node:crypto'\nimport { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport YAML from 'yaml'\n\nexport interface HermesApiServerConfig {\n host?: string\n port?: number\n key?: string\n}\n\nexport interface EnsureHermesConfigResult {\n configPath: string\n apiServer: HermesApiServerConfig\n changed: boolean\n keyAdded: boolean\n backupPath: string | null\n notice: string | null\n}\n\nexport function resolveHermesProfileDir(profileName = 'default'): string {\n if (profileName === 'default') {\n return path.join(os.homedir(), '.hermes')\n }\n return path.join(os.homedir(), '.hermes', 'profiles', profileName)\n}\n\nexport function resolveHermesConfigPath(profileName = 'default'): string {\n return path.join(resolveHermesProfileDir(profileName), 'config.yaml')\n}\n\nexport async function readHermesApiServerConfig(\n profileName = 'default',\n configPath = resolveHermesConfigPath(profileName),\n): Promise<HermesApiServerConfig> {\n const existingRaw = await readFile(configPath, 'utf8').catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return null\n }\n throw error\n })\n if (!existingRaw) {\n return {}\n }\n const config = toRecord(YAML.parse(existingRaw))\n const platforms = toRecord(config.platforms)\n const apiServer = toRecord(platforms.api_server)\n return readApiServerConfig(toRecord(apiServer.extra))\n}\n\nexport async function ensureHermesApiServerKey(\n profileName = 'default',\n configPath = resolveHermesConfigPath(profileName),\n): Promise<EnsureHermesConfigResult> {\n const existingRaw = await readFile(configPath, 'utf8').catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return null\n }\n throw error\n })\n const document = existingRaw ? YAML.parseDocument(existingRaw) : new YAML.Document({})\n const config = toRecord(document.toJSON())\n const platforms = ensureRecord(config, 'platforms')\n const apiServer = ensureRecord(platforms, 'api_server')\n const extra = ensureRecord(apiServer, 'extra')\n const beforeKey = typeof extra.key === 'string' && extra.key.length > 0 ? extra.key : null\n\n let changed = false\n if (!beforeKey) {\n extra.key = randomBytes(32).toString('base64url')\n changed = true\n }\n\n if (!changed) {\n return {\n configPath,\n apiServer: readApiServerConfig(extra),\n changed: false,\n keyAdded: false,\n backupPath: null,\n notice: null,\n }\n }\n\n const backupPath = existingRaw ? `${configPath}.bak.${Date.now()}` : null\n await mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 })\n if (backupPath) {\n await copyFile(configPath, backupPath)\n }\n document.contents = document.createNode(config)\n await writeFile(configPath, document.toString(), { mode: 0o600 })\n\n return {\n configPath,\n apiServer: readApiServerConfig(extra),\n changed: true,\n keyAdded: true,\n backupPath,\n notice: '已为 Hermes API Server 自动补充 key;未覆盖已有 port/host/key。',\n }\n}\n\nfunction readApiServerConfig(extra: Record<string, unknown>): HermesApiServerConfig {\n return {\n host: typeof extra.host === 'string' ? extra.host : undefined,\n port: typeof extra.port === 'number' ? extra.port : undefined,\n key: typeof extra.key === 'string' ? extra.key : undefined,\n }\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : {}\n}\n\nfunction ensureRecord(parent: Record<string, unknown>, key: string): Record<string, unknown> {\n const value = parent[key]\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n return value as Record<string, unknown>\n }\n const next: Record<string, unknown> = {}\n parent[key] = next\n return next\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code\n}\n","import { mkdir, readdir, rename, rm, stat } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { readJsonFile, writeJsonFile } from '../storage/atomic-json.js'\nimport {\n ensureHermesApiServerKey,\n readHermesApiServerConfig,\n resolveHermesConfigPath,\n resolveHermesProfileDir,\n} from './config.js'\n\nexport interface HermesProfile {\n name: string\n active: boolean\n path: string\n configPath: string\n}\n\ninterface ProfileState {\n activeProfile: string\n}\n\nconst DEFAULT_PROFILE = 'default'\nconst PROFILE_NAME_PATTERN = /^[a-zA-Z0-9._-]{1,64}$/\n\nexport async function listHermesProfiles(paths: RuntimePaths = resolveRuntimePaths()): Promise<HermesProfile[]> {\n const activeProfile = await getActiveProfile(paths)\n const profiles = new Map<string, HermesProfile>()\n profiles.set(DEFAULT_PROFILE, profileInfo(DEFAULT_PROFILE, activeProfile))\n\n const profilesDir = path.join(os.homedir(), '.hermes', 'profiles')\n const entries = await readdir(profilesDir, { withFileTypes: true }).catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return []\n }\n throw error\n })\n for (const entry of entries) {\n if (entry.isDirectory() && PROFILE_NAME_PATTERN.test(entry.name)) {\n profiles.set(entry.name, profileInfo(entry.name, activeProfile))\n }\n }\n\n return [...profiles.values()].sort((left, right) => {\n if (left.name === DEFAULT_PROFILE) {\n return -1\n }\n if (right.name === DEFAULT_PROFILE) {\n return 1\n }\n return left.name.localeCompare(right.name)\n })\n}\n\nexport async function getHermesProfileStatus(\n name: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<HermesProfile & { exists: boolean; apiKeyConfigured: boolean }> {\n assertProfileName(name)\n const profile = profileInfo(name, await getActiveProfile(paths))\n const exists = await stat(profile.path)\n .then((value) => value.isDirectory())\n .catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return false\n }\n throw error\n })\n const config = await readHermesApiServerConfig(name, profile.configPath)\n return {\n ...profile,\n exists,\n apiKeyConfigured: Boolean(config.key),\n }\n}\n\nexport async function createHermesProfile(name: string): Promise<HermesProfile> {\n assertProfileName(name)\n if (name === DEFAULT_PROFILE) {\n throw new Error('default profile already exists')\n }\n const profile = profileInfo(name, DEFAULT_PROFILE)\n if (await pathExists(profile.path)) {\n throw new Error('profile already exists')\n }\n await mkdir(profile.path, { recursive: true, mode: 0o700 })\n await ensureHermesApiServerKey(name, profile.configPath)\n return profile\n}\n\nexport async function useHermesProfile(\n name: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<HermesProfile> {\n assertProfileName(name)\n const profile = profileInfo(name, name)\n await mkdir(profile.path, { recursive: true, mode: 0o700 })\n const current = (await readJsonFile<Record<string, unknown>>(paths.stateFile)) ?? {}\n await writeJsonFile(paths.stateFile, { ...current, activeProfile: name } satisfies ProfileState)\n return profile\n}\n\nexport async function renameHermesProfile(oldName: string, newName: string): Promise<HermesProfile> {\n assertMutableProfile(oldName)\n assertMutableProfile(newName)\n const oldProfile = profileInfo(oldName, DEFAULT_PROFILE)\n const newProfile = profileInfo(newName, DEFAULT_PROFILE)\n await rename(oldProfile.path, newProfile.path)\n return newProfile\n}\n\nexport async function deleteHermesProfile(name: string): Promise<void> {\n assertMutableProfile(name)\n await rm(resolveHermesProfileDir(name), { recursive: true, force: true })\n}\n\nasync function getActiveProfile(paths: RuntimePaths): Promise<string> {\n const state = await readJsonFile<Partial<ProfileState>>(paths.stateFile)\n return typeof state?.activeProfile === 'string' && PROFILE_NAME_PATTERN.test(state.activeProfile)\n ? state.activeProfile\n : DEFAULT_PROFILE\n}\n\nfunction profileInfo(name: string, activeProfile: string): HermesProfile {\n return {\n name,\n active: name === activeProfile,\n path: resolveHermesProfileDir(name),\n configPath: resolveHermesConfigPath(name),\n }\n}\n\nfunction assertMutableProfile(name: string): void {\n assertProfileName(name)\n if (name === DEFAULT_PROFILE) {\n throw new Error('default profile cannot be renamed or deleted')\n }\n}\n\nfunction assertProfileName(name: string): void {\n if (!PROFILE_NAME_PATTERN.test(name)) {\n throw new Error('invalid profile name')\n }\n}\n\nasync function pathExists(targetPath: string): Promise<boolean> {\n return await stat(targetPath)\n .then(() => true)\n .catch((error: unknown) => {\n if (isNodeError(error, 'ENOENT')) {\n return false\n }\n throw error\n })\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code\n}\n","import { generateKeyPairSync, randomUUID, sign } from 'node:crypto'\nimport { mkdir, chmod } from 'node:fs/promises'\nimport { z } from 'zod'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { readJsonFile, writeJsonFile } from '../storage/atomic-json.js'\n\nconst linkIdentitySchema = z.object({\n install_id: z.string().min(1),\n link_id: z.string().min(1).nullable().optional(),\n public_key_pem: z.string().min(1),\n private_key_pem: z.string().min(1),\n created_at: z.string().min(1),\n updated_at: z.string().min(1),\n})\n\nexport type LinkIdentity = z.infer<typeof linkIdentitySchema>\n\nexport interface IdentityStatus {\n installId: string\n linkId: string | null\n hasPrivateKey: boolean\n publicKeyPem: string\n}\n\nexport async function loadIdentity(paths: RuntimePaths = resolveRuntimePaths()): Promise<LinkIdentity | null> {\n const value = await readJsonFile<unknown>(paths.identityFile)\n if (value === null) {\n return null\n }\n return linkIdentitySchema.parse(value)\n}\n\nexport async function ensureIdentity(paths: RuntimePaths = resolveRuntimePaths()): Promise<LinkIdentity> {\n const existing = await loadIdentity(paths)\n if (existing) {\n return existing\n }\n\n await mkdir(paths.homeDir, { recursive: true, mode: 0o700 })\n await chmod(paths.homeDir, 0o700).catch(() => undefined)\n\n const { publicKey, privateKey } = generateKeyPairSync('ed25519')\n const now = new Date().toISOString()\n const identity: LinkIdentity = {\n install_id: `install_${randomUUID().replaceAll('-', '')}`,\n link_id: null,\n public_key_pem: publicKey.export({ type: 'spki', format: 'pem' }).toString(),\n private_key_pem: privateKey.export({ type: 'pkcs8', format: 'pem' }).toString(),\n created_at: now,\n updated_at: now,\n }\n await writeJsonFile(paths.identityFile, identity)\n return identity\n}\n\nexport async function saveAssignedLinkId(\n linkId: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<LinkIdentity> {\n const identity = await ensureIdentity(paths)\n const next: LinkIdentity = {\n ...identity,\n link_id: linkId,\n updated_at: new Date().toISOString(),\n }\n await writeJsonFile(paths.identityFile, next)\n return next\n}\n\nexport function signRelayNonce(identity: LinkIdentity, nonce: string): string {\n const signature = sign(null, Buffer.from(nonce, 'utf8'), identity.private_key_pem)\n return signature.toString('base64url')\n}\n\nexport function getIdentityStatus(identity: LinkIdentity): IdentityStatus {\n return {\n installId: identity.install_id,\n linkId: identity.link_id ?? null,\n hasPrivateKey: identity.private_key_pem.trim().length > 0,\n publicKeyPem: identity.public_key_pem,\n }\n}\n\n","import { randomBytes, randomUUID, timingSafeEqual, createHash } from 'node:crypto'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { readJsonFile, writeJsonFile } from '../storage/atomic-json.js'\nimport { LinkHttpError } from '../http/errors.js'\n\nexport interface DeviceRecord {\n id: string\n label: string\n platform: string\n scope: 'admin'\n access_token_hash: string\n access_expires_at: string\n refresh_token_hash: string\n refresh_expires_at: string\n created_at: string\n updated_at: string\n revoked_at: string | null\n}\n\ninterface CredentialStore {\n devices: DeviceRecord[]\n}\n\nexport interface CreatedDeviceSession {\n device: {\n id: string\n device_id: string\n label: string\n platform: string\n scope: 'admin'\n }\n accessToken: {\n token: string\n expiresAt: string\n }\n refreshToken: {\n token: string\n expiresAt: string\n }\n}\n\nconst ACCESS_TOKEN_TTL_MS = 15 * 60 * 1000\nconst REFRESH_TOKEN_TTL_MS = 90 * 24 * 60 * 60 * 1000\n\nexport async function createDeviceSession(\n input: { label: string; platform: string },\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<CreatedDeviceSession> {\n const store = await readCredentialStore(paths)\n const now = new Date()\n const accessToken = randomToken('hpat_')\n const refreshToken = randomToken('hprt_')\n const device: DeviceRecord = {\n id: `dev_${randomUUID().replaceAll('-', '')}`,\n label: input.label,\n platform: input.platform,\n scope: 'admin',\n access_token_hash: sha256(accessToken),\n access_expires_at: new Date(now.getTime() + ACCESS_TOKEN_TTL_MS).toISOString(),\n refresh_token_hash: sha256(refreshToken),\n refresh_expires_at: new Date(now.getTime() + REFRESH_TOKEN_TTL_MS).toISOString(),\n created_at: now.toISOString(),\n updated_at: now.toISOString(),\n revoked_at: null,\n }\n store.devices.push(device)\n await writeCredentialStore(paths, store)\n return formatDeviceSession(device, accessToken, refreshToken)\n}\n\nexport async function authenticateDeviceAccessToken(\n token: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<DeviceRecord | null> {\n const tokenHash = sha256(token)\n const store = await readCredentialStore(paths)\n const device = store.devices.find((item) => safeEqual(item.access_token_hash, tokenHash))\n if (!device || device.revoked_at || Date.parse(device.access_expires_at) <= Date.now()) {\n return null\n }\n return device\n}\n\nexport async function refreshDeviceSession(\n refreshToken: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<CreatedDeviceSession> {\n const tokenHash = sha256(refreshToken)\n const store = await readCredentialStore(paths)\n const device = store.devices.find((item) => safeEqual(item.refresh_token_hash, tokenHash))\n if (!device || device.revoked_at || Date.parse(device.refresh_expires_at) <= Date.now()) {\n throw new LinkHttpError(401, 'refresh_token_invalid', 'Refresh token is invalid or expired')\n }\n\n const now = new Date()\n const nextAccessToken = randomToken('hpat_')\n const nextRefreshToken = randomToken('hprt_')\n device.access_token_hash = sha256(nextAccessToken)\n device.access_expires_at = new Date(now.getTime() + ACCESS_TOKEN_TTL_MS).toISOString()\n device.refresh_token_hash = sha256(nextRefreshToken)\n device.refresh_expires_at = new Date(now.getTime() + REFRESH_TOKEN_TTL_MS).toISOString()\n device.updated_at = now.toISOString()\n await writeCredentialStore(paths, store)\n return formatDeviceSession(device, nextAccessToken, nextRefreshToken)\n}\n\nexport async function revokeDeviceRefreshToken(\n refreshToken: string,\n paths: RuntimePaths = resolveRuntimePaths(),\n): Promise<void> {\n const tokenHash = sha256(refreshToken)\n const store = await readCredentialStore(paths)\n const device = store.devices.find((item) => safeEqual(item.refresh_token_hash, tokenHash))\n if (!device || device.revoked_at) {\n return\n }\n device.revoked_at = new Date().toISOString()\n device.updated_at = device.revoked_at\n await writeCredentialStore(paths, store)\n}\n\nasync function readCredentialStore(paths: RuntimePaths): Promise<CredentialStore> {\n const existing = await readJsonFile<Partial<CredentialStore>>(paths.credentialsFile)\n return {\n devices: Array.isArray(existing?.devices) ? existing.devices.filter(isDeviceRecord) : [],\n }\n}\n\nasync function writeCredentialStore(paths: RuntimePaths, store: CredentialStore): Promise<void> {\n await writeJsonFile(paths.credentialsFile, store)\n}\n\nfunction formatDeviceSession(device: DeviceRecord, accessToken: string, refreshToken: string): CreatedDeviceSession {\n return {\n device: {\n id: device.id,\n device_id: device.id,\n label: device.label,\n platform: device.platform,\n scope: device.scope,\n },\n accessToken: {\n token: accessToken,\n expiresAt: device.access_expires_at,\n },\n refreshToken: {\n token: refreshToken,\n expiresAt: device.refresh_expires_at,\n },\n }\n}\n\nfunction isDeviceRecord(value: unknown): value is DeviceRecord {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as DeviceRecord).id === 'string' &&\n typeof (value as DeviceRecord).access_token_hash === 'string' &&\n typeof (value as DeviceRecord).refresh_token_hash === 'string'\n )\n}\n\nfunction randomToken(prefix: string): string {\n return `${prefix}${randomBytes(24).toString('base64url')}`\n}\n\nfunction sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex')\n}\n\nfunction safeEqual(left: string, right: string): boolean {\n const leftBytes = Buffer.from(left)\n const rightBytes = Buffer.from(right)\n return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes)\n}\n","import { saveAssignedLinkId, signRelayNonce, type LinkIdentity } from '../identity/identity.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\n\nexport interface RelayBootstrapOptions {\n relayBaseUrl: string\n relayBootstrapToken: string\n identity: LinkIdentity\n paths?: RuntimePaths\n fetchImpl?: typeof fetch\n}\n\nexport interface RelayBootstrapResult {\n linkId: string\n reused: boolean\n}\n\ninterface RelayChallengeResponse {\n ok?: unknown\n nonce?: unknown\n expires_at?: unknown\n}\n\ninterface RelayBootstrapResponse {\n ok?: unknown\n link_id?: unknown\n reused?: unknown\n}\n\nexport async function bootstrapRelayLink(options: RelayBootstrapOptions): Promise<RelayBootstrapResult> {\n const fetcher = options.fetchImpl ?? fetch\n const baseUrl = options.relayBaseUrl.replace(/\\/+$/u, '')\n const commonPayload = {\n install_id: options.identity.install_id,\n link_id: options.identity.link_id ?? undefined,\n public_key_pem: options.identity.public_key_pem,\n }\n const challenge = await postJson<RelayChallengeResponse>(\n fetcher,\n `${baseUrl}/api/v1/relay/link/challenge`,\n options.relayBootstrapToken,\n commonPayload,\n )\n if (challenge.ok !== true || typeof challenge.nonce !== 'string') {\n throw new Error('Relay did not return a valid install challenge')\n }\n\n const proof = {\n nonce: challenge.nonce,\n signature: signRelayNonce(options.identity, challenge.nonce),\n }\n const assigned = await postJson<RelayBootstrapResponse>(\n fetcher,\n `${baseUrl}/api/v1/relay/link/bootstrap`,\n options.relayBootstrapToken,\n {\n ...commonPayload,\n proof,\n },\n )\n if (assigned.ok !== true || typeof assigned.link_id !== 'string') {\n throw new Error('Relay did not return a valid link_id')\n }\n\n await saveAssignedLinkId(assigned.link_id, options.paths ?? resolveRuntimePaths())\n return {\n linkId: assigned.link_id,\n reused: assigned.reused === true,\n }\n}\n\nasync function postJson<T>(\n fetcher: typeof fetch,\n url: string,\n token: string,\n body: Record<string, unknown>,\n): Promise<T> {\n const response = await fetcher(url, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n const payload = (await response.json().catch(() => null)) as T | null\n if (!response.ok) {\n const message = readErrorMessage(payload) ?? `Relay request failed with HTTP ${response.status}`\n throw new Error(message)\n }\n if (!payload) {\n throw new Error('Relay returned an empty response')\n }\n return payload\n}\n\nfunction readErrorMessage(payload: unknown): string | null {\n if (typeof payload !== 'object' || payload === null) {\n return null\n }\n const error = (payload as { error?: unknown }).error\n if (typeof error !== 'object' || error === null) {\n return null\n }\n const message = (error as { message?: unknown }).message\n return typeof message === 'string' ? message : null\n}\n","import os from 'node:os'\nimport type { NetworkInterfaceInfo } from 'node:os'\n\nexport interface RouteDiscoveryResult {\n lanIps: string[]\n publicIpv4s: string[]\n publicIpv6s: string[]\n preferredUrls: string[]\n}\n\nconst VIRTUAL_INTERFACE_NAME_PATTERN =\n /(docker|veth|vmnet|vmenet|vbox|virtualbox|vmware|tailscale|zerotier|wireguard|utun|virbr|hyper-v|vethernet|loopback|\\blo\\b|^lo\\d*$|^br-|^bridge\\d+$|^zt|^tun|^tap|awdl|llw|anpi|gif|stf|ipsec|ppp)/iu\n\nconst MAX_LAN_IPS = 4\nconst MAX_PUBLIC_IPV4S = 2\nconst MAX_PUBLIC_IPV6S = 2\n\nexport async function discoverRouteCandidates(options: {\n port: number\n relayBaseUrl: string\n linkId: string\n installId: string\n publicKeyPem: string\n relayBootstrapToken?: string\n fetchImpl?: typeof fetch\n}): Promise<RouteDiscoveryResult> {\n const lanIps = discoverLanIps()\n const publicIps = options.relayBootstrapToken\n ? await observePublicRoute(options).catch(() => ({ publicIpv4s: [], publicIpv6s: [] }))\n : { publicIpv4s: [], publicIpv6s: [] }\n const publicIpv4s = unique(publicIps.publicIpv4s.filter(isUsablePublicIpv4)).slice(0, MAX_PUBLIC_IPV4S)\n const publicIpv6s = unique(publicIps.publicIpv6s.filter(isUsablePublicIpv6)).slice(0, MAX_PUBLIC_IPV6S)\n const preferredUrls = [\n ...lanIps.map((ip) => buildDirectUrl(ip, options.port)),\n ...publicIpv4s.map((ip) => buildDirectUrl(ip, options.port)),\n ...publicIpv6s.map((ip) => buildDirectUrl(ip, options.port)),\n `${options.relayBaseUrl.replace(/\\/+$/u, '')}/api/v1/relay/links/${options.linkId}`,\n ]\n return {\n lanIps,\n publicIpv4s,\n publicIpv6s,\n preferredUrls,\n }\n}\n\nfunction discoverLanIps(): string[] {\n return discoverLanIpsFromInterfaces(os.networkInterfaces())\n}\n\nexport function discoverLanIpsFromInterfaces(interfaces: NodeJS.Dict<NetworkInterfaceInfo[]>): string[] {\n const result = new Set<string>()\n const candidates: Array<{ name: string; address: string }> = []\n for (const [name, items] of Object.entries(interfaces)) {\n if (shouldIgnoreInterface(name)) {\n continue\n }\n for (const item of items ?? []) {\n if (!item.internal && item.address && item.family === 'IPv4' && isUsableLanIpv4(item.address, item.netmask)) {\n candidates.push({ name, address: item.address })\n }\n }\n }\n for (const candidate of candidates.sort(compareLanCandidate)) {\n result.add(candidate.address)\n }\n return [...result].slice(0, MAX_LAN_IPS)\n}\n\nasync function observePublicRoute(options: {\n relayBaseUrl: string\n installId: string\n linkId: string\n publicKeyPem: string\n relayBootstrapToken?: string\n fetchImpl?: typeof fetch\n}): Promise<{ publicIpv4s: string[]; publicIpv6s: string[] }> {\n const fetcher = options.fetchImpl ?? fetch\n const response = await fetcher(`${options.relayBaseUrl.replace(/\\/+$/u, '')}/api/v1/relay/public-route/observe`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${options.relayBootstrapToken}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n install_id: options.installId,\n link_id: options.linkId,\n public_key_pem: options.publicKeyPem,\n }),\n })\n const payload = (await response.json().catch(() => null)) as Record<string, unknown> | null\n const record = typeof payload?.record === 'object' && payload.record !== null\n ? (payload.record as Record<string, unknown>)\n : null\n const observed = typeof payload?.observed === 'object' && payload.observed !== null\n ? (payload.observed as Record<string, unknown>)\n : null\n const values = [\n readIpRecord(record?.ipv4),\n readIpRecord(record?.ipv6),\n typeof observed?.ip === 'string' ? observed.ip : null,\n ].filter((value): value is string => Boolean(value))\n return {\n publicIpv4s: unique(values.filter(isUsablePublicIpv4)),\n publicIpv6s: unique(values.filter(isUsablePublicIpv6)),\n }\n}\n\nfunction readIpRecord(value: unknown): string | null {\n if (typeof value !== 'object' || value === null) {\n return null\n }\n const ip = (value as { ip?: unknown }).ip\n return typeof ip === 'string' && ip.trim() ? ip.trim() : null\n}\n\nfunction buildDirectUrl(ip: string, port: number): string {\n return `http://${ip.includes(':') ? `[${ip}]` : ip}:${port}`\n}\n\nfunction shouldIgnoreInterface(name: string): boolean {\n return !name.trim() || VIRTUAL_INTERFACE_NAME_PATTERN.test(name)\n}\n\nfunction compareLanCandidate(left: { name: string; address: string }, right: { name: string; address: string }): number {\n const priority = interfacePriority(left.name) - interfacePriority(right.name)\n return priority || left.name.localeCompare(right.name) || left.address.localeCompare(right.address)\n}\n\nfunction interfacePriority(name: string): number {\n if (/^(en|eth|wlan|wi-fi|wifi)/iu.test(name)) {\n return 0\n }\n return 1\n}\n\nfunction isUsableLanIpv4(address: string, netmask?: string): boolean {\n return isPrivateIpv4(address) && !isNetworkOrBroadcastIpv4Address(address, netmask)\n}\n\nfunction isUsablePublicIpv4(address: string): boolean {\n return isValidIpv4(address) && !isSpecialIpv4(address)\n}\n\nfunction isUsablePublicIpv6(address: string): boolean {\n const normalized = address.toLowerCase()\n return (\n normalized.includes(':') &&\n !normalized.startsWith('fe80:') &&\n !normalized.startsWith('fc') &&\n !normalized.startsWith('fd') &&\n !normalized.startsWith('ff') &&\n normalized !== '::' &&\n normalized !== '::1'\n )\n}\n\nfunction isPrivateIpv4(address: string): boolean {\n const parts = parseIpv4Segments(address)\n if (!parts) {\n return false\n }\n const [first, second] = parts\n return first === 10 || (first === 172 && second >= 16 && second <= 31) || (first === 192 && second === 168)\n}\n\nfunction isSpecialIpv4(address: string): boolean {\n const parts = parseIpv4Segments(address)\n if (!parts) {\n return true\n }\n const [first, second, third, fourth] = parts\n return (\n first === 0 ||\n first === 10 ||\n first === 127 ||\n first >= 224 ||\n (first === 100 && second >= 64 && second <= 127) ||\n (first === 169 && second === 254) ||\n (first === 172 && second >= 16 && second <= 31) ||\n (first === 192 && second === 168) ||\n (first === 192 && second === 0 && third === 2) ||\n (first === 198 && (second === 18 || second === 19)) ||\n (first === 198 && second === 51 && third === 100) ||\n (first === 203 && second === 0 && third === 113) ||\n (first === 255 && second === 255 && third === 255 && fourth === 255)\n )\n}\n\nfunction isNetworkOrBroadcastIpv4Address(address: string, netmask?: string): boolean {\n const addressParts = parseIpv4Segments(address)\n const netmaskParts = netmask ? parseIpv4Segments(netmask) : null\n if (!addressParts) {\n return true\n }\n if (!netmaskParts) {\n const last = addressParts[3]\n return last === 0 || last === 255\n }\n const addressInt = ipv4SegmentsToInt(addressParts)\n const netmaskInt = ipv4SegmentsToInt(netmaskParts)\n const hostMask = (~netmaskInt) >>> 0\n if (hostMask === 0) {\n return false\n }\n const networkInt = addressInt & netmaskInt\n const broadcastInt = (networkInt | hostMask) >>> 0\n return addressInt === networkInt || addressInt === broadcastInt\n}\n\nfunction isValidIpv4(address: string): boolean {\n return Boolean(parseIpv4Segments(address))\n}\n\nfunction parseIpv4Segments(address: string): [number, number, number, number] | null {\n if (!/^\\d{1,3}(?:\\.\\d{1,3}){3}$/u.test(address)) {\n return null\n }\n const parts = address.split('.').map((part) => Number.parseInt(part, 10))\n if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {\n return null\n }\n return parts as [number, number, number, number]\n}\n\nfunction ipv4SegmentsToInt(parts: [number, number, number, number]): number {\n return (((parts[0] << 24) >>> 0) | (parts[1] << 16) | (parts[2] << 8) | parts[3]) >>> 0\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)]\n}\n","import { loadConfig } from '../config/config.js'\nimport { createDeviceSession } from '../security/devices.js'\nimport { ensureIdentity, loadIdentity, type LinkIdentity } from '../identity/identity.js'\nimport { bootstrapRelayLink } from '../relay/bootstrap.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\nimport { discoverRouteCandidates, type RouteDiscoveryResult } from '../topology/network.js'\nimport { LinkHttpError } from '../http/errors.js'\n\nexport interface PreparedPairing {\n sessionId: string\n code: string\n pairingToken: string\n relayBootstrapToken: string\n relayBaseUrl: string\n displayName: string\n linkId: string\n routes: RouteDiscoveryResult\n qrPayload: Record<string, unknown>\n}\n\nexport async function preparePairing(paths: RuntimePaths = resolveRuntimePaths()): Promise<PreparedPairing> {\n const config = await loadConfig(paths)\n const identity = await ensureIdentity(paths)\n const created = await postServerJson<{\n sessionId: string\n code: string\n pairingToken: string\n relayBootstrapToken: string\n relayBaseUrl: string\n }>(config.serverBaseUrl, '/api/v1/link-pairings', {\n install_id: identity.install_id,\n link_id: identity.link_id ?? undefined,\n display_name: defaultDisplayName(),\n public_key_pem: identity.public_key_pem,\n })\n const relayBaseUrl = created.relayBaseUrl || config.relayBaseUrl\n const assigned = await bootstrapRelayLink({\n relayBaseUrl,\n relayBootstrapToken: created.relayBootstrapToken,\n identity,\n paths,\n })\n const updatedIdentity = (await loadIdentity(paths)) ?? identity\n const routes = await discoverRouteCandidates({\n port: config.port,\n relayBaseUrl,\n relayBootstrapToken: created.relayBootstrapToken,\n linkId: assigned.linkId,\n installId: updatedIdentity.install_id,\n publicKeyPem: updatedIdentity.public_key_pem,\n })\n await patchServerJson(config.serverBaseUrl, `/api/v1/link-pairings/${created.sessionId}/link`, created.pairingToken, {\n install_id: updatedIdentity.install_id,\n link_id: assigned.linkId,\n display_name: defaultDisplayName(),\n lan_ips: routes.lanIps,\n public_ipv4s: routes.publicIpv4s,\n public_ipv6s: routes.publicIpv6s,\n preferred_urls: routes.preferredUrls,\n })\n const qrPayload = {\n kind: 'hermes_link_pairing',\n version: 1,\n link_id: assigned.linkId,\n display_name: defaultDisplayName(),\n session_id: created.sessionId,\n code: created.code,\n preferred_urls: qrPreferredUrls(routes),\n }\n return {\n sessionId: created.sessionId,\n code: created.code,\n pairingToken: created.pairingToken,\n relayBootstrapToken: created.relayBootstrapToken,\n relayBaseUrl,\n displayName: defaultDisplayName(),\n linkId: assigned.linkId,\n routes,\n qrPayload,\n }\n}\n\nexport async function claimPairing(input: {\n sessionId: string\n claimToken: string\n deviceLabel: string\n devicePlatform: string\n paths?: RuntimePaths\n}): Promise<{\n link: { link_id: string; display_name: string }\n device: ReturnType<typeof formatDevice>\n access_token: { token: string; expires_at: string }\n refresh_token: { token: string; expires_at: string }\n}> {\n const paths = input.paths ?? resolveRuntimePaths()\n const [identity, config] = await Promise.all([loadRequiredIdentity(paths), loadConfig(paths)])\n const verified = await postServerJson<{ ok: boolean; linkId: string }>(\n config.serverBaseUrl,\n `/api/v1/link-pairings/${input.sessionId}/claim/verify`,\n {\n claim_token: input.claimToken,\n },\n )\n if (verified.ok !== true || verified.linkId !== identity.link_id) {\n throw new LinkHttpError(409, 'pairing_claim_mismatch', 'Pairing claim does not match this Link')\n }\n const session = await createDeviceSession(\n {\n label: input.deviceLabel || 'HermesPilot App',\n platform: input.devicePlatform || 'unknown',\n },\n paths,\n )\n return {\n link: {\n link_id: identity.link_id,\n display_name: defaultDisplayName(),\n },\n device: formatDevice(session.device),\n access_token: {\n token: session.accessToken.token,\n expires_at: session.accessToken.expiresAt,\n },\n refresh_token: {\n token: session.refreshToken.token,\n expires_at: session.refreshToken.expiresAt,\n },\n }\n}\n\nasync function loadRequiredIdentity(paths: RuntimePaths): Promise<LinkIdentity & { link_id: string }> {\n const identity = await loadIdentity(paths)\n if (!identity?.link_id) {\n throw new LinkHttpError(409, 'link_not_paired', 'Hermes Link is not paired')\n }\n return identity as LinkIdentity & { link_id: string }\n}\n\nasync function postServerJson<T>(serverBaseUrl: string, path: string, body: Record<string, unknown>): Promise<T> {\n const response = await fetch(`${serverBaseUrl.replace(/\\/+$/u, '')}${path}`, {\n method: 'POST',\n headers: {\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n return readJsonResponse<T>(response)\n}\n\nasync function patchServerJson<T>(\n serverBaseUrl: string,\n path: string,\n token: string,\n body: Record<string, unknown>,\n): Promise<T> {\n const response = await fetch(`${serverBaseUrl.replace(/\\/+$/u, '')}${path}`, {\n method: 'PATCH',\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n return readJsonResponse<T>(response)\n}\n\nasync function readJsonResponse<T>(response: Response): Promise<T> {\n const payload = (await response.json().catch(() => null)) as T | null\n if (!response.ok || !payload) {\n const message = readErrorMessage(payload) ?? `HermesPilot Server request failed with HTTP ${response.status}`\n throw new LinkHttpError(response.status, 'server_request_failed', message)\n }\n return payload\n}\n\nfunction readErrorMessage(payload: unknown): string | null {\n if (typeof payload !== 'object' || payload === null) {\n return null\n }\n const error = (payload as { error?: unknown }).error\n if (typeof error !== 'object' || error === null) {\n return null\n }\n const message = (error as { message?: unknown }).message\n return typeof message === 'string' ? message : null\n}\n\nfunction defaultDisplayName(): string {\n return `Hermes Link ${process.platform}`\n}\n\nfunction qrPreferredUrls(routes: RouteDiscoveryResult): string[] {\n return routes.preferredUrls.filter((url) => !url.includes('/api/v1/relay/links/')).slice(0, 1)\n}\n\nfunction formatDevice(device: { id: string; device_id: string; label: string; platform: string; scope: 'admin' }) {\n return {\n id: device.id,\n device_id: device.device_id,\n label: device.label,\n platform: device.platform,\n scope: device.scope,\n }\n}\n","import { createPublicKey, verify, type JsonWebKey as NodeJsonWebKey } from 'node:crypto'\nimport { LinkConfig } from '../config/config.js'\nimport { LinkHttpError } from '../http/errors.js'\n\ninterface JwksResponse {\n keys?: ServerJwk[]\n}\n\ninterface JwtHeader {\n alg?: string\n kid?: string\n typ?: string\n}\n\nexport interface AppConnectClaims {\n token_type: 'hermes_app_connect'\n iss: string\n aud: string\n sub: string\n link_id: string\n exp: number\n iat?: number\n jti?: string\n}\n\ntype ServerJwk = NodeJsonWebKey & { kid?: string }\n\nlet cachedJwks: { expiresAt: number; keys: ServerJwk[] } | null = null\n\nexport async function verifyAppConnectToken(\n token: string,\n options: {\n config: LinkConfig\n linkId: string\n fetchImpl?: typeof fetch\n },\n): Promise<AppConnectClaims> {\n const segments = token.split('.')\n if (segments.length !== 3) {\n throw new LinkHttpError(401, 'app_connect_token_invalid', 'App connect token is malformed')\n }\n const [encodedHeader, encodedPayload, encodedSignature] = segments\n const header = decodeJson<JwtHeader>(encodedHeader)\n const payload = decodeJson<AppConnectClaims>(encodedPayload)\n if (header.alg !== 'ES256' || header.typ !== 'JWT') {\n throw new LinkHttpError(401, 'app_connect_token_invalid', 'App connect token algorithm is unsupported')\n }\n if (\n payload.token_type !== 'hermes_app_connect' ||\n payload.iss !== options.config.appConnectTokenIssuer ||\n payload.aud !== options.config.appConnectTokenAudience ||\n payload.link_id !== options.linkId ||\n !Number.isFinite(payload.exp) ||\n payload.exp <= Math.floor(Date.now() / 1000)\n ) {\n throw new LinkHttpError(401, 'app_connect_token_invalid', 'App connect token claims are invalid')\n }\n\n const jwks = await getJwks(options.config, options.fetchImpl ?? fetch)\n const key = jwks.find((item) => item.kid === header.kid) ?? jwks[0]\n if (!key) {\n throw new LinkHttpError(503, 'app_connect_jwks_unavailable', 'App connect token key is unavailable')\n }\n const publicKey = createPublicKey({ key, format: 'jwk' })\n const ok = verify(\n 'sha256',\n Buffer.from(`${encodedHeader}.${encodedPayload}`),\n { key: publicKey, dsaEncoding: 'ieee-p1363' },\n Buffer.from(base64UrlToBase64(encodedSignature), 'base64'),\n )\n if (!ok) {\n throw new LinkHttpError(401, 'app_connect_token_invalid', 'App connect token signature is invalid')\n }\n return payload\n}\n\nasync function getJwks(config: LinkConfig, fetcher: typeof fetch): Promise<ServerJwk[]> {\n if (cachedJwks && cachedJwks.expiresAt > Date.now()) {\n return cachedJwks.keys\n }\n const response = await fetcher(`${config.serverBaseUrl.replace(/\\/+$/u, '')}/api/v1/app-connect/jwks.json`, {\n headers: { accept: 'application/json' },\n })\n if (!response.ok) {\n throw new LinkHttpError(503, 'app_connect_jwks_unavailable', 'Unable to load app connect JWKS')\n }\n const payload = (await response.json()) as JwksResponse\n const keys = Array.isArray(payload.keys) ? payload.keys : []\n cachedJwks = {\n keys,\n expiresAt: Date.now() + 5 * 60 * 1000,\n }\n return keys\n}\n\nfunction decodeJson<T>(value: string): T {\n return JSON.parse(Buffer.from(base64UrlToBase64(value), 'base64').toString('utf8')) as T\n}\n\nfunction base64UrlToBase64(value: string): string {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/')\n return normalized + '='.repeat((4 - (normalized.length % 4)) % 4)\n}\n","import { appendFile, mkdir, open, readFile, rename, rm, stat } from 'node:fs/promises'\nimport path from 'node:path'\nimport { resolveRuntimePaths, type RuntimePaths } from './paths.js'\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\nexport interface LogEntry {\n ts: string\n level: LogLevel\n message: string\n fields?: Record<string, JsonValue>\n}\n\ntype JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }\n\nexport interface FileLoggerOptions {\n paths?: RuntimePaths\n fileName?: string\n maxFileBytes?: number\n maxFiles?: number\n now?: () => Date\n}\n\nexport interface ReadLogOptions {\n paths?: RuntimePaths\n fileName?: string\n limit?: number\n maxFiles?: number\n maxBytesPerFile?: number\n}\n\nconst DEFAULT_LOG_FILE = 'hermeslink.log'\nconst DEFAULT_MAX_FILE_BYTES = 1024 * 1024\nconst DEFAULT_MAX_FILES = 5\nconst DEFAULT_READ_LIMIT = 200\nconst MAX_READ_LIMIT = 1000\nconst DEFAULT_MAX_BYTES_PER_FILE = 512 * 1024\n\nexport class FileLogger {\n readonly filePath: string\n private readonly paths: RuntimePaths\n private readonly maxFileBytes: number\n private readonly maxFiles: number\n private readonly now: () => Date\n private queue = Promise.resolve()\n\n constructor(options: FileLoggerOptions = {}) {\n this.paths = options.paths ?? resolveRuntimePaths()\n this.filePath = getLinkLogFile(this.paths, options.fileName)\n this.maxFileBytes = Math.max(256, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES))\n this.maxFiles = Math.max(0, Math.floor(options.maxFiles ?? DEFAULT_MAX_FILES))\n this.now = options.now ?? (() => new Date())\n }\n\n debug(message: string, fields?: Record<string, unknown>): Promise<void> {\n return this.write('debug', message, fields)\n }\n\n info(message: string, fields?: Record<string, unknown>): Promise<void> {\n return this.write('info', message, fields)\n }\n\n warn(message: string, fields?: Record<string, unknown>): Promise<void> {\n return this.write('warn', message, fields)\n }\n\n error(message: string, fields?: Record<string, unknown>): Promise<void> {\n return this.write('error', message, fields)\n }\n\n write(level: LogLevel, message: string, fields?: Record<string, unknown>): Promise<void> {\n const entry: LogEntry = {\n ts: this.now().toISOString(),\n level,\n message,\n ...(fields ? { fields: sanitizeFields(fields) } : {}),\n }\n const next = this.queue.then(() => this.appendEntry(entry)).catch(() => undefined)\n this.queue = next\n return next\n }\n\n flush(): Promise<void> {\n return this.queue\n }\n\n private async appendEntry(entry: LogEntry): Promise<void> {\n await mkdir(this.paths.logsDir, { recursive: true, mode: 0o700 })\n const line = `${JSON.stringify(entry)}\\n`\n await this.rotateIfNeeded(Buffer.byteLength(line, 'utf8'))\n await appendFile(this.filePath, line, { mode: 0o600 })\n }\n\n private async rotateIfNeeded(nextBytes: number): Promise<void> {\n const current = await stat(this.filePath).catch(() => null)\n if (!current || current.size === 0 || current.size + nextBytes <= this.maxFileBytes) {\n return\n }\n if (this.maxFiles === 0) {\n await rm(this.filePath, { force: true }).catch(() => undefined)\n return\n }\n await rm(rotatedLogFile(this.filePath, this.maxFiles), { force: true }).catch(() => undefined)\n for (let index = this.maxFiles - 1; index >= 1; index -= 1) {\n await moveIfExists(rotatedLogFile(this.filePath, index), rotatedLogFile(this.filePath, index + 1))\n }\n await moveIfExists(this.filePath, rotatedLogFile(this.filePath, 1))\n }\n}\n\nexport function createFileLogger(options: FileLoggerOptions = {}): FileLogger {\n return new FileLogger(options)\n}\n\nexport function getLinkLogFile(paths: RuntimePaths = resolveRuntimePaths(), fileName = DEFAULT_LOG_FILE): string {\n return path.join(paths.logsDir, fileName)\n}\n\nexport async function readRecentLogEntries(options: ReadLogOptions = {}): Promise<LogEntry[]> {\n const paths = options.paths ?? resolveRuntimePaths()\n const filePath = getLinkLogFile(paths, options.fileName)\n const limit = clampLimit(options.limit)\n const maxFiles = Math.max(0, Math.floor(options.maxFiles ?? DEFAULT_MAX_FILES))\n const maxBytesPerFile = Math.max(1024, Math.floor(options.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE))\n const files = [filePath, ...Array.from({ length: maxFiles }, (_, index) => rotatedLogFile(filePath, index + 1))]\n const entries: LogEntry[] = []\n\n for (const file of files) {\n const raw = await readTail(file, maxBytesPerFile)\n if (!raw) {\n continue\n }\n const lines = raw.split(/\\r?\\n/u).filter(Boolean)\n for (let index = lines.length - 1; index >= 0 && entries.length < limit; index -= 1) {\n const entry = parseLogLine(lines[index])\n if (entry) {\n entries.push(entry)\n }\n }\n if (entries.length >= limit) {\n break\n }\n }\n\n return entries.reverse()\n}\n\nfunction clampLimit(value: number | undefined): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return DEFAULT_READ_LIMIT\n }\n return Math.min(MAX_READ_LIMIT, Math.max(1, Math.floor(value)))\n}\n\nfunction sanitizeFields(fields: Record<string, unknown>): Record<string, JsonValue> {\n return sanitizeObject(fields, 0)\n}\n\nfunction sanitizeValue(value: unknown, depth: number): JsonValue {\n if (value === null || typeof value === 'boolean') {\n return value\n }\n if (typeof value === 'number') {\n return Number.isFinite(value) ? value : null\n }\n if (typeof value === 'string') {\n return value.length > 2000 ? `${value.slice(0, 2000)}...` : value\n }\n if (Array.isArray(value)) {\n if (depth >= 3) {\n return '[array]'\n }\n return value.slice(0, 20).map((item) => sanitizeValue(item, depth + 1))\n }\n if (typeof value === 'object' && value !== null) {\n if (depth >= 3) {\n return '[object]'\n }\n return sanitizeObject(value as Record<string, unknown>, depth + 1)\n }\n return String(value)\n}\n\nfunction sanitizeObject(value: Record<string, unknown>, depth: number): Record<string, JsonValue> {\n const result: Record<string, JsonValue> = {}\n for (const [key, child] of Object.entries(value).slice(0, 50)) {\n if (isSensitiveKey(key)) {\n result[key] = '[redacted]'\n continue\n }\n result[key] = sanitizeValue(child, depth)\n }\n return result\n}\n\nfunction isSensitiveKey(key: string): boolean {\n return /(authorization|cookie|token|secret|password|private[_-]?key|api[_-]?key)/iu.test(key)\n}\n\nfunction parseLogLine(line: string): LogEntry | null {\n try {\n const value = JSON.parse(line) as Partial<LogEntry>\n if (!value || typeof value.ts !== 'string' || !isLogLevel(value.level) || typeof value.message !== 'string') {\n return null\n }\n return {\n ts: value.ts,\n level: value.level,\n message: value.message,\n ...(value.fields && typeof value.fields === 'object' ? { fields: value.fields as Record<string, JsonValue> } : {}),\n }\n } catch {\n return null\n }\n}\n\nfunction isLogLevel(value: unknown): value is LogLevel {\n return value === 'debug' || value === 'info' || value === 'warn' || value === 'error'\n}\n\nasync function readTail(filePath: string, maxBytes: number): Promise<string | null> {\n const info = await stat(filePath).catch(() => null)\n if (!info || info.size <= 0) {\n return null\n }\n if (info.size <= maxBytes) {\n return await readFile(filePath, 'utf8').catch(() => null)\n }\n const handle = await open(filePath, 'r').catch(() => null)\n if (!handle) {\n return null\n }\n try {\n const length = Math.min(info.size, maxBytes)\n const buffer = Buffer.alloc(length)\n await handle.read(buffer, 0, length, info.size - length)\n return buffer.toString('utf8')\n } finally {\n await handle.close()\n }\n}\n\nasync function moveIfExists(from: string, to: string): Promise<void> {\n await rm(to, { force: true }).catch(() => undefined)\n await rename(from, to).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error\n }\n })\n}\n\nfunction rotatedLogFile(filePath: string, index: number): string {\n return `${filePath}.${index}`\n}\n"],"mappings":"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","names":["path","mkdir","readFile","os","path","isNodeError","runId","path","mkdir","rename","rm","os","path","path","os","isNodeError","mkdir","rename","rm","randomUUID","mkdir","mkdir","randomUUID","randomBytes","randomUUID","randomUUID","randomBytes","os","path","readJsonResponse","readErrorMessage","mkdir","open","readFile","rename","rm","stat","path","mkdir","stat","rm","path","readFile","open","rename","readString","loadRequiredIdentity"]}
package/dist/cli/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  loadIdentity,
13
13
  preparePairing,
14
14
  resolveRuntimePaths
15
- } from "../chunk-7M3UZCA7.js";
15
+ } from "../chunk-T35GPRKF.js";
16
16
 
17
17
  // src/cli/index.ts
18
18
  import { Command } from "commander";
@@ -31,6 +31,7 @@ import { mkdir as mkdir2, open, readFile, rm as rm2 } from "fs/promises";
31
31
  import path from "path";
32
32
 
33
33
  // src/daemon/service.ts
34
+ import { createServer } from "http";
34
35
  import { mkdir, rm, writeFile } from "fs/promises";
35
36
 
36
37
  // src/relay/control-client.ts
@@ -166,7 +167,17 @@ async function startLinkService(options = {}) {
166
167
  mode: identity?.link_id ? "paired" : "local-only"
167
168
  });
168
169
  const app = await createApp({ paths, logger, onPairingClaimed: options.onPairingClaimed });
169
- const server = app.listen(config.port);
170
+ const server = createServer(app.callback());
171
+ try {
172
+ await listenServer(server, config.port);
173
+ } catch (error) {
174
+ await logger.error("service_start_failed", {
175
+ port: config.port,
176
+ error: error instanceof Error ? error.message : String(error)
177
+ });
178
+ await logger.flush();
179
+ throw error;
180
+ }
170
181
  server.on("error", (error) => {
171
182
  void logger.error("service_error", { error: error.message });
172
183
  });
@@ -224,6 +235,25 @@ async function closeServer(server) {
224
235
  });
225
236
  });
226
237
  }
238
+ async function listenServer(server, port) {
239
+ await new Promise((resolve, reject) => {
240
+ const cleanup = () => {
241
+ server.off("error", onError);
242
+ server.off("listening", onListening);
243
+ };
244
+ const onError = (error) => {
245
+ cleanup();
246
+ reject(error);
247
+ };
248
+ const onListening = () => {
249
+ cleanup();
250
+ resolve();
251
+ };
252
+ server.once("error", onError);
253
+ server.once("listening", onListening);
254
+ server.listen(port);
255
+ });
256
+ }
227
257
 
228
258
  // src/daemon/process.ts
229
259
  async function startDaemonProcess(paths = resolveRuntimePaths()) {
@@ -555,6 +585,7 @@ var messages = {
555
585
  "error.relayLinkInvalid": "Relay did not return a valid link_id.",
556
586
  "error.relayEmpty": "Relay returned an empty response.",
557
587
  "error.serverHttp": "HermesPilot Server request failed with HTTP {status}.",
588
+ "error.portInUse": "Local port {port} is already in use. Stop the existing Hermes Link process, then run `hermeslink pair` again.",
558
589
  "error.pairingRequires": "Pairing needs HermesPilot Server and Relay, but this command could not start a complete pairing session.",
559
590
  "error.pairingRequires.detail": "The deployed services may be healthy, but the installed Link package must call Server for a short-lived relay bootstrap token before it can request a link_id."
560
591
  },
@@ -614,6 +645,7 @@ var messages = {
614
645
  "error.relayLinkInvalid": "Relay \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684 link_id\u3002",
615
646
  "error.relayEmpty": "Relay \u8FD4\u56DE\u4E86\u7A7A\u54CD\u5E94\u3002",
616
647
  "error.serverHttp": "HermesPilot Server \u8BF7\u6C42\u5931\u8D25\uFF0CHTTP \u72B6\u6001\u7801\uFF1A{status}\u3002",
648
+ "error.portInUse": "\u672C\u5730\u7AEF\u53E3 {port} \u5DF2\u88AB\u5360\u7528\u3002\u8BF7\u5148\u505C\u6B62\u5DF2\u6709\u7684 Hermes Link \u8FDB\u7A0B\uFF0C\u7136\u540E\u91CD\u65B0\u8FD0\u884C `hermeslink pair`\u3002",
617
649
  "error.pairingRequires": "\u914D\u5BF9\u9700\u8981 HermesPilot Server \u548C Relay\uFF0C\u4F46\u5F53\u524D\u547D\u4EE4\u6CA1\u6709\u80FD\u542F\u52A8\u5B8C\u6574\u914D\u5BF9\u4F1A\u8BDD\u3002",
618
650
  "error.pairingRequires.detail": "\u4E91\u7AEF\u670D\u52A1\u53EF\u4EE5\u662F\u5DF2\u90E8\u7F72\u4E14\u5065\u5EB7\u7684\uFF1B\u672C\u673A Link \u4ECD\u5FC5\u987B\u5148\u5411 Server \u7533\u8BF7\u77ED\u671F relay bootstrap token\uFF0C\u624D\u80FD\u518D\u5411 Relay \u7533\u8BF7 link_id\u3002"
619
651
  }
@@ -668,6 +700,10 @@ function translateKnownError(message, language) {
668
700
  if (message === "Relay returned an empty response") {
669
701
  return translate(language, "error.relayEmpty");
670
702
  }
703
+ const portInUse = /^listen EADDRINUSE: address already in use .*:(?<port>\d+)$/u.exec(message);
704
+ if (portInUse?.groups?.port) {
705
+ return translate(language, "error.portInUse", { port: portInUse.groups.port });
706
+ }
671
707
  const serverHttp = /^HermesPilot Server request failed with HTTP (?<status>\d+)$/u.exec(message);
672
708
  if (serverHttp?.groups?.status) {
673
709
  return translate(language, "error.serverHttp", { status: serverHttp.groups.status });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/index.ts","../../src/autostart/autostart.ts","../../src/daemon/process.ts","../../src/daemon/service.ts","../../src/relay/control-client.ts","../../src/i18n.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander'\nimport qrcode from 'qrcode-terminal'\nimport { LINK_COMMAND, LINK_VERSION } from '../constants.js'\nimport { enableAutostart, disableAutostart, getAutostartStatus } from '../autostart/autostart.js'\nimport { loadConfig } from '../config/config.js'\nimport { getDaemonStatus, startDaemonProcess, stopDaemonProcess, daemonLogFile } from '../daemon/process.js'\nimport { startLinkService } from '../daemon/service.js'\nimport { ensureHermesApiServerKey } from '../hermes/config.js'\nimport { ensureIdentity, getIdentityStatus, loadIdentity } from '../identity/identity.js'\nimport { detectSystemLanguage, localizeErrorMessage, resolveLanguage, translate } from '../i18n.js'\nimport { preparePairing } from '../pairing/pairing.js'\nimport { getLinkLogFile } from '../runtime/logger.js'\nimport { resolveRuntimePaths } from '../runtime/paths.js'\n\nconst program = new Command()\nconst helpLanguage = detectSystemLanguage()\nconst helpText = translate.bind(null, helpLanguage)\n\nprogram\n .name(LINK_COMMAND)\n .description(helpText('program.description'))\n .version(LINK_VERSION, '-v, --version', helpText('program.version'))\n\nprogram\n .command('status')\n .option('--json', helpText('status.json'))\n .description(helpText('status.description'))\n .action(async (options: { json?: boolean }) => {\n const paths = resolveRuntimePaths()\n const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)])\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const payload = {\n version: LINK_VERSION,\n runtimeHome: paths.homeDir,\n paired: Boolean(identity?.link_id),\n mode: identity?.link_id ? 'paired' : 'local-only',\n port: config.port,\n identity: identity ? getIdentityStatus(identity) : null,\n relay: {\n configured: Boolean(config.relayBaseUrl),\n connected: false,\n },\n }\n if (options.json) {\n console.log(JSON.stringify(payload, null, 2))\n return\n }\n console.log(`Hermes Link ${payload.version}`)\n console.log(t('status.runtime', { value: payload.runtimeHome }))\n console.log(t('status.mode', { value: payload.mode }))\n console.log(t('status.port', { value: payload.port }))\n console.log(t('status.linkId', { value: payload.identity?.linkId ?? t('status.notPaired') }))\n })\n\nprogram\n .command('start')\n .description(helpText('start.description'))\n .action(async () => {\n const [config, status] = await Promise.all([loadConfig(), getDaemonStatus()])\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n if (status.running && status.pid) {\n console.log(t('start.alreadyRunning', { pid: status.pid }))\n return\n }\n const nextStatus = await startDaemonProcess()\n console.log(t('start.backgroundStarted', { pid: nextStatus.pid ?? 'unknown' }))\n })\n\nprogram\n .command('stop')\n .description(helpText('stop.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const before = await getDaemonStatus()\n if (!before.running) {\n console.log(t('stop.notRunning'))\n return\n }\n await stopDaemonProcess()\n console.log(t('stop.stopped'))\n })\n\nprogram\n .command('restart')\n .description(helpText('restart.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n await stopDaemonProcess()\n const status = await startDaemonProcess()\n console.log(t('start.backgroundStarted', { pid: status.pid ?? 'unknown' }))\n })\n\nprogram\n .command('daemon')\n .option('--foreground', 'run in foreground')\n .description(helpText('daemon.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const service = await startLinkService({ writePidFile: true })\n console.log(t('daemon.foreground'))\n await waitForShutdown(async () => {\n await service.close()\n })\n })\n\nprogram\n .command('pair')\n .description(helpText('pair.description'))\n .action(async () => {\n const paths = resolveRuntimePaths()\n const config = await loadConfig(paths)\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n console.log(t('pair.preparing'))\n console.log(t('pair.server', { url: config.serverBaseUrl }))\n console.log(t('pair.relay', { url: config.relayBaseUrl }))\n await ensureIdentity(paths)\n const prepared = await preparePairing(paths)\n const pairingClaimed = createDeferred()\n const service = await startLinkService({\n paths,\n onPairingClaimed: () => pairingClaimed.resolve(),\n })\n const qrValue = JSON.stringify(prepared.qrPayload)\n console.log(t('pair.linkId', { value: prepared.linkId }))\n console.log(t('pair.code', { value: prepared.code }))\n console.log(t('pair.localApi', { port: config.port }))\n console.log(t('pair.scan'))\n qrcode.generate(qrValue, { small: true })\n console.log(t('pair.expires'))\n const result = await waitForPairingOrShutdown(pairingClaimed.promise)\n await service.close()\n if (result === 'claimed') {\n console.log(t('pair.claimed'))\n try {\n const autostart = await enableAutostart()\n if (autostart.supported && autostart.enabled) {\n console.log(t('autostart.enabled', { method: autostart.method, path: autostart.filePath ?? '' }))\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n console.log(t('pair.autostartFailed', { message }))\n }\n const status = await startDaemonProcess(paths)\n console.log(t('start.backgroundStarted', { pid: status.pid ?? 'unknown' }))\n }\n })\n\nconst autostart = program.command('autostart').description(helpText('autostart.description'))\n\nautostart\n .command('on')\n .description(helpText('autostart.on.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const status = await enableAutostart()\n if (!status.supported) {\n console.log(t('autostart.unsupported'))\n return\n }\n console.log(t('autostart.enabled', { method: status.method, path: status.filePath ?? '' }))\n })\n\nautostart\n .command('off')\n .description(helpText('autostart.off.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n await disableAutostart()\n console.log(t('autostart.disabled'))\n })\n\nautostart\n .command('status')\n .description(helpText('autostart.status.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const status = await getAutostartStatus()\n if (!status.supported) {\n console.log(t('autostart.unsupported'))\n return\n }\n console.log(\n t(status.enabled ? 'autostart.status.enabled' : 'autostart.status.disabled', {\n method: status.method,\n path: status.filePath ?? '',\n }),\n )\n })\n\nprogram\n .command('logs')\n .description(helpText('logs.description'))\n .action(async () => {\n const paths = resolveRuntimePaths()\n const config = await loadConfig(paths)\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n console.log(t('logs.servicePath', { path: getLinkLogFile(paths) }))\n console.log(t('logs.daemonPath', { path: daemonLogFile(paths) }))\n })\n\nprogram\n .command('doctor')\n .description(helpText('doctor.description'))\n .action(async () => {\n const [identity, config] = await Promise.all([ensureIdentity(), loadConfig()])\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const hermesConfig = await ensureHermesApiServerKey()\n console.log(t('doctor.identityOk'))\n console.log(t('doctor.installId', { value: identity.install_id }))\n console.log(t('doctor.linkId', { value: identity.link_id ?? t('doctor.notAssigned') }))\n if (hermesConfig.notice) {\n console.log(hermesConfig.notice)\n if (hermesConfig.backupPath) {\n console.log(`Hermes config backup: ${hermesConfig.backupPath}`)\n }\n }\n })\n\nprogram.parseAsync(process.argv).catch(async (error) => {\n const language = await loadCliLanguage().catch(() => detectSystemLanguage())\n console.error(localizeErrorMessage(error, language))\n process.exitCode = 1\n})\n\nasync function loadCliLanguage() {\n const config = await loadConfig()\n return resolveLanguage(config.language)\n}\n\nasync function waitForShutdown(cleanup: () => Promise<void>): Promise<void> {\n await new Promise<void>((resolve) => {\n const stop = () => resolve()\n process.once('SIGINT', stop)\n process.once('SIGTERM', stop)\n })\n await cleanup()\n}\n\nasync function waitForPairingOrShutdown(pairingClaimed: Promise<void>): Promise<'claimed' | 'shutdown'> {\n let stop: (() => void) | null = null\n const shutdown = new Promise<'shutdown'>((resolve) => {\n stop = () => resolve('shutdown')\n process.once('SIGINT', stop)\n process.once('SIGTERM', stop)\n })\n const result = await Promise.race([pairingClaimed.then(() => 'claimed' as const), shutdown])\n if (stop) {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n }\n return result\n}\n\nfunction createDeferred(): { promise: Promise<void>; resolve: () => void } {\n let resolve!: () => void\n const promise = new Promise<void>((innerResolve) => {\n resolve = innerResolve\n })\n return { promise, resolve }\n}\n","import { execFile } from 'node:child_process'\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { promisify } from 'node:util'\nimport { currentCliScriptPath } from '../daemon/process.js'\n\nconst execFileAsync = promisify(execFile)\nconst MACOS_LABEL = 'com.hermespilot.link'\n\nexport interface AutostartStatus {\n supported: boolean\n enabled: boolean\n method: 'launchd' | 'systemd-user' | 'xdg-autostart' | 'windows-startup' | 'unsupported'\n filePath: string | null\n}\n\nexport async function enableAutostart(): Promise<AutostartStatus> {\n const definition = await resolveAutostartDefinition()\n if (!definition) {\n return unsupportedStatus()\n }\n await mkdir(path.dirname(definition.filePath), { recursive: true, mode: 0o700 })\n await writeFile(definition.filePath, definition.content, { mode: 0o600 })\n if (definition.method === 'systemd-user') {\n await execFileAsync('systemctl', ['--user', 'enable', path.basename(definition.filePath)]).catch(async () => {\n await rm(definition.filePath, { force: true }).catch(() => undefined)\n const fallback = xdgAutostartDefinition()\n await mkdir(path.dirname(fallback.filePath), { recursive: true, mode: 0o700 })\n await writeFile(fallback.filePath, fallback.content, { mode: 0o600 })\n })\n }\n return await getAutostartStatus()\n}\n\nexport async function disableAutostart(): Promise<AutostartStatus> {\n const definitions = await allAutostartDefinitions()\n for (const definition of definitions) {\n if (definition.method === 'systemd-user') {\n await execFileAsync('systemctl', ['--user', 'disable', path.basename(definition.filePath)]).catch(() => undefined)\n }\n await rm(definition.filePath, { force: true }).catch(() => undefined)\n }\n return await getAutostartStatus()\n}\n\nexport async function getAutostartStatus(): Promise<AutostartStatus> {\n const definitions = await allAutostartDefinitions()\n if (definitions.length === 0) {\n return unsupportedStatus()\n }\n for (const definition of definitions) {\n const content = await readFile(definition.filePath, 'utf8').catch(() => null)\n if (content !== null) {\n return {\n supported: true,\n enabled: true,\n method: definition.method,\n filePath: definition.filePath,\n }\n }\n }\n const primary = definitions[0]\n return {\n supported: true,\n enabled: false,\n method: primary.method,\n filePath: primary.filePath,\n }\n}\n\nasync function resolveAutostartDefinition(): Promise<AutostartDefinition | null> {\n if (process.platform === 'darwin') {\n return launchdDefinition()\n }\n if (process.platform === 'win32') {\n return windowsStartupDefinition()\n }\n if (process.platform === 'linux') {\n return await hasSystemctlUser() ? systemdUserDefinition() : xdgAutostartDefinition()\n }\n return null\n}\n\nasync function allAutostartDefinitions(): Promise<AutostartDefinition[]> {\n if (process.platform === 'darwin') {\n return [launchdDefinition()]\n }\n if (process.platform === 'win32') {\n return [windowsStartupDefinition()]\n }\n if (process.platform === 'linux') {\n return [systemdUserDefinition(), xdgAutostartDefinition()]\n }\n return []\n}\n\nasync function hasSystemctlUser(): Promise<boolean> {\n try {\n await execFileAsync('systemctl', ['--user', 'show-environment'])\n return true\n } catch {\n return false\n }\n}\n\nfunction launchdDefinition(): AutostartDefinition {\n const filePath = path.join(os.homedir(), 'Library', 'LaunchAgents', `${MACOS_LABEL}.plist`)\n return {\n method: 'launchd',\n filePath,\n content: `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${MACOS_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${xmlEscape(process.execPath)}</string>\n <string>${xmlEscape(currentCliScriptPath())}</string>\n <string>daemon</string>\n <string>--foreground</string>\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <false/>\n <key>StandardOutPath</key>\n <string>${xmlEscape(path.join(os.homedir(), '.hermeslink', 'logs', 'daemon.log'))}</string>\n <key>StandardErrorPath</key>\n <string>${xmlEscape(path.join(os.homedir(), '.hermeslink', 'logs', 'daemon.log'))}</string>\n</dict>\n</plist>\n`,\n }\n}\n\nfunction systemdUserDefinition(): AutostartDefinition {\n const filePath = path.join(os.homedir(), '.config', 'systemd', 'user', 'hermeslink.service')\n return {\n method: 'systemd-user',\n filePath,\n content: `[Unit]\nDescription=Hermes Link\nAfter=network-online.target\n\n[Service]\nType=simple\nExecStart=${systemdQuote(process.execPath)} ${systemdQuote(currentCliScriptPath())} daemon --foreground\nRestart=no\n\n[Install]\nWantedBy=default.target\n`,\n }\n}\n\nfunction xdgAutostartDefinition(): AutostartDefinition {\n const filePath = path.join(os.homedir(), '.config', 'autostart', 'hermeslink.desktop')\n return {\n method: 'xdg-autostart',\n filePath,\n content: `[Desktop Entry]\nType=Application\nName=Hermes Link\nExec=${desktopQuote(process.execPath)} ${desktopQuote(currentCliScriptPath())} daemon --foreground\nTerminal=false\nX-GNOME-Autostart-enabled=true\n`,\n }\n}\n\nfunction windowsStartupDefinition(): AutostartDefinition {\n const appData = process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming')\n const filePath = path.join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', 'HermesLink.cmd')\n return {\n method: 'windows-startup',\n filePath,\n content: `@echo off\\r\\nstart \"\" /min \"${process.execPath}\" \"${currentCliScriptPath()}\" daemon --foreground\\r\\n`,\n }\n}\n\nfunction unsupportedStatus(): AutostartStatus {\n return {\n supported: false,\n enabled: false,\n method: 'unsupported',\n filePath: null,\n }\n}\n\nfunction xmlEscape(value: string): string {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&apos;')\n}\n\nfunction systemdQuote(value: string): string {\n return `\"${value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')}\"`\n}\n\nfunction desktopQuote(value: string): string {\n return `\"${value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')}\"`\n}\n\ninterface AutostartDefinition {\n method: AutostartStatus['method']\n filePath: string\n content: string\n}\n","import { spawn } from 'node:child_process'\nimport { mkdir, open, readFile, rm } from 'node:fs/promises'\nimport path from 'node:path'\nimport { pidFilePath } from './service.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\n\nexport interface DaemonStatus {\n running: boolean\n pid: number | null\n pidFile: string\n logFile: string\n}\n\nexport async function startDaemonProcess(paths: RuntimePaths = resolveRuntimePaths()): Promise<DaemonStatus> {\n const status = await getDaemonStatus(paths)\n if (status.running) {\n return status\n }\n await mkdir(paths.logsDir, { recursive: true, mode: 0o700 })\n await mkdir(paths.runDir, { recursive: true, mode: 0o700 })\n const log = await open(daemonLogFile(paths), 'a', 0o600)\n const scriptPath = currentCliScriptPath()\n const child = spawn(process.execPath, [scriptPath, 'daemon', '--foreground'], {\n detached: true,\n stdio: ['ignore', log.fd, log.fd],\n env: process.env,\n })\n child.unref()\n await log.close()\n for (let index = 0; index < 12; index += 1) {\n await wait(250)\n const next = await getDaemonStatus(paths)\n if (next.running) {\n return next\n }\n }\n return await getDaemonStatus(paths)\n}\n\nexport async function stopDaemonProcess(paths: RuntimePaths = resolveRuntimePaths()): Promise<DaemonStatus> {\n const status = await getDaemonStatus(paths)\n if (!status.running || !status.pid) {\n return status\n }\n try {\n process.kill(status.pid, 'SIGTERM')\n } catch {\n await rm(pidFilePath(paths), { force: true }).catch(() => undefined)\n return await getDaemonStatus(paths)\n }\n for (let index = 0; index < 20; index += 1) {\n await wait(250)\n if (!isProcessAlive(status.pid)) {\n break\n }\n }\n if (!isProcessAlive(status.pid)) {\n await rm(pidFilePath(paths), { force: true }).catch(() => undefined)\n }\n return await getDaemonStatus(paths)\n}\n\nexport async function getDaemonStatus(paths: RuntimePaths = resolveRuntimePaths()): Promise<DaemonStatus> {\n const pidFile = pidFilePath(paths)\n const pid = await readPid(pidFile)\n if (pid && !isProcessAlive(pid)) {\n await rm(pidFile, { force: true }).catch(() => undefined)\n return {\n running: false,\n pid: null,\n pidFile,\n logFile: daemonLogFile(paths),\n }\n }\n return {\n running: Boolean(pid),\n pid,\n pidFile,\n logFile: daemonLogFile(paths),\n }\n}\n\nexport function daemonLogFile(paths: RuntimePaths = resolveRuntimePaths()): string {\n return path.join(paths.logsDir, 'daemon.log')\n}\n\nexport function currentCliScriptPath(): string {\n return process.argv[1]\n}\n\nasync function readPid(filePath: string): Promise<number | null> {\n const raw = await readFile(filePath, 'utf8').catch(() => null)\n if (!raw) {\n return null\n }\n const pid = Number.parseInt(raw.trim(), 10)\n return Number.isInteger(pid) && pid > 0 ? pid : null\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch {\n return false\n }\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","import type { Server } from 'node:http'\nimport { mkdir, rm, writeFile } from 'node:fs/promises'\nimport { createApp, type CreateAppOptions } from '../http/app.js'\nimport { loadConfig } from '../config/config.js'\nimport { loadIdentity } from '../identity/identity.js'\nimport { connectRelayControl, type RelayControlClient } from '../relay/control-client.js'\nimport { createFileLogger } from '../runtime/logger.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\n\nexport interface LinkService {\n close(): Promise<void>\n}\n\nexport interface StartLinkServiceOptions extends CreateAppOptions {\n paths?: RuntimePaths\n writePidFile?: boolean\n relayMaxReconnectAttempts?: number\n}\n\nexport async function startLinkService(options: StartLinkServiceOptions = {}): Promise<LinkService> {\n const paths = options.paths ?? resolveRuntimePaths()\n const logger = createFileLogger({ paths })\n const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)])\n await logger.info('service_starting', {\n port: config.port,\n mode: identity?.link_id ? 'paired' : 'local-only',\n })\n const app = await createApp({ paths, logger, onPairingClaimed: options.onPairingClaimed })\n const server = app.listen(config.port)\n server.on('error', (error) => {\n void logger.error('service_error', { error: error.message })\n })\n void logger.info('service_started', {\n port: config.port,\n link_id: identity?.link_id ?? null,\n })\n let relay: RelayControlClient | null = null\n if (identity?.link_id) {\n relay = connectRelayControl({\n relayBaseUrl: config.relayBaseUrl,\n linkId: identity.link_id,\n localPort: config.port,\n maxReconnectAttempts: options.relayMaxReconnectAttempts ?? 5,\n backoffBaseMs: 1_000,\n backoffMaxMs: 30_000,\n onStatus: (status) => {\n void logger.info('relay_status', status)\n },\n })\n } else {\n void logger.info('relay_skipped', { reason: 'link_not_paired' })\n }\n if (options.writePidFile) {\n await writePidFile(paths)\n }\n return {\n async close() {\n relay?.close()\n await closeServer(server)\n await logger.info('service_stopped')\n await logger.flush()\n if (options.writePidFile) {\n await rm(pidFilePath(paths), { force: true }).catch(() => undefined)\n }\n },\n }\n}\n\nexport function pidFilePath(paths: RuntimePaths = resolveRuntimePaths()): string {\n return `${paths.runDir}/hermeslink.pid`\n}\n\nasync function writePidFile(paths: RuntimePaths): Promise<void> {\n await mkdir(paths.runDir, { recursive: true, mode: 0o700 })\n await writeFile(pidFilePath(paths), `${process.pid}\\n`, { mode: 0o600 })\n}\n\nasync function closeServer(server: Server): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error)\n return\n }\n resolve()\n })\n })\n}\n","import WebSocket from 'ws'\nimport { LINK_VERSION } from '../constants.js'\n\ninterface RelayRequestFrame {\n type: 'http.request'\n id: string\n method: string\n path: string\n headers?: Record<string, string>\n bodyBase64?: string | null\n}\n\ninterface RelayCancelFrame {\n type: 'http.cancel'\n id: string\n}\n\ntype RelayFrame = RelayRequestFrame | RelayCancelFrame\n\nexport interface RelayControlClient {\n close(): void\n}\n\nexport function connectRelayControl(options: {\n relayBaseUrl: string\n linkId: string\n localPort: number\n maxReconnectAttempts?: number\n backoffBaseMs?: number\n backoffMaxMs?: number\n onStatus?: (status: { state: 'connecting' | 'connected' | 'disconnected' | 'retrying' | 'failed'; attempt: number; message?: string }) => void\n}): RelayControlClient {\n const wsUrl = new URL(`${options.relayBaseUrl.replace(/\\/+$/u, '')}/api/v1/relay/link/connect`)\n wsUrl.protocol = wsUrl.protocol === 'https:' ? 'wss:' : 'ws:'\n wsUrl.searchParams.set('link_id', options.linkId)\n\n const maxReconnectAttempts = options.maxReconnectAttempts ?? 5\n const backoffBaseMs = options.backoffBaseMs ?? 1_000\n const backoffMaxMs = options.backoffMaxMs ?? 30_000\n let reconnectAttempts = 0\n let closedByUser = false\n let socket: WebSocket | null = null\n let retryTimer: ReturnType<typeof setTimeout> | null = null\n let abortControllers = new Map<string, AbortController>()\n\n const connect = () => {\n options.onStatus?.({ state: 'connecting', attempt: reconnectAttempts })\n socket = new WebSocket(wsUrl, {\n headers: {\n 'x-hermes-link-version': LINK_VERSION,\n },\n })\n socket.on('open', () => {\n reconnectAttempts = 0\n options.onStatus?.({ state: 'connected', attempt: reconnectAttempts })\n })\n socket.on('message', (raw) => {\n if (!socket || (typeof raw !== 'string' && !Buffer.isBuffer(raw))) {\n return\n }\n void handleFrame(socket, String(raw), options.localPort, abortControllers).catch((error) => {\n const message = error instanceof Error ? error.message : 'Relay request failed'\n socket?.send(JSON.stringify({ type: 'http.error', id: 'unknown', status: 502, message }))\n })\n })\n socket.on('error', (error) => {\n const message = error instanceof Error ? error.message : 'Relay websocket error'\n options.onStatus?.({ state: 'disconnected', attempt: reconnectAttempts, message })\n })\n socket.on('close', () => {\n abortAll(abortControllers)\n abortControllers = new Map<string, AbortController>()\n if (closedByUser) {\n options.onStatus?.({ state: 'disconnected', attempt: reconnectAttempts })\n return\n }\n if (reconnectAttempts >= maxReconnectAttempts) {\n options.onStatus?.({ state: 'failed', attempt: reconnectAttempts, message: 'Relay reconnect attempts exhausted' })\n return\n }\n reconnectAttempts += 1\n const delay = computeBackoffMs(reconnectAttempts, backoffBaseMs, backoffMaxMs)\n options.onStatus?.({ state: 'retrying', attempt: reconnectAttempts, message: `Retrying in ${delay}ms` })\n retryTimer = setTimeout(connect, delay)\n retryTimer.unref?.()\n })\n }\n\n connect()\n\n return {\n close() {\n closedByUser = true\n if (retryTimer) {\n clearTimeout(retryTimer)\n }\n abortAll(abortControllers)\n socket?.close()\n },\n }\n}\n\nfunction abortAll(abortControllers: Map<string, AbortController>): void {\n for (const controller of abortControllers.values()) {\n controller.abort()\n }\n abortControllers.clear()\n}\n\nfunction computeBackoffMs(attempt: number, baseMs: number, maxMs: number): number {\n const exponential = Math.min(maxMs, baseMs * 2 ** Math.max(0, attempt - 1))\n const jitter = Math.floor(Math.random() * Math.min(1_000, exponential * 0.2))\n return exponential + jitter\n}\n\nasync function handleFrame(\n socket: WebSocket,\n raw: string,\n localPort: number,\n abortControllers: Map<string, AbortController>,\n): Promise<void> {\n const frame = JSON.parse(raw) as RelayFrame\n if (frame.type === 'http.cancel') {\n abortControllers.get(frame.id)?.abort()\n abortControllers.delete(frame.id)\n return\n }\n if (frame.type !== 'http.request') {\n return\n }\n const abortController = new AbortController()\n abortControllers.set(frame.id, abortController)\n try {\n const response = await fetch(`http://127.0.0.1:${localPort}${frame.path}`, {\n method: frame.method,\n headers: frame.headers ?? {},\n body: frame.bodyBase64 ? Buffer.from(frame.bodyBase64, 'base64') : undefined,\n signal: abortController.signal,\n })\n const headers = Object.fromEntries(response.headers.entries())\n const contentType = response.headers.get('content-type') ?? ''\n if (response.body && contentType.includes('text/event-stream')) {\n socket.send(JSON.stringify({ type: 'http.stream.start', id: frame.id, status: response.status, headers }))\n const reader = response.body.getReader()\n while (true) {\n const next = await reader.read()\n if (next.done) {\n break\n }\n socket.send(JSON.stringify({ type: 'http.stream.chunk', id: frame.id, bodyBase64: Buffer.from(next.value).toString('base64') }))\n }\n socket.send(JSON.stringify({ type: 'http.stream.end', id: frame.id }))\n return\n }\n const body = Buffer.from(await response.arrayBuffer()).toString('base64')\n socket.send(JSON.stringify({ type: 'http.response', id: frame.id, status: response.status, headers, bodyBase64: body }))\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Relay request failed'\n socket.send(JSON.stringify({ type: 'http.error', id: frame.id, status: 502, message }))\n } finally {\n abortControllers.delete(frame.id)\n }\n}\n","export type SupportedLanguage = 'zh-CN' | 'en'\nexport type ConfiguredLanguage = SupportedLanguage | 'auto'\n\nconst messages = {\n en: {\n 'program.description': 'Hermes Link companion service',\n 'program.version': 'print Hermes Link version',\n 'status.description': 'Show local Hermes Link status',\n 'status.json': 'print machine-readable status',\n 'status.runtime': 'Runtime: {value}',\n 'status.mode': 'Mode: {value}',\n 'status.port': 'Local port: {value}',\n 'status.linkId': 'Link ID: {value}',\n 'status.notPaired': 'not paired',\n 'start.description': 'Start Hermes Link daemon',\n 'start.backgroundStarted': 'Hermes Link is running in the background. PID: {pid}',\n 'start.alreadyRunning': 'Hermes Link is already running. PID: {pid}',\n 'start.notPaired': 'Hermes Link is not paired yet. Starting in local-only maintenance mode.',\n 'start.notPaired.detail':\n 'Relay, Server polling, and LAN entrypoints stay disabled until you run `hermeslink pair`.',\n 'start.listening': 'Hermes Link API listening on http://127.0.0.1:{port}',\n 'start.relayConnecting': 'Relay control connecting for {linkId}',\n 'stop.description': 'Stop the background Hermes Link daemon',\n 'stop.stopped': 'Hermes Link stopped.',\n 'stop.notRunning': 'Hermes Link is not running.',\n 'restart.description': 'Restart the background Hermes Link daemon',\n 'daemon.description': 'Run Hermes Link in the foreground',\n 'daemon.foreground': 'Hermes Link foreground daemon is running. Press Ctrl+C to stop.',\n 'logs.description': 'Show Hermes Link log paths',\n 'logs.servicePath': 'Service log: {path}',\n 'logs.daemonPath': 'Daemon stdout/stderr log: {path}',\n 'autostart.description': 'Manage boot autostart',\n 'autostart.on.description': 'Enable boot autostart',\n 'autostart.off.description': 'Disable boot autostart',\n 'autostart.status.description': 'Show boot autostart status',\n 'autostart.enabled': 'Boot autostart enabled via {method}: {path}',\n 'autostart.disabled': 'Boot autostart disabled.',\n 'autostart.status.enabled': 'Boot autostart: enabled via {method}: {path}',\n 'autostart.status.disabled': 'Boot autostart: disabled. Method: {method}. File: {path}',\n 'autostart.unsupported': 'Boot autostart is not supported on this platform yet.',\n 'pair.description': 'Create a Hermes Link pairing session',\n 'pair.preparing': 'Preparing pairing session through HermesPilot Server and Relay...',\n 'pair.server': 'Server: {url}',\n 'pair.relay': 'Relay: {url}',\n 'pair.linkId': 'Hermes Link ID: {value}',\n 'pair.code': 'Pairing code: {value}',\n 'pair.localApi': 'Local API: http://127.0.0.1:{port}',\n 'pair.scan': 'Scan this QR code with the HermesPilot App:',\n 'pair.expires': 'Pairing expires in 10 minutes. Press Ctrl+C to stop Hermes Link.',\n 'pair.claimed': 'Pairing succeeded. Starting Hermes Link in the background...',\n 'pair.autostartFailed': 'Pairing succeeded, but boot autostart could not be enabled: {message}',\n 'doctor.description': 'Run local diagnostics',\n 'doctor.identityOk': 'Runtime identity: OK',\n 'doctor.installId': 'Install ID: {value}',\n 'doctor.linkId': 'Link ID: {value}',\n 'doctor.notAssigned': 'not assigned',\n 'error.relayPublicKeyMismatch':\n 'Relay rejected the pairing request because the Server-issued bootstrap token does not match this Link public key. Make sure Server and Relay are deployed with the same bootstrap key configuration, then run `hermeslink pair` again.',\n 'error.relayChallengeInvalid': 'Relay did not return a valid install challenge.',\n 'error.relayLinkInvalid': 'Relay did not return a valid link_id.',\n 'error.relayEmpty': 'Relay returned an empty response.',\n 'error.serverHttp': 'HermesPilot Server request failed with HTTP {status}.',\n 'error.pairingRequires':\n 'Pairing needs HermesPilot Server and Relay, but this command could not start a complete pairing session.',\n 'error.pairingRequires.detail':\n 'The deployed services may be healthy, but the installed Link package must call Server for a short-lived relay bootstrap token before it can request a link_id.',\n },\n 'zh-CN': {\n 'program.description': 'Hermes Link 本地伴随服务',\n 'program.version': '输出 Hermes Link 版本号',\n 'status.description': '查看本机 Hermes Link 状态',\n 'status.json': '输出机器可读的状态 JSON',\n 'status.runtime': '运行目录:{value}',\n 'status.mode': '模式:{value}',\n 'status.port': '本地端口:{value}',\n 'status.linkId': 'Link ID:{value}',\n 'status.notPaired': '尚未配对',\n 'start.description': '启动 Hermes Link 服务',\n 'start.backgroundStarted': 'Hermes Link 已在后台运行。PID:{pid}',\n 'start.alreadyRunning': 'Hermes Link 已经在运行。PID:{pid}',\n 'start.notPaired': 'Hermes Link 还没有配对,将以本地维护模式启动。',\n 'start.notPaired.detail': '在你运行 `hermeslink pair` 前,Relay、Server 轮询和局域网入口都会保持关闭。',\n 'start.listening': 'Hermes Link API 正在监听 http://127.0.0.1:{port}',\n 'start.relayConnecting': '正在为 {linkId} 连接 Relay 控制通道',\n 'stop.description': '停止后台 Hermes Link 服务',\n 'stop.stopped': 'Hermes Link 已停止。',\n 'stop.notRunning': 'Hermes Link 没有在运行。',\n 'restart.description': '重启后台 Hermes Link 服务',\n 'daemon.description': '以前台方式运行 Hermes Link',\n 'daemon.foreground': 'Hermes Link 前台服务正在运行。按 Ctrl+C 停止。',\n 'logs.description': '显示 Hermes Link 日志路径',\n 'logs.servicePath': '服务日志:{path}',\n 'logs.daemonPath': 'Daemon 标准输出/错误日志:{path}',\n 'autostart.description': '管理开机自启',\n 'autostart.on.description': '启用开机自启',\n 'autostart.off.description': '关闭开机自启',\n 'autostart.status.description': '查看开机自启状态',\n 'autostart.enabled': '已启用开机自启,方式:{method},文件:{path}',\n 'autostart.disabled': '已关闭开机自启。',\n 'autostart.status.enabled': '开机自启:已启用,方式:{method},文件:{path}',\n 'autostart.status.disabled': '开机自启:未启用。方式:{method},文件:{path}',\n 'autostart.unsupported': '当前平台暂不支持开机自启。',\n 'pair.description': '创建 Hermes Link 配对会话',\n 'pair.preparing': '正在通过 HermesPilot Server 和 Relay 创建配对会话...',\n 'pair.server': 'Server:{url}',\n 'pair.relay': 'Relay:{url}',\n 'pair.linkId': 'Hermes Link ID:{value}',\n 'pair.code': '配对码:{value}',\n 'pair.localApi': '本地 API:http://127.0.0.1:{port}',\n 'pair.scan': '请使用 HermesPilot App 扫描这个二维码:',\n 'pair.expires': '配对会话 10 分钟后过期。按 Ctrl+C 停止 Hermes Link。',\n 'pair.claimed': '配对已成功。正在把 Hermes Link 切换到后台运行...',\n 'pair.autostartFailed': '配对已成功,但启用开机自启失败:{message}',\n 'doctor.description': '运行本机诊断',\n 'doctor.identityOk': '运行身份:正常',\n 'doctor.installId': 'Install ID:{value}',\n 'doctor.linkId': 'Link ID:{value}',\n 'doctor.notAssigned': '尚未分配',\n 'error.relayPublicKeyMismatch':\n 'Relay 拒绝了配对请求:Server 签发的 bootstrap token 与本机 Link 公钥不匹配。请确认 Server 和 Relay 使用同一套 bootstrap key 配置,然后重新运行 `hermeslink pair`。',\n 'error.relayChallengeInvalid': 'Relay 没有返回有效的安装挑战。',\n 'error.relayLinkInvalid': 'Relay 没有返回有效的 link_id。',\n 'error.relayEmpty': 'Relay 返回了空响应。',\n 'error.serverHttp': 'HermesPilot Server 请求失败,HTTP 状态码:{status}。',\n 'error.pairingRequires': '配对需要 HermesPilot Server 和 Relay,但当前命令没有能启动完整配对会话。',\n 'error.pairingRequires.detail':\n '云端服务可以是已部署且健康的;本机 Link 仍必须先向 Server 申请短期 relay bootstrap token,才能再向 Relay 申请 link_id。',\n },\n} satisfies Record<SupportedLanguage, Record<string, string>>\n\nexport type MessageKey = keyof (typeof messages)['en']\n\nexport function detectSystemLanguage(env: NodeJS.ProcessEnv = process.env): SupportedLanguage {\n const candidates = [\n env.HERMESLINK_LANG,\n env.HERMESLINK_LANGUAGE,\n env.LC_ALL,\n env.LC_MESSAGES,\n env.LANG,\n env.LANGUAGE?.split(':')[0],\n Intl.DateTimeFormat().resolvedOptions().locale,\n ]\n for (const candidate of candidates) {\n const language = parseLanguage(candidate)\n if (language) {\n return language\n }\n }\n return 'en'\n}\n\nexport function resolveLanguage(setting?: ConfiguredLanguage | string | null): SupportedLanguage {\n const configured = parseLanguage(setting)\n if (configured) {\n return configured\n }\n return detectSystemLanguage()\n}\n\nexport function translate(\n language: SupportedLanguage,\n key: MessageKey,\n values: Record<string, string | number> = {},\n): string {\n const template = messages[language][key] ?? messages.en[key]\n return template.replace(/\\{(\\w+)\\}/gu, (_, name: string) => String(values[name] ?? ''))\n}\n\nexport function localizeErrorMessage(error: unknown, language: SupportedLanguage): string {\n const message = error instanceof Error ? error.message : String(error)\n if (language === 'en') {\n return message\n }\n const mapped = translateKnownError(message, language)\n return mapped ?? message\n}\n\nfunction translateKnownError(message: string, language: SupportedLanguage): string | null {\n if (message === 'Relay bootstrap token does not match public key') {\n return translate(language, 'error.relayPublicKeyMismatch')\n }\n if (message === 'Relay did not return a valid install challenge') {\n return translate(language, 'error.relayChallengeInvalid')\n }\n if (message === 'Relay did not return a valid link_id') {\n return translate(language, 'error.relayLinkInvalid')\n }\n if (message === 'Relay returned an empty response') {\n return translate(language, 'error.relayEmpty')\n }\n const serverHttp = /^HermesPilot Server request failed with HTTP (?<status>\\d+)$/u.exec(message)\n if (serverHttp?.groups?.status) {\n return translate(language, 'error.serverHttp', { status: serverHttp.groups.status })\n }\n if (message.includes('Pairing requires HermesPilot Server and Relay')) {\n return [translate(language, 'error.pairingRequires'), translate(language, 'error.pairingRequires.detail')].join('\\n')\n }\n return null\n}\n\nfunction parseLanguage(value: string | null | undefined): SupportedLanguage | null {\n const normalized = value?.trim().replace('_', '-').toLowerCase()\n if (!normalized || normalized === 'auto' || normalized === 'c' || normalized === 'posix') {\n return null\n }\n if (normalized.startsWith('zh')) {\n return 'zh-CN'\n }\n if (normalized.startsWith('en')) {\n return 'en'\n }\n return null\n}\n"],"mappings":"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","names":["mkdir","readFile","rm","writeFile","path","mkdir","rm","mkdir","rm","mkdir","path","writeFile","rm","readFile","autostart"]}
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/autostart/autostart.ts","../../src/daemon/process.ts","../../src/daemon/service.ts","../../src/relay/control-client.ts","../../src/i18n.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander'\nimport qrcode from 'qrcode-terminal'\nimport { LINK_COMMAND, LINK_VERSION } from '../constants.js'\nimport { enableAutostart, disableAutostart, getAutostartStatus } from '../autostart/autostart.js'\nimport { loadConfig } from '../config/config.js'\nimport { getDaemonStatus, startDaemonProcess, stopDaemonProcess, daemonLogFile } from '../daemon/process.js'\nimport { startLinkService } from '../daemon/service.js'\nimport { ensureHermesApiServerKey } from '../hermes/config.js'\nimport { ensureIdentity, getIdentityStatus, loadIdentity } from '../identity/identity.js'\nimport { detectSystemLanguage, localizeErrorMessage, resolveLanguage, translate } from '../i18n.js'\nimport { preparePairing } from '../pairing/pairing.js'\nimport { getLinkLogFile } from '../runtime/logger.js'\nimport { resolveRuntimePaths } from '../runtime/paths.js'\n\nconst program = new Command()\nconst helpLanguage = detectSystemLanguage()\nconst helpText = translate.bind(null, helpLanguage)\n\nprogram\n .name(LINK_COMMAND)\n .description(helpText('program.description'))\n .version(LINK_VERSION, '-v, --version', helpText('program.version'))\n\nprogram\n .command('status')\n .option('--json', helpText('status.json'))\n .description(helpText('status.description'))\n .action(async (options: { json?: boolean }) => {\n const paths = resolveRuntimePaths()\n const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)])\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const payload = {\n version: LINK_VERSION,\n runtimeHome: paths.homeDir,\n paired: Boolean(identity?.link_id),\n mode: identity?.link_id ? 'paired' : 'local-only',\n port: config.port,\n identity: identity ? getIdentityStatus(identity) : null,\n relay: {\n configured: Boolean(config.relayBaseUrl),\n connected: false,\n },\n }\n if (options.json) {\n console.log(JSON.stringify(payload, null, 2))\n return\n }\n console.log(`Hermes Link ${payload.version}`)\n console.log(t('status.runtime', { value: payload.runtimeHome }))\n console.log(t('status.mode', { value: payload.mode }))\n console.log(t('status.port', { value: payload.port }))\n console.log(t('status.linkId', { value: payload.identity?.linkId ?? t('status.notPaired') }))\n })\n\nprogram\n .command('start')\n .description(helpText('start.description'))\n .action(async () => {\n const [config, status] = await Promise.all([loadConfig(), getDaemonStatus()])\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n if (status.running && status.pid) {\n console.log(t('start.alreadyRunning', { pid: status.pid }))\n return\n }\n const nextStatus = await startDaemonProcess()\n console.log(t('start.backgroundStarted', { pid: nextStatus.pid ?? 'unknown' }))\n })\n\nprogram\n .command('stop')\n .description(helpText('stop.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const before = await getDaemonStatus()\n if (!before.running) {\n console.log(t('stop.notRunning'))\n return\n }\n await stopDaemonProcess()\n console.log(t('stop.stopped'))\n })\n\nprogram\n .command('restart')\n .description(helpText('restart.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n await stopDaemonProcess()\n const status = await startDaemonProcess()\n console.log(t('start.backgroundStarted', { pid: status.pid ?? 'unknown' }))\n })\n\nprogram\n .command('daemon')\n .option('--foreground', 'run in foreground')\n .description(helpText('daemon.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const service = await startLinkService({ writePidFile: true })\n console.log(t('daemon.foreground'))\n await waitForShutdown(async () => {\n await service.close()\n })\n })\n\nprogram\n .command('pair')\n .description(helpText('pair.description'))\n .action(async () => {\n const paths = resolveRuntimePaths()\n const config = await loadConfig(paths)\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n console.log(t('pair.preparing'))\n console.log(t('pair.server', { url: config.serverBaseUrl }))\n console.log(t('pair.relay', { url: config.relayBaseUrl }))\n await ensureIdentity(paths)\n const prepared = await preparePairing(paths)\n const pairingClaimed = createDeferred()\n const service = await startLinkService({\n paths,\n onPairingClaimed: () => pairingClaimed.resolve(),\n })\n const qrValue = JSON.stringify(prepared.qrPayload)\n console.log(t('pair.linkId', { value: prepared.linkId }))\n console.log(t('pair.code', { value: prepared.code }))\n console.log(t('pair.localApi', { port: config.port }))\n console.log(t('pair.scan'))\n qrcode.generate(qrValue, { small: true })\n console.log(t('pair.expires'))\n const result = await waitForPairingOrShutdown(pairingClaimed.promise)\n await service.close()\n if (result === 'claimed') {\n console.log(t('pair.claimed'))\n try {\n const autostart = await enableAutostart()\n if (autostart.supported && autostart.enabled) {\n console.log(t('autostart.enabled', { method: autostart.method, path: autostart.filePath ?? '' }))\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n console.log(t('pair.autostartFailed', { message }))\n }\n const status = await startDaemonProcess(paths)\n console.log(t('start.backgroundStarted', { pid: status.pid ?? 'unknown' }))\n }\n })\n\nconst autostart = program.command('autostart').description(helpText('autostart.description'))\n\nautostart\n .command('on')\n .description(helpText('autostart.on.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const status = await enableAutostart()\n if (!status.supported) {\n console.log(t('autostart.unsupported'))\n return\n }\n console.log(t('autostart.enabled', { method: status.method, path: status.filePath ?? '' }))\n })\n\nautostart\n .command('off')\n .description(helpText('autostart.off.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n await disableAutostart()\n console.log(t('autostart.disabled'))\n })\n\nautostart\n .command('status')\n .description(helpText('autostart.status.description'))\n .action(async () => {\n const config = await loadConfig()\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const status = await getAutostartStatus()\n if (!status.supported) {\n console.log(t('autostart.unsupported'))\n return\n }\n console.log(\n t(status.enabled ? 'autostart.status.enabled' : 'autostart.status.disabled', {\n method: status.method,\n path: status.filePath ?? '',\n }),\n )\n })\n\nprogram\n .command('logs')\n .description(helpText('logs.description'))\n .action(async () => {\n const paths = resolveRuntimePaths()\n const config = await loadConfig(paths)\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n console.log(t('logs.servicePath', { path: getLinkLogFile(paths) }))\n console.log(t('logs.daemonPath', { path: daemonLogFile(paths) }))\n })\n\nprogram\n .command('doctor')\n .description(helpText('doctor.description'))\n .action(async () => {\n const [identity, config] = await Promise.all([ensureIdentity(), loadConfig()])\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n const hermesConfig = await ensureHermesApiServerKey()\n console.log(t('doctor.identityOk'))\n console.log(t('doctor.installId', { value: identity.install_id }))\n console.log(t('doctor.linkId', { value: identity.link_id ?? t('doctor.notAssigned') }))\n if (hermesConfig.notice) {\n console.log(hermesConfig.notice)\n if (hermesConfig.backupPath) {\n console.log(`Hermes config backup: ${hermesConfig.backupPath}`)\n }\n }\n })\n\nprogram.parseAsync(process.argv).catch(async (error) => {\n const language = await loadCliLanguage().catch(() => detectSystemLanguage())\n console.error(localizeErrorMessage(error, language))\n process.exitCode = 1\n})\n\nasync function loadCliLanguage() {\n const config = await loadConfig()\n return resolveLanguage(config.language)\n}\n\nasync function waitForShutdown(cleanup: () => Promise<void>): Promise<void> {\n await new Promise<void>((resolve) => {\n const stop = () => resolve()\n process.once('SIGINT', stop)\n process.once('SIGTERM', stop)\n })\n await cleanup()\n}\n\nasync function waitForPairingOrShutdown(pairingClaimed: Promise<void>): Promise<'claimed' | 'shutdown'> {\n let stop: (() => void) | null = null\n const shutdown = new Promise<'shutdown'>((resolve) => {\n stop = () => resolve('shutdown')\n process.once('SIGINT', stop)\n process.once('SIGTERM', stop)\n })\n const result = await Promise.race([pairingClaimed.then(() => 'claimed' as const), shutdown])\n if (stop) {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n }\n return result\n}\n\nfunction createDeferred(): { promise: Promise<void>; resolve: () => void } {\n let resolve!: () => void\n const promise = new Promise<void>((innerResolve) => {\n resolve = innerResolve\n })\n return { promise, resolve }\n}\n","import { execFile } from 'node:child_process'\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { promisify } from 'node:util'\nimport { currentCliScriptPath } from '../daemon/process.js'\n\nconst execFileAsync = promisify(execFile)\nconst MACOS_LABEL = 'com.hermespilot.link'\n\nexport interface AutostartStatus {\n supported: boolean\n enabled: boolean\n method: 'launchd' | 'systemd-user' | 'xdg-autostart' | 'windows-startup' | 'unsupported'\n filePath: string | null\n}\n\nexport async function enableAutostart(): Promise<AutostartStatus> {\n const definition = await resolveAutostartDefinition()\n if (!definition) {\n return unsupportedStatus()\n }\n await mkdir(path.dirname(definition.filePath), { recursive: true, mode: 0o700 })\n await writeFile(definition.filePath, definition.content, { mode: 0o600 })\n if (definition.method === 'systemd-user') {\n await execFileAsync('systemctl', ['--user', 'enable', path.basename(definition.filePath)]).catch(async () => {\n await rm(definition.filePath, { force: true }).catch(() => undefined)\n const fallback = xdgAutostartDefinition()\n await mkdir(path.dirname(fallback.filePath), { recursive: true, mode: 0o700 })\n await writeFile(fallback.filePath, fallback.content, { mode: 0o600 })\n })\n }\n return await getAutostartStatus()\n}\n\nexport async function disableAutostart(): Promise<AutostartStatus> {\n const definitions = await allAutostartDefinitions()\n for (const definition of definitions) {\n if (definition.method === 'systemd-user') {\n await execFileAsync('systemctl', ['--user', 'disable', path.basename(definition.filePath)]).catch(() => undefined)\n }\n await rm(definition.filePath, { force: true }).catch(() => undefined)\n }\n return await getAutostartStatus()\n}\n\nexport async function getAutostartStatus(): Promise<AutostartStatus> {\n const definitions = await allAutostartDefinitions()\n if (definitions.length === 0) {\n return unsupportedStatus()\n }\n for (const definition of definitions) {\n const content = await readFile(definition.filePath, 'utf8').catch(() => null)\n if (content !== null) {\n return {\n supported: true,\n enabled: true,\n method: definition.method,\n filePath: definition.filePath,\n }\n }\n }\n const primary = definitions[0]\n return {\n supported: true,\n enabled: false,\n method: primary.method,\n filePath: primary.filePath,\n }\n}\n\nasync function resolveAutostartDefinition(): Promise<AutostartDefinition | null> {\n if (process.platform === 'darwin') {\n return launchdDefinition()\n }\n if (process.platform === 'win32') {\n return windowsStartupDefinition()\n }\n if (process.platform === 'linux') {\n return await hasSystemctlUser() ? systemdUserDefinition() : xdgAutostartDefinition()\n }\n return null\n}\n\nasync function allAutostartDefinitions(): Promise<AutostartDefinition[]> {\n if (process.platform === 'darwin') {\n return [launchdDefinition()]\n }\n if (process.platform === 'win32') {\n return [windowsStartupDefinition()]\n }\n if (process.platform === 'linux') {\n return [systemdUserDefinition(), xdgAutostartDefinition()]\n }\n return []\n}\n\nasync function hasSystemctlUser(): Promise<boolean> {\n try {\n await execFileAsync('systemctl', ['--user', 'show-environment'])\n return true\n } catch {\n return false\n }\n}\n\nfunction launchdDefinition(): AutostartDefinition {\n const filePath = path.join(os.homedir(), 'Library', 'LaunchAgents', `${MACOS_LABEL}.plist`)\n return {\n method: 'launchd',\n filePath,\n content: `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${MACOS_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${xmlEscape(process.execPath)}</string>\n <string>${xmlEscape(currentCliScriptPath())}</string>\n <string>daemon</string>\n <string>--foreground</string>\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <false/>\n <key>StandardOutPath</key>\n <string>${xmlEscape(path.join(os.homedir(), '.hermeslink', 'logs', 'daemon.log'))}</string>\n <key>StandardErrorPath</key>\n <string>${xmlEscape(path.join(os.homedir(), '.hermeslink', 'logs', 'daemon.log'))}</string>\n</dict>\n</plist>\n`,\n }\n}\n\nfunction systemdUserDefinition(): AutostartDefinition {\n const filePath = path.join(os.homedir(), '.config', 'systemd', 'user', 'hermeslink.service')\n return {\n method: 'systemd-user',\n filePath,\n content: `[Unit]\nDescription=Hermes Link\nAfter=network-online.target\n\n[Service]\nType=simple\nExecStart=${systemdQuote(process.execPath)} ${systemdQuote(currentCliScriptPath())} daemon --foreground\nRestart=no\n\n[Install]\nWantedBy=default.target\n`,\n }\n}\n\nfunction xdgAutostartDefinition(): AutostartDefinition {\n const filePath = path.join(os.homedir(), '.config', 'autostart', 'hermeslink.desktop')\n return {\n method: 'xdg-autostart',\n filePath,\n content: `[Desktop Entry]\nType=Application\nName=Hermes Link\nExec=${desktopQuote(process.execPath)} ${desktopQuote(currentCliScriptPath())} daemon --foreground\nTerminal=false\nX-GNOME-Autostart-enabled=true\n`,\n }\n}\n\nfunction windowsStartupDefinition(): AutostartDefinition {\n const appData = process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming')\n const filePath = path.join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', 'HermesLink.cmd')\n return {\n method: 'windows-startup',\n filePath,\n content: `@echo off\\r\\nstart \"\" /min \"${process.execPath}\" \"${currentCliScriptPath()}\" daemon --foreground\\r\\n`,\n }\n}\n\nfunction unsupportedStatus(): AutostartStatus {\n return {\n supported: false,\n enabled: false,\n method: 'unsupported',\n filePath: null,\n }\n}\n\nfunction xmlEscape(value: string): string {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&apos;')\n}\n\nfunction systemdQuote(value: string): string {\n return `\"${value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')}\"`\n}\n\nfunction desktopQuote(value: string): string {\n return `\"${value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')}\"`\n}\n\ninterface AutostartDefinition {\n method: AutostartStatus['method']\n filePath: string\n content: string\n}\n","import { spawn } from 'node:child_process'\nimport { mkdir, open, readFile, rm } from 'node:fs/promises'\nimport path from 'node:path'\nimport { pidFilePath } from './service.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\n\nexport interface DaemonStatus {\n running: boolean\n pid: number | null\n pidFile: string\n logFile: string\n}\n\nexport async function startDaemonProcess(paths: RuntimePaths = resolveRuntimePaths()): Promise<DaemonStatus> {\n const status = await getDaemonStatus(paths)\n if (status.running) {\n return status\n }\n await mkdir(paths.logsDir, { recursive: true, mode: 0o700 })\n await mkdir(paths.runDir, { recursive: true, mode: 0o700 })\n const log = await open(daemonLogFile(paths), 'a', 0o600)\n const scriptPath = currentCliScriptPath()\n const child = spawn(process.execPath, [scriptPath, 'daemon', '--foreground'], {\n detached: true,\n stdio: ['ignore', log.fd, log.fd],\n env: process.env,\n })\n child.unref()\n await log.close()\n for (let index = 0; index < 12; index += 1) {\n await wait(250)\n const next = await getDaemonStatus(paths)\n if (next.running) {\n return next\n }\n }\n return await getDaemonStatus(paths)\n}\n\nexport async function stopDaemonProcess(paths: RuntimePaths = resolveRuntimePaths()): Promise<DaemonStatus> {\n const status = await getDaemonStatus(paths)\n if (!status.running || !status.pid) {\n return status\n }\n try {\n process.kill(status.pid, 'SIGTERM')\n } catch {\n await rm(pidFilePath(paths), { force: true }).catch(() => undefined)\n return await getDaemonStatus(paths)\n }\n for (let index = 0; index < 20; index += 1) {\n await wait(250)\n if (!isProcessAlive(status.pid)) {\n break\n }\n }\n if (!isProcessAlive(status.pid)) {\n await rm(pidFilePath(paths), { force: true }).catch(() => undefined)\n }\n return await getDaemonStatus(paths)\n}\n\nexport async function getDaemonStatus(paths: RuntimePaths = resolveRuntimePaths()): Promise<DaemonStatus> {\n const pidFile = pidFilePath(paths)\n const pid = await readPid(pidFile)\n if (pid && !isProcessAlive(pid)) {\n await rm(pidFile, { force: true }).catch(() => undefined)\n return {\n running: false,\n pid: null,\n pidFile,\n logFile: daemonLogFile(paths),\n }\n }\n return {\n running: Boolean(pid),\n pid,\n pidFile,\n logFile: daemonLogFile(paths),\n }\n}\n\nexport function daemonLogFile(paths: RuntimePaths = resolveRuntimePaths()): string {\n return path.join(paths.logsDir, 'daemon.log')\n}\n\nexport function currentCliScriptPath(): string {\n return process.argv[1]\n}\n\nasync function readPid(filePath: string): Promise<number | null> {\n const raw = await readFile(filePath, 'utf8').catch(() => null)\n if (!raw) {\n return null\n }\n const pid = Number.parseInt(raw.trim(), 10)\n return Number.isInteger(pid) && pid > 0 ? pid : null\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch {\n return false\n }\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","import { createServer, type Server } from 'node:http'\nimport { mkdir, rm, writeFile } from 'node:fs/promises'\nimport { createApp, type CreateAppOptions } from '../http/app.js'\nimport { loadConfig } from '../config/config.js'\nimport { loadIdentity } from '../identity/identity.js'\nimport { connectRelayControl, type RelayControlClient } from '../relay/control-client.js'\nimport { createFileLogger } from '../runtime/logger.js'\nimport { resolveRuntimePaths, type RuntimePaths } from '../runtime/paths.js'\n\nexport interface LinkService {\n close(): Promise<void>\n}\n\nexport interface StartLinkServiceOptions extends CreateAppOptions {\n paths?: RuntimePaths\n writePidFile?: boolean\n relayMaxReconnectAttempts?: number\n}\n\nexport async function startLinkService(options: StartLinkServiceOptions = {}): Promise<LinkService> {\n const paths = options.paths ?? resolveRuntimePaths()\n const logger = createFileLogger({ paths })\n const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)])\n await logger.info('service_starting', {\n port: config.port,\n mode: identity?.link_id ? 'paired' : 'local-only',\n })\n const app = await createApp({ paths, logger, onPairingClaimed: options.onPairingClaimed })\n const server = createServer(app.callback())\n try {\n await listenServer(server, config.port)\n } catch (error) {\n await logger.error('service_start_failed', {\n port: config.port,\n error: error instanceof Error ? error.message : String(error),\n })\n await logger.flush()\n throw error\n }\n server.on('error', (error) => {\n void logger.error('service_error', { error: error.message })\n })\n void logger.info('service_started', {\n port: config.port,\n link_id: identity?.link_id ?? null,\n })\n let relay: RelayControlClient | null = null\n if (identity?.link_id) {\n relay = connectRelayControl({\n relayBaseUrl: config.relayBaseUrl,\n linkId: identity.link_id,\n localPort: config.port,\n maxReconnectAttempts: options.relayMaxReconnectAttempts ?? 5,\n backoffBaseMs: 1_000,\n backoffMaxMs: 30_000,\n onStatus: (status) => {\n void logger.info('relay_status', status)\n },\n })\n } else {\n void logger.info('relay_skipped', { reason: 'link_not_paired' })\n }\n if (options.writePidFile) {\n await writePidFile(paths)\n }\n return {\n async close() {\n relay?.close()\n await closeServer(server)\n await logger.info('service_stopped')\n await logger.flush()\n if (options.writePidFile) {\n await rm(pidFilePath(paths), { force: true }).catch(() => undefined)\n }\n },\n }\n}\n\nexport function pidFilePath(paths: RuntimePaths = resolveRuntimePaths()): string {\n return `${paths.runDir}/hermeslink.pid`\n}\n\nasync function writePidFile(paths: RuntimePaths): Promise<void> {\n await mkdir(paths.runDir, { recursive: true, mode: 0o700 })\n await writeFile(pidFilePath(paths), `${process.pid}\\n`, { mode: 0o600 })\n}\n\nasync function closeServer(server: Server): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error)\n return\n }\n resolve()\n })\n })\n}\n\nasync function listenServer(server: Server, port: number): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const cleanup = () => {\n server.off('error', onError)\n server.off('listening', onListening)\n }\n const onError = (error: Error) => {\n cleanup()\n reject(error)\n }\n const onListening = () => {\n cleanup()\n resolve()\n }\n\n server.once('error', onError)\n server.once('listening', onListening)\n server.listen(port)\n })\n}\n","import WebSocket from 'ws'\nimport { LINK_VERSION } from '../constants.js'\n\ninterface RelayRequestFrame {\n type: 'http.request'\n id: string\n method: string\n path: string\n headers?: Record<string, string>\n bodyBase64?: string | null\n}\n\ninterface RelayCancelFrame {\n type: 'http.cancel'\n id: string\n}\n\ntype RelayFrame = RelayRequestFrame | RelayCancelFrame\n\nexport interface RelayControlClient {\n close(): void\n}\n\nexport function connectRelayControl(options: {\n relayBaseUrl: string\n linkId: string\n localPort: number\n maxReconnectAttempts?: number\n backoffBaseMs?: number\n backoffMaxMs?: number\n onStatus?: (status: { state: 'connecting' | 'connected' | 'disconnected' | 'retrying' | 'failed'; attempt: number; message?: string }) => void\n}): RelayControlClient {\n const wsUrl = new URL(`${options.relayBaseUrl.replace(/\\/+$/u, '')}/api/v1/relay/link/connect`)\n wsUrl.protocol = wsUrl.protocol === 'https:' ? 'wss:' : 'ws:'\n wsUrl.searchParams.set('link_id', options.linkId)\n\n const maxReconnectAttempts = options.maxReconnectAttempts ?? 5\n const backoffBaseMs = options.backoffBaseMs ?? 1_000\n const backoffMaxMs = options.backoffMaxMs ?? 30_000\n let reconnectAttempts = 0\n let closedByUser = false\n let socket: WebSocket | null = null\n let retryTimer: ReturnType<typeof setTimeout> | null = null\n let abortControllers = new Map<string, AbortController>()\n\n const connect = () => {\n options.onStatus?.({ state: 'connecting', attempt: reconnectAttempts })\n socket = new WebSocket(wsUrl, {\n headers: {\n 'x-hermes-link-version': LINK_VERSION,\n },\n })\n socket.on('open', () => {\n reconnectAttempts = 0\n options.onStatus?.({ state: 'connected', attempt: reconnectAttempts })\n })\n socket.on('message', (raw) => {\n if (!socket || (typeof raw !== 'string' && !Buffer.isBuffer(raw))) {\n return\n }\n void handleFrame(socket, String(raw), options.localPort, abortControllers).catch((error) => {\n const message = error instanceof Error ? error.message : 'Relay request failed'\n socket?.send(JSON.stringify({ type: 'http.error', id: 'unknown', status: 502, message }))\n })\n })\n socket.on('error', (error) => {\n const message = error instanceof Error ? error.message : 'Relay websocket error'\n options.onStatus?.({ state: 'disconnected', attempt: reconnectAttempts, message })\n })\n socket.on('close', () => {\n abortAll(abortControllers)\n abortControllers = new Map<string, AbortController>()\n if (closedByUser) {\n options.onStatus?.({ state: 'disconnected', attempt: reconnectAttempts })\n return\n }\n if (reconnectAttempts >= maxReconnectAttempts) {\n options.onStatus?.({ state: 'failed', attempt: reconnectAttempts, message: 'Relay reconnect attempts exhausted' })\n return\n }\n reconnectAttempts += 1\n const delay = computeBackoffMs(reconnectAttempts, backoffBaseMs, backoffMaxMs)\n options.onStatus?.({ state: 'retrying', attempt: reconnectAttempts, message: `Retrying in ${delay}ms` })\n retryTimer = setTimeout(connect, delay)\n retryTimer.unref?.()\n })\n }\n\n connect()\n\n return {\n close() {\n closedByUser = true\n if (retryTimer) {\n clearTimeout(retryTimer)\n }\n abortAll(abortControllers)\n socket?.close()\n },\n }\n}\n\nfunction abortAll(abortControllers: Map<string, AbortController>): void {\n for (const controller of abortControllers.values()) {\n controller.abort()\n }\n abortControllers.clear()\n}\n\nfunction computeBackoffMs(attempt: number, baseMs: number, maxMs: number): number {\n const exponential = Math.min(maxMs, baseMs * 2 ** Math.max(0, attempt - 1))\n const jitter = Math.floor(Math.random() * Math.min(1_000, exponential * 0.2))\n return exponential + jitter\n}\n\nasync function handleFrame(\n socket: WebSocket,\n raw: string,\n localPort: number,\n abortControllers: Map<string, AbortController>,\n): Promise<void> {\n const frame = JSON.parse(raw) as RelayFrame\n if (frame.type === 'http.cancel') {\n abortControllers.get(frame.id)?.abort()\n abortControllers.delete(frame.id)\n return\n }\n if (frame.type !== 'http.request') {\n return\n }\n const abortController = new AbortController()\n abortControllers.set(frame.id, abortController)\n try {\n const response = await fetch(`http://127.0.0.1:${localPort}${frame.path}`, {\n method: frame.method,\n headers: frame.headers ?? {},\n body: frame.bodyBase64 ? Buffer.from(frame.bodyBase64, 'base64') : undefined,\n signal: abortController.signal,\n })\n const headers = Object.fromEntries(response.headers.entries())\n const contentType = response.headers.get('content-type') ?? ''\n if (response.body && contentType.includes('text/event-stream')) {\n socket.send(JSON.stringify({ type: 'http.stream.start', id: frame.id, status: response.status, headers }))\n const reader = response.body.getReader()\n while (true) {\n const next = await reader.read()\n if (next.done) {\n break\n }\n socket.send(JSON.stringify({ type: 'http.stream.chunk', id: frame.id, bodyBase64: Buffer.from(next.value).toString('base64') }))\n }\n socket.send(JSON.stringify({ type: 'http.stream.end', id: frame.id }))\n return\n }\n const body = Buffer.from(await response.arrayBuffer()).toString('base64')\n socket.send(JSON.stringify({ type: 'http.response', id: frame.id, status: response.status, headers, bodyBase64: body }))\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Relay request failed'\n socket.send(JSON.stringify({ type: 'http.error', id: frame.id, status: 502, message }))\n } finally {\n abortControllers.delete(frame.id)\n }\n}\n","export type SupportedLanguage = 'zh-CN' | 'en'\nexport type ConfiguredLanguage = SupportedLanguage | 'auto'\n\nconst messages = {\n en: {\n 'program.description': 'Hermes Link companion service',\n 'program.version': 'print Hermes Link version',\n 'status.description': 'Show local Hermes Link status',\n 'status.json': 'print machine-readable status',\n 'status.runtime': 'Runtime: {value}',\n 'status.mode': 'Mode: {value}',\n 'status.port': 'Local port: {value}',\n 'status.linkId': 'Link ID: {value}',\n 'status.notPaired': 'not paired',\n 'start.description': 'Start Hermes Link daemon',\n 'start.backgroundStarted': 'Hermes Link is running in the background. PID: {pid}',\n 'start.alreadyRunning': 'Hermes Link is already running. PID: {pid}',\n 'start.notPaired': 'Hermes Link is not paired yet. Starting in local-only maintenance mode.',\n 'start.notPaired.detail':\n 'Relay, Server polling, and LAN entrypoints stay disabled until you run `hermeslink pair`.',\n 'start.listening': 'Hermes Link API listening on http://127.0.0.1:{port}',\n 'start.relayConnecting': 'Relay control connecting for {linkId}',\n 'stop.description': 'Stop the background Hermes Link daemon',\n 'stop.stopped': 'Hermes Link stopped.',\n 'stop.notRunning': 'Hermes Link is not running.',\n 'restart.description': 'Restart the background Hermes Link daemon',\n 'daemon.description': 'Run Hermes Link in the foreground',\n 'daemon.foreground': 'Hermes Link foreground daemon is running. Press Ctrl+C to stop.',\n 'logs.description': 'Show Hermes Link log paths',\n 'logs.servicePath': 'Service log: {path}',\n 'logs.daemonPath': 'Daemon stdout/stderr log: {path}',\n 'autostart.description': 'Manage boot autostart',\n 'autostart.on.description': 'Enable boot autostart',\n 'autostart.off.description': 'Disable boot autostart',\n 'autostart.status.description': 'Show boot autostart status',\n 'autostart.enabled': 'Boot autostart enabled via {method}: {path}',\n 'autostart.disabled': 'Boot autostart disabled.',\n 'autostart.status.enabled': 'Boot autostart: enabled via {method}: {path}',\n 'autostart.status.disabled': 'Boot autostart: disabled. Method: {method}. File: {path}',\n 'autostart.unsupported': 'Boot autostart is not supported on this platform yet.',\n 'pair.description': 'Create a Hermes Link pairing session',\n 'pair.preparing': 'Preparing pairing session through HermesPilot Server and Relay...',\n 'pair.server': 'Server: {url}',\n 'pair.relay': 'Relay: {url}',\n 'pair.linkId': 'Hermes Link ID: {value}',\n 'pair.code': 'Pairing code: {value}',\n 'pair.localApi': 'Local API: http://127.0.0.1:{port}',\n 'pair.scan': 'Scan this QR code with the HermesPilot App:',\n 'pair.expires': 'Pairing expires in 10 minutes. Press Ctrl+C to stop Hermes Link.',\n 'pair.claimed': 'Pairing succeeded. Starting Hermes Link in the background...',\n 'pair.autostartFailed': 'Pairing succeeded, but boot autostart could not be enabled: {message}',\n 'doctor.description': 'Run local diagnostics',\n 'doctor.identityOk': 'Runtime identity: OK',\n 'doctor.installId': 'Install ID: {value}',\n 'doctor.linkId': 'Link ID: {value}',\n 'doctor.notAssigned': 'not assigned',\n 'error.relayPublicKeyMismatch':\n 'Relay rejected the pairing request because the Server-issued bootstrap token does not match this Link public key. Make sure Server and Relay are deployed with the same bootstrap key configuration, then run `hermeslink pair` again.',\n 'error.relayChallengeInvalid': 'Relay did not return a valid install challenge.',\n 'error.relayLinkInvalid': 'Relay did not return a valid link_id.',\n 'error.relayEmpty': 'Relay returned an empty response.',\n 'error.serverHttp': 'HermesPilot Server request failed with HTTP {status}.',\n 'error.portInUse':\n 'Local port {port} is already in use. Stop the existing Hermes Link process, then run `hermeslink pair` again.',\n 'error.pairingRequires':\n 'Pairing needs HermesPilot Server and Relay, but this command could not start a complete pairing session.',\n 'error.pairingRequires.detail':\n 'The deployed services may be healthy, but the installed Link package must call Server for a short-lived relay bootstrap token before it can request a link_id.',\n },\n 'zh-CN': {\n 'program.description': 'Hermes Link 本地伴随服务',\n 'program.version': '输出 Hermes Link 版本号',\n 'status.description': '查看本机 Hermes Link 状态',\n 'status.json': '输出机器可读的状态 JSON',\n 'status.runtime': '运行目录:{value}',\n 'status.mode': '模式:{value}',\n 'status.port': '本地端口:{value}',\n 'status.linkId': 'Link ID:{value}',\n 'status.notPaired': '尚未配对',\n 'start.description': '启动 Hermes Link 服务',\n 'start.backgroundStarted': 'Hermes Link 已在后台运行。PID:{pid}',\n 'start.alreadyRunning': 'Hermes Link 已经在运行。PID:{pid}',\n 'start.notPaired': 'Hermes Link 还没有配对,将以本地维护模式启动。',\n 'start.notPaired.detail': '在你运行 `hermeslink pair` 前,Relay、Server 轮询和局域网入口都会保持关闭。',\n 'start.listening': 'Hermes Link API 正在监听 http://127.0.0.1:{port}',\n 'start.relayConnecting': '正在为 {linkId} 连接 Relay 控制通道',\n 'stop.description': '停止后台 Hermes Link 服务',\n 'stop.stopped': 'Hermes Link 已停止。',\n 'stop.notRunning': 'Hermes Link 没有在运行。',\n 'restart.description': '重启后台 Hermes Link 服务',\n 'daemon.description': '以前台方式运行 Hermes Link',\n 'daemon.foreground': 'Hermes Link 前台服务正在运行。按 Ctrl+C 停止。',\n 'logs.description': '显示 Hermes Link 日志路径',\n 'logs.servicePath': '服务日志:{path}',\n 'logs.daemonPath': 'Daemon 标准输出/错误日志:{path}',\n 'autostart.description': '管理开机自启',\n 'autostart.on.description': '启用开机自启',\n 'autostart.off.description': '关闭开机自启',\n 'autostart.status.description': '查看开机自启状态',\n 'autostart.enabled': '已启用开机自启,方式:{method},文件:{path}',\n 'autostart.disabled': '已关闭开机自启。',\n 'autostart.status.enabled': '开机自启:已启用,方式:{method},文件:{path}',\n 'autostart.status.disabled': '开机自启:未启用。方式:{method},文件:{path}',\n 'autostart.unsupported': '当前平台暂不支持开机自启。',\n 'pair.description': '创建 Hermes Link 配对会话',\n 'pair.preparing': '正在通过 HermesPilot Server 和 Relay 创建配对会话...',\n 'pair.server': 'Server:{url}',\n 'pair.relay': 'Relay:{url}',\n 'pair.linkId': 'Hermes Link ID:{value}',\n 'pair.code': '配对码:{value}',\n 'pair.localApi': '本地 API:http://127.0.0.1:{port}',\n 'pair.scan': '请使用 HermesPilot App 扫描这个二维码:',\n 'pair.expires': '配对会话 10 分钟后过期。按 Ctrl+C 停止 Hermes Link。',\n 'pair.claimed': '配对已成功。正在把 Hermes Link 切换到后台运行...',\n 'pair.autostartFailed': '配对已成功,但启用开机自启失败:{message}',\n 'doctor.description': '运行本机诊断',\n 'doctor.identityOk': '运行身份:正常',\n 'doctor.installId': 'Install ID:{value}',\n 'doctor.linkId': 'Link ID:{value}',\n 'doctor.notAssigned': '尚未分配',\n 'error.relayPublicKeyMismatch':\n 'Relay 拒绝了配对请求:Server 签发的 bootstrap token 与本机 Link 公钥不匹配。请确认 Server 和 Relay 使用同一套 bootstrap key 配置,然后重新运行 `hermeslink pair`。',\n 'error.relayChallengeInvalid': 'Relay 没有返回有效的安装挑战。',\n 'error.relayLinkInvalid': 'Relay 没有返回有效的 link_id。',\n 'error.relayEmpty': 'Relay 返回了空响应。',\n 'error.serverHttp': 'HermesPilot Server 请求失败,HTTP 状态码:{status}。',\n 'error.portInUse': '本地端口 {port} 已被占用。请先停止已有的 Hermes Link 进程,然后重新运行 `hermeslink pair`。',\n 'error.pairingRequires': '配对需要 HermesPilot Server 和 Relay,但当前命令没有能启动完整配对会话。',\n 'error.pairingRequires.detail':\n '云端服务可以是已部署且健康的;本机 Link 仍必须先向 Server 申请短期 relay bootstrap token,才能再向 Relay 申请 link_id。',\n },\n} satisfies Record<SupportedLanguage, Record<string, string>>\n\nexport type MessageKey = keyof (typeof messages)['en']\n\nexport function detectSystemLanguage(env: NodeJS.ProcessEnv = process.env): SupportedLanguage {\n const candidates = [\n env.HERMESLINK_LANG,\n env.HERMESLINK_LANGUAGE,\n env.LC_ALL,\n env.LC_MESSAGES,\n env.LANG,\n env.LANGUAGE?.split(':')[0],\n Intl.DateTimeFormat().resolvedOptions().locale,\n ]\n for (const candidate of candidates) {\n const language = parseLanguage(candidate)\n if (language) {\n return language\n }\n }\n return 'en'\n}\n\nexport function resolveLanguage(setting?: ConfiguredLanguage | string | null): SupportedLanguage {\n const configured = parseLanguage(setting)\n if (configured) {\n return configured\n }\n return detectSystemLanguage()\n}\n\nexport function translate(\n language: SupportedLanguage,\n key: MessageKey,\n values: Record<string, string | number> = {},\n): string {\n const template = messages[language][key] ?? messages.en[key]\n return template.replace(/\\{(\\w+)\\}/gu, (_, name: string) => String(values[name] ?? ''))\n}\n\nexport function localizeErrorMessage(error: unknown, language: SupportedLanguage): string {\n const message = error instanceof Error ? error.message : String(error)\n if (language === 'en') {\n return message\n }\n const mapped = translateKnownError(message, language)\n return mapped ?? message\n}\n\nfunction translateKnownError(message: string, language: SupportedLanguage): string | null {\n if (message === 'Relay bootstrap token does not match public key') {\n return translate(language, 'error.relayPublicKeyMismatch')\n }\n if (message === 'Relay did not return a valid install challenge') {\n return translate(language, 'error.relayChallengeInvalid')\n }\n if (message === 'Relay did not return a valid link_id') {\n return translate(language, 'error.relayLinkInvalid')\n }\n if (message === 'Relay returned an empty response') {\n return translate(language, 'error.relayEmpty')\n }\n const portInUse = /^listen EADDRINUSE: address already in use .*:(?<port>\\d+)$/u.exec(message)\n if (portInUse?.groups?.port) {\n return translate(language, 'error.portInUse', { port: portInUse.groups.port })\n }\n const serverHttp = /^HermesPilot Server request failed with HTTP (?<status>\\d+)$/u.exec(message)\n if (serverHttp?.groups?.status) {\n return translate(language, 'error.serverHttp', { status: serverHttp.groups.status })\n }\n if (message.includes('Pairing requires HermesPilot Server and Relay')) {\n return [translate(language, 'error.pairingRequires'), translate(language, 'error.pairingRequires.detail')].join('\\n')\n }\n return null\n}\n\nfunction parseLanguage(value: string | null | undefined): SupportedLanguage | null {\n const normalized = value?.trim().replace('_', '-').toLowerCase()\n if (!normalized || normalized === 'auto' || normalized === 'c' || normalized === 'posix') {\n return null\n }\n if (normalized.startsWith('zh')) {\n return 'zh-CN'\n }\n if (normalized.startsWith('en')) {\n return 'en'\n }\n return null\n}\n"],"mappings":"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","names":["mkdir","readFile","rm","writeFile","path","mkdir","rm","mkdir","rm","mkdir","path","writeFile","rm","readFile","autostart"]}
package/dist/http/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApp
3
- } from "../chunk-7M3UZCA7.js";
3
+ } from "../chunk-T35GPRKF.js";
4
4
  export {
5
5
  createApp
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hermespilot/link",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "description": "Hermes Link companion service and CLI for connecting hermes-agent through HermesPilot",
6
6
  "license": "MIT",