@hermespilot/link 0.1.1 → 0.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/index.ts","../../src/i18n.ts","../../src/relay/control-client.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander'\nimport qrcode from 'qrcode-terminal'\nimport { LINK_COMMAND, LINK_VERSION } from '../constants.js'\nimport { loadConfig } from '../config/config.js'\nimport { ensureHermesApiServerKey } from '../hermes/config.js'\nimport { createApp } from '../http/app.js'\nimport { ensureIdentity, getIdentityStatus, loadIdentity } from '../identity/identity.js'\nimport { detectSystemLanguage, localizeErrorMessage, resolveLanguage, translate } from '../i18n.js'\nimport { preparePairing } from '../pairing/pairing.js'\nimport { connectRelayControl } from '../relay/control-client.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 [identity, config] = await Promise.all([loadIdentity(), loadConfig()])\n const language = resolveLanguage(config.language)\n const t = translate.bind(null, language)\n if (!identity?.link_id) {\n console.log(t('start.notPaired'))\n console.log(t('start.notPaired.detail'))\n }\n const server = await startHttpServer(config.port)\n const relay = identity?.link_id\n ? connectRelayControl({\n relayBaseUrl: config.relayBaseUrl,\n linkId: identity.link_id,\n localPort: config.port,\n })\n : null\n console.log(t('start.listening', { port: config.port }))\n if (identity?.link_id) {\n console.log(t('start.relayConnecting', { linkId: identity.link_id }))\n }\n await waitForShutdown(async () => {\n relay?.close()\n await new Promise<void>((resolve) => server.close(() => resolve()))\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 server = await startHttpServer(config.port)\n const relay = connectRelayControl({\n relayBaseUrl: prepared.relayBaseUrl,\n linkId: prepared.linkId,\n localPort: config.port,\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 await waitForShutdown(async () => {\n relay.close()\n await new Promise<void>((resolve) => server.close(() => resolve()))\n })\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 startHttpServer(port: number) {\n const app = await createApp()\n return app.listen(port)\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","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.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 '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 '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.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 '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 '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","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}): 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 socket = new WebSocket(wsUrl, {\n headers: {\n 'x-hermes-link-version': LINK_VERSION,\n },\n })\n const abortControllers = new Map<string, AbortController>()\n socket.on('message', (raw) => {\n if (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('close', () => {\n for (const controller of abortControllers.values()) {\n controller.abort()\n }\n abortControllers.clear()\n })\n return {\n close() {\n socket.close()\n },\n }\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"],"mappings":"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","names":[]}
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,5 +1,48 @@
1
1
  import Koa from 'koa';
2
2
 
3
- declare function createApp(): Promise<Koa>;
3
+ interface RuntimePaths {
4
+ homeDir: string;
5
+ identityFile: string;
6
+ configFile: string;
7
+ stateFile: string;
8
+ credentialsFile: string;
9
+ databaseFile: string;
10
+ logsDir: string;
11
+ runDir: string;
12
+ pairingDir: string;
13
+ }
4
14
 
5
- export { createApp };
15
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
16
+ interface FileLoggerOptions {
17
+ paths?: RuntimePaths;
18
+ fileName?: string;
19
+ maxFileBytes?: number;
20
+ maxFiles?: number;
21
+ now?: () => Date;
22
+ }
23
+ declare class FileLogger {
24
+ readonly filePath: string;
25
+ private readonly paths;
26
+ private readonly maxFileBytes;
27
+ private readonly maxFiles;
28
+ private readonly now;
29
+ private queue;
30
+ constructor(options?: FileLoggerOptions);
31
+ debug(message: string, fields?: Record<string, unknown>): Promise<void>;
32
+ info(message: string, fields?: Record<string, unknown>): Promise<void>;
33
+ warn(message: string, fields?: Record<string, unknown>): Promise<void>;
34
+ error(message: string, fields?: Record<string, unknown>): Promise<void>;
35
+ write(level: LogLevel, message: string, fields?: Record<string, unknown>): Promise<void>;
36
+ flush(): Promise<void>;
37
+ private appendEntry;
38
+ private rotateIfNeeded;
39
+ }
40
+
41
+ interface CreateAppOptions {
42
+ paths?: RuntimePaths;
43
+ logger?: FileLogger;
44
+ onPairingClaimed?: () => void | Promise<void>;
45
+ }
46
+ declare function createApp(options?: CreateAppOptions): Promise<Koa>;
47
+
48
+ export { type CreateAppOptions, createApp };
package/dist/http/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApp
3
- } from "../chunk-4CDHEW3J.js";
3
+ } from "../chunk-7M3UZCA7.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.1",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "description": "Hermes Link companion service and CLI for connecting hermes-agent through HermesPilot",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
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"],"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, type AppConnectClaims } from '../security/app-connect-token.js'\nimport { discoverRouteCandidates } from '../topology/network.js'\n\ninterface AuthContext {\n kind: 'device' | 'app-connect'\n device?: DeviceRecord\n accountId?: string\n}\n\nexport async function createApp(): Promise<Koa> {\n const app = new Koa()\n const router = new Router()\n\n app.use(async (ctx, next) => {\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 }\n })\n\n router.get('/api/v1/bootstrap', async (ctx) => {\n const [identity, config] = await Promise.all([loadIdentity(), loadConfig()])\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 },\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 ctx.body = 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 })\n })\n\n router.get('/api/v1/auth/me', async (ctx) => {\n const auth = await authenticateRequest(ctx)\n const identity = await loadRequiredIdentity()\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)\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)\n }\n ctx.body = { ok: true }\n })\n\n router.get('/api/v1/status', async (ctx) => {\n await authenticateRequest(ctx)\n const [identity, config] = await Promise.all([loadIdentity(), loadConfig()])\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/models', async (ctx) => {\n await authenticateRequest(ctx)\n ctx.body = await listHermesModels()\n })\n\n router.post('/api/v1/runs', async (ctx) => {\n await authenticateRequest(ctx)\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)\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)\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)\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)\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)\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)\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)\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)\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): 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)\n if (device) {\n return { kind: 'device', device }\n }\n const [identity, config] = await Promise.all([loadRequiredIdentity(), loadConfig()])\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() {\n const identity = await loadIdentity()\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 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.1'\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'\n\nexport interface RouteDiscoveryResult {\n lanIps: string[]\n publicIpv4s: string[]\n publicIpv6s: string[]\n preferredUrls: string[]\n}\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 preferredUrls = [\n ...lanIps.map((ip) => buildDirectUrl(ip, options.port)),\n ...publicIps.publicIpv4s.map((ip) => buildDirectUrl(ip, options.port)),\n ...publicIps.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: publicIps.publicIpv4s,\n publicIpv6s: publicIps.publicIpv6s,\n preferredUrls,\n }\n}\n\nfunction discoverLanIps(): string[] {\n const result = new Set<string>()\n const interfaces = os.networkInterfaces()\n for (const items of Object.values(interfaces)) {\n for (const item of items ?? []) {\n if (!item.internal && item.address && (item.family === 'IPv4' || item.family === 'IPv6')) {\n result.add(item.address)\n }\n }\n }\n return [...result]\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((ip) => !ip.includes(':'))),\n publicIpv6s: unique(values.filter((ip) => ip.includes(':'))),\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 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: routes.preferredUrls,\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 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"],"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","readString","loadRequiredIdentity"]}