{“content”:”---\nname: jakephone-pwa\ndescription: 在 Android/Termux 上运行的 PWA,桥接 Web 界面和 Hermes Agent 后端\n---\n\n# Jakephone PWA — Web App for Hermes\n\n## 背景\n在 Android/Termux 上运行的 PWA,桥接 Web 界面和 Hermes Agent 后端。\n项目目录:~/jakephone-pwa/\n\n## 架构\n- 前端:PWA(manifest + Service Worker),深色主题,4 个功能区(聊天/仪表盘/工具/设置)\n- 服务器:Express + WebSocket,端口 3000\n- 隧道:cloudflared(每次重启需重新生成 URL)\n- 后端:Hermes Agent\n\n## 访问地址\nbash\n# 启动隧道\ncloudflared tunnel --url http://localhost:3000\n\n# 重启服务器\ncd ~/jakephone-pwa && node server.js\n\n\n## 关键:Hermes 命令行聊天(非交互式)\nbash\nhermes chat -q \"消息内容\"\n\n返回格式(需解析):\n\n╭─ ⚕ Hermes ───────────────────╮\n响应内容\n\nsession_id: 20260417_134709_5de5d5\n\n\n## 解析函数(JavaScript)\njavascript\nfunction parseHermesOutput(output) {\n let text = output.replace(/\\r/g, '');\n text = text.replace(/^\\n?╭─[^\\n]*─╮\\n?/, '');\n text = text.replace(/\\nsession_id:[^\\n]*/g, '');\n text = text.replace(/[╭╮╰│─]/g, '');\n return text.trim() || '(無回應)';\n}\n\n\n## server.js 聊天转发核心逻辑\njavascript\n// WebSocket 聊天消息 → Hermes → 返回解析后的响应\nwss.on('connection', (ws) => {\n ws.on('message', (message) => {\n const { type, content } = JSON.parse(message);\n if (type === 'chat') {\n const cmd = `hermes chat -q \"${content.replace(/\"/g, '\\\\\"')}\"`;\n exec(cmd, { timeout: 120000 }, (error, stdout, stderr) => {\n const response = parseHermesOutput(stdout || stderr || '');\n ws.send(JSON.stringify({ type: 'chat_response', content: response }));\n });\n }\n });\n});\n\n\n## PWA URL(最近一次)\nhttps://supply-cleaner-emma-bonds.trycloudflare.com\n\n## 待完成\n- [ ] 仪表盘功能区(目前只是占位)\n- [ ] 工具/设置功能区\n- [ ] 持久化 cloudflared 隧道\n”}