@bulolo/hermes-link 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +330 -439
- package/README.zh-CN.md +739 -0
- package/dist/{chunk-EYXOHOAC.js → chunk-7IVSOP5F.js} +137 -45
- package/dist/cli/index.js +10 -5
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
- package/README.en.md +0 -630
package/README.md
CHANGED
|
@@ -2,99 +2,99 @@
|
|
|
2
2
|
|
|
3
3
|
# hermes-link
|
|
4
4
|
|
|
5
|
-
**Hermes Agent
|
|
5
|
+
**Local access layer for Hermes Agent**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Provides full client API, multi-device auth and conversation management for [Hermes Agent](https://github.com/nousresearch/hermes-agent), with LAN and internet connectivity.
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@bulolo/hermes-link)
|
|
10
10
|
[](https://nodejs.org/)
|
|
11
11
|
[](#)
|
|
12
12
|
[](#)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
[中文](./README.zh-CN.md) | **English**
|
|
15
15
|
|
|
16
|
-
[npm
|
|
16
|
+
[npm package](https://www.npmjs.com/package/@bulolo/hermes-link)
|
|
17
17
|
|
|
18
18
|
<p>
|
|
19
19
|
<a href="https://github.com/bulolo/HermesLink">
|
|
20
|
-
<img src="https://img.shields.io/badge/⭐_Star
|
|
20
|
+
<img src="https://img.shields.io/badge/⭐_Star-Project-yellow?style=for-the-badge&logo=github" alt="Star Project"/>
|
|
21
21
|
</a>
|
|
22
22
|
</p>
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**If this project helps you, please ⭐ Star it — it means a lot to the developer!**
|
|
25
25
|
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## Overview
|
|
31
31
|
|
|
32
|
-
Hermes Link
|
|
32
|
+
Hermes Link is a background HTTP service running on your local machine, listening on `http://0.0.0.0:18642` by default. Clients (App / browser) connect directly over LAN or the internet — all conversations, files and commands are processed locally, with no data leaving your machine.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
All API requests fall into two categories:
|
|
35
35
|
|
|
36
|
-
-
|
|
37
|
-
-
|
|
36
|
+
- **No auth required**: `/pair`, `/api/v1/bootstrap`
|
|
37
|
+
- **Bearer Token required**: all other endpoints require `Authorization: Bearer hlat_xxx`, obtained through the pairing flow
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Why HermesLink?
|
|
40
40
|
|
|
41
|
-
Hermes Agent
|
|
41
|
+
Hermes Agent ships with a built-in API Server (port 8642), but it only exposes **12 endpoints**:
|
|
42
42
|
|
|
43
|
-
|
|
|
44
|
-
|
|
45
|
-
|
|
|
46
|
-
| Agent
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
| Profile & Memory
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
43
|
+
| Feature | Hermes API Server `:8642` | HermesLink `:18642` |
|
|
44
|
+
|---------|:---:|:---:|
|
|
45
|
+
| Endpoint count | 12 | **97** |
|
|
46
|
+
| Agent execution / event stream | ✓ | ✓ (proxied) |
|
|
47
|
+
| Model list / Cron jobs | ✓ | ✓ (proxied) |
|
|
48
|
+
| Authentication | Single shared key | Per-device token, individually revocable |
|
|
49
|
+
| Device pairing | — | ✓ QR code / multi-device management |
|
|
50
|
+
| Conversation storage | — | ✓ Local history + attachments |
|
|
51
|
+
| Profile & Memory management | — | ✓ Multi-profile, memory, permissions, tool switches |
|
|
52
|
+
| Usage statistics | — | ✓ Token usage by date / model / profile |
|
|
53
|
+
| Tool call approval | — | ✓ Approve / deny flow |
|
|
54
|
+
| Update management / autostart | — | ✓ |
|
|
55
55
|
|
|
56
|
-
###
|
|
56
|
+
### When to use which
|
|
57
57
|
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
58
|
+
- **Local scripts / trusted internal services calling Hermes directly** → use Hermes API Server (8642)
|
|
59
|
+
- **Building a mobile app or multi-device access** → HermesLink (18642) required
|
|
60
|
+
- **Need conversation history / Profile management / statistics** → HermesLink (18642) required
|
|
61
61
|
|
|
62
|
-
##
|
|
62
|
+
## How It Works
|
|
63
63
|
|
|
64
64
|
```
|
|
65
|
-
|
|
65
|
+
Client (browser / App)
|
|
66
66
|
│
|
|
67
|
-
└──→ hermeslink (
|
|
67
|
+
└──→ hermeslink (local machine, port 18642)
|
|
68
68
|
│
|
|
69
|
-
├──
|
|
69
|
+
├── auth / device management / conversation storage / Profile & Memory ← handled by HermesLink (~87 endpoints)
|
|
70
70
|
│
|
|
71
|
-
└──→ Hermes Agent API Server (127.0.0.1:8642)
|
|
71
|
+
└──→ Hermes Agent API Server (127.0.0.1:8642) ← only runs / models / cron jobs (~10 endpoints)
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
The vast majority of functionality is handled by HermesLink independently, without relying on the API Server. If the API Server is not running, auth, pairing, conversation queries, and Profile management all continue to work — only Agent execution, model listing, and cron jobs become unavailable. All data is stored locally.
|
|
75
75
|
|
|
76
|
-
##
|
|
76
|
+
## Requirements
|
|
77
77
|
|
|
78
78
|
### 1. Node.js >= 20.0.0
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
node --version #
|
|
81
|
+
node --version # must be >= v20.0.0
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
If not installed, use [nvm](https://github.com/nvm-sh/nvm):
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
87
|
nvm install 20
|
|
88
88
|
nvm use 20
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
### 2.
|
|
91
|
+
### 2. Start the Hermes Agent API Server
|
|
92
92
|
|
|
93
|
-
Hermes
|
|
93
|
+
HermesLink communicates with the **Hermes Agent API Server** at `127.0.0.1:8642`.
|
|
94
94
|
|
|
95
|
-
>
|
|
95
|
+
> If the API Server is not running, conversation and Profile features will be unavailable, but auth, pairing, device management, and logs still work fine.
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
Add the following to `~/.hermes/.env` to enable the API Server:
|
|
98
98
|
|
|
99
99
|
```bash
|
|
100
100
|
API_SERVER_ENABLED=true
|
|
@@ -104,71 +104,68 @@ API_SERVER_CORS_ORIGINS=*
|
|
|
104
104
|
GATEWAY_ALLOW_ALL_USERS=true
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
|
|
|
108
|
-
|
|
109
|
-
| `API_SERVER_ENABLED` |
|
|
110
|
-
| `API_SERVER_KEY` |
|
|
111
|
-
| `API_SERVER_HOST` |
|
|
112
|
-
| `API_SERVER_CORS_ORIGINS` | CORS
|
|
107
|
+
| Option | Description |
|
|
108
|
+
|--------|-------------|
|
|
109
|
+
| `API_SERVER_ENABLED` | Set to `true` to enable the API Server |
|
|
110
|
+
| `API_SERVER_KEY` | Auth key — replace with a strong random string: `openssl rand -hex 32` |
|
|
111
|
+
| `API_SERVER_HOST` | Listen address — `0.0.0.0` allows all network interfaces |
|
|
112
|
+
| `API_SERVER_CORS_ORIGINS` | CORS origins — can be `*` for local development |
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
Then restart:
|
|
115
115
|
|
|
116
116
|
```bash
|
|
117
|
-
hermes gateway stop
|
|
118
|
-
hermes gateway start
|
|
119
|
-
或者
|
|
120
117
|
hermes gateway restart
|
|
121
118
|
```
|
|
122
119
|
|
|
123
|
-
|
|
120
|
+
Verify it's running:
|
|
124
121
|
|
|
125
122
|
```bash
|
|
126
123
|
curl -s http://127.0.0.1:8642/v1/health
|
|
127
124
|
```
|
|
128
125
|
|
|
129
|
-
|
|
126
|
+
If missing or outdated:
|
|
130
127
|
|
|
131
128
|
```bash
|
|
132
129
|
hermes update
|
|
133
130
|
```
|
|
134
131
|
|
|
135
|
-
##
|
|
132
|
+
## Installation
|
|
136
133
|
|
|
137
|
-
npm
|
|
134
|
+
npm package: [https://www.npmjs.com/package/@bulolo/hermes-link](https://www.npmjs.com/package/@bulolo/hermes-link)
|
|
138
135
|
|
|
139
136
|
```bash
|
|
140
137
|
npm install -g @bulolo/hermes-link
|
|
141
138
|
```
|
|
142
139
|
|
|
143
|
-
>
|
|
140
|
+
> If the `hermeslink` command is not found after installation, the npm global bin directory is not in your PATH. Fix it with:
|
|
144
141
|
>
|
|
145
142
|
> ```bash
|
|
146
143
|
> export PATH="$(npm prefix -g)/bin:$PATH"
|
|
147
144
|
> ```
|
|
148
145
|
>
|
|
149
|
-
>
|
|
146
|
+
> Or call it directly: `$(npm prefix -g)/bin/hermeslink`
|
|
150
147
|
|
|
151
|
-
##
|
|
148
|
+
## Quick Start
|
|
152
149
|
|
|
153
150
|
```bash
|
|
154
|
-
# 1.
|
|
151
|
+
# 1. Start the background daemon
|
|
155
152
|
hermeslink start
|
|
156
153
|
|
|
157
|
-
# 2.
|
|
154
|
+
# 2. Open the pairing page in a browser
|
|
158
155
|
hermeslink pair
|
|
159
156
|
|
|
160
|
-
# 3.
|
|
157
|
+
# 3. Check status
|
|
161
158
|
hermeslink status
|
|
162
159
|
|
|
163
|
-
# 4.
|
|
160
|
+
# 4. View logs
|
|
164
161
|
hermeslink logs
|
|
165
162
|
```
|
|
166
163
|
|
|
167
|
-
##
|
|
164
|
+
## Pairing
|
|
168
165
|
|
|
169
|
-
###
|
|
166
|
+
### Method 1: App QR code scan (standard flow)
|
|
170
167
|
|
|
171
|
-
|
|
168
|
+
The QR code contains a JSON payload the app parses to get everything it needs:
|
|
172
169
|
|
|
173
170
|
```json
|
|
174
171
|
{
|
|
@@ -182,31 +179,31 @@ hermeslink logs
|
|
|
182
179
|
}
|
|
183
180
|
```
|
|
184
181
|
|
|
185
|
-
|
|
182
|
+
Once the app has this:
|
|
186
183
|
|
|
187
184
|
```
|
|
188
|
-
1.
|
|
185
|
+
1. Use preferred_urls[0] as the base URL (LAN IP preferred)
|
|
189
186
|
2. POST {baseUrl}/api/v1/pairing/claim
|
|
190
|
-
Body: { "session_id": "...", "claim_token": "<code
|
|
191
|
-
3.
|
|
192
|
-
4.
|
|
187
|
+
Body: { "session_id": "...", "claim_token": "<value of the code field>" }
|
|
188
|
+
3. Response contains access_token and refresh_token
|
|
189
|
+
4. Include Authorization: Bearer <access_token> on all subsequent requests
|
|
193
190
|
```
|
|
194
191
|
|
|
195
|
-
###
|
|
192
|
+
### Method 2: Browser pairing
|
|
196
193
|
|
|
197
194
|
```bash
|
|
198
195
|
hermeslink pair
|
|
199
|
-
#
|
|
200
|
-
#
|
|
196
|
+
# Open the Pairing page URL printed in the terminal
|
|
197
|
+
# Click "Pair on this device" — the page shows your access_token and refresh_token
|
|
201
198
|
```
|
|
202
199
|
|
|
203
|
-
###
|
|
200
|
+
### Method 3: CLI / script (automation-friendly)
|
|
204
201
|
|
|
205
202
|
```bash
|
|
206
|
-
# 1.
|
|
203
|
+
# 1. Get the connect_token
|
|
207
204
|
CONNECT_TOKEN=$(hermeslink pair 2>&1 | grep "Connect token:" | awk '{print $NF}')
|
|
208
205
|
|
|
209
|
-
# 2.
|
|
206
|
+
# 2. Exchange it for an access_token
|
|
210
207
|
curl -s -X POST http://localhost:18642/api/v1/auth/device-session \
|
|
211
208
|
-H "Authorization: Bearer $CONNECT_TOKEN" \
|
|
212
209
|
-H "Content-Type: application/json" \
|
|
@@ -215,348 +212,242 @@ curl -s -X POST http://localhost:18642/api/v1/auth/device-session \
|
|
|
215
212
|
|
|
216
213
|
---
|
|
217
214
|
|
|
218
|
-
> **Token
|
|
215
|
+
> **Token expiry**: access_token lasts 2 hours, refresh_token lasts 90 days. When the access_token expires, use the refresh_token to get a new one — no need to re-pair.
|
|
219
216
|
|
|
220
|
-
##
|
|
217
|
+
## Commands
|
|
221
218
|
|
|
222
|
-
|
|
|
223
|
-
|
|
224
|
-
| `hermeslink start` |
|
|
225
|
-
| `hermeslink stop` |
|
|
226
|
-
| `hermeslink restart` |
|
|
227
|
-
| `hermeslink status` |
|
|
228
|
-
| `hermeslink pair` |
|
|
229
|
-
| `hermeslink config get` |
|
|
230
|
-
| `hermeslink config set <key> <value>` |
|
|
231
|
-
| `hermeslink autostart on` |
|
|
232
|
-
| `hermeslink autostart off` |
|
|
233
|
-
| `hermeslink logs` |
|
|
234
|
-
| `hermeslink logs --gateway` |
|
|
235
|
-
| `hermeslink logs -n 100` |
|
|
236
|
-
| `hermeslink version` |
|
|
219
|
+
| Command | Description |
|
|
220
|
+
|---------|-------------|
|
|
221
|
+
| `hermeslink start` | Start the background daemon |
|
|
222
|
+
| `hermeslink stop` | Stop the daemon |
|
|
223
|
+
| `hermeslink restart` | Restart the daemon |
|
|
224
|
+
| `hermeslink status` | Show running status |
|
|
225
|
+
| `hermeslink pair` | Generate pairing URL and QR code |
|
|
226
|
+
| `hermeslink config get` | Show current config |
|
|
227
|
+
| `hermeslink config set <key> <value>` | Update a config value |
|
|
228
|
+
| `hermeslink autostart on` | Enable autostart on login (alias: `enable`) |
|
|
229
|
+
| `hermeslink autostart off` | Disable autostart (alias: `disable`) |
|
|
230
|
+
| `hermeslink logs` | View Link logs |
|
|
231
|
+
| `hermeslink logs --gateway` | View Hermes gateway logs |
|
|
232
|
+
| `hermeslink logs -n 100` | View last 100 log lines |
|
|
233
|
+
| `hermeslink version` | Show version |
|
|
237
234
|
|
|
238
|
-
##
|
|
235
|
+
## Configuration
|
|
239
236
|
|
|
240
237
|
```bash
|
|
241
|
-
hermeslink config set port 18642 #
|
|
242
|
-
hermeslink config set lan-host 192.168.1.10 #
|
|
243
|
-
hermeslink config set language
|
|
244
|
-
hermeslink config set log-level debug #
|
|
238
|
+
hermeslink config set port 18642 # Change listen port (default: 18642)
|
|
239
|
+
hermeslink config set lan-host 192.168.1.10 # Set LAN IP manually (default: auto-detect)
|
|
240
|
+
hermeslink config set language en # Language: auto / en / zh-CN
|
|
241
|
+
hermeslink config set log-level debug # Log level: debug / info / warn / error
|
|
245
242
|
```
|
|
246
243
|
|
|
247
|
-
|
|
244
|
+
Config file is at `~/.hermeslink/config.json`.
|
|
248
245
|
|
|
249
|
-
## API
|
|
246
|
+
## API Reference
|
|
250
247
|
|
|
251
|
-
|
|
248
|
+
Service listens on `http://0.0.0.0:18642` by default. All authenticated endpoints use a Bearer Token with the `hlat_` prefix.
|
|
252
249
|
|
|
253
|
-
### Token
|
|
250
|
+
### Token Types
|
|
254
251
|
|
|
255
|
-
| Token |
|
|
256
|
-
|
|
257
|
-
| Connect Token |
|
|
258
|
-
| Access Token | `hlat_` |
|
|
259
|
-
| Refresh Token | `hlrt_` | 90
|
|
252
|
+
| Token | Prefix | Expiry | Purpose |
|
|
253
|
+
|-------|--------|--------|---------|
|
|
254
|
+
| Connect Token | none (base64url) | 5 min, one-time | Exchange for access_token |
|
|
255
|
+
| Access Token | `hlat_` | 15 min | All API requests |
|
|
256
|
+
| Refresh Token | `hlrt_` | 90 days | Refresh access_token |
|
|
260
257
|
|
|
261
|
-
###
|
|
258
|
+
### No Auth Required
|
|
262
259
|
|
|
263
|
-
|
|
|
264
|
-
|
|
265
|
-
| GET | `/pair` |
|
|
266
|
-
| GET | `/api/v1/bootstrap` |
|
|
260
|
+
| Method | Path | Description |
|
|
261
|
+
|--------|------|-------------|
|
|
262
|
+
| GET | `/pair` | Pairing web page (open in browser) |
|
|
263
|
+
| GET | `/api/v1/bootstrap` | Service info: link_id, version, capabilities |
|
|
267
264
|
|
|
268
|
-
###
|
|
265
|
+
### Auth / Devices
|
|
269
266
|
|
|
270
|
-
|
|
267
|
+
All endpoints below require `Authorization: Bearer hlat_xxx`
|
|
271
268
|
|
|
272
|
-
|
|
|
273
|
-
|
|
274
|
-
| GET | `/api/v1/auth/me` |
|
|
275
|
-
| POST | `/api/v1/auth/device-session` |
|
|
276
|
-
| POST | `/api/v1/auth/refresh` |
|
|
277
|
-
| POST | `/api/v1/auth/logout` |
|
|
269
|
+
| Method | Path | Description |
|
|
270
|
+
|--------|------|-------------|
|
|
271
|
+
| GET | `/api/v1/auth/me` | Current token info and device details |
|
|
272
|
+
| POST | `/api/v1/auth/device-session` | Exchange connect_token for access/refresh tokens |
|
|
273
|
+
| POST | `/api/v1/auth/refresh` | Refresh access_token using refresh_token |
|
|
274
|
+
| POST | `/api/v1/auth/logout` | Revoke refresh_token |
|
|
278
275
|
|
|
279
|
-
**POST `/api/v1/auth/device-session`**
|
|
276
|
+
**POST `/api/v1/auth/device-session`** — Authorization header takes the **connect_token** (not hlat_). Body:
|
|
280
277
|
|
|
281
278
|
```json
|
|
282
279
|
{
|
|
283
|
-
"device_label": "
|
|
280
|
+
"device_label": "My Device",
|
|
284
281
|
"device_platform": "ios|android|web|cli",
|
|
285
|
-
"device_model": "
|
|
282
|
+
"device_model": "optional device model"
|
|
286
283
|
}
|
|
287
284
|
```
|
|
288
285
|
|
|
289
|
-
|
|
286
|
+
Response:
|
|
290
287
|
|
|
291
288
|
```json
|
|
292
289
|
{
|
|
293
290
|
"ok": true,
|
|
294
|
-
"device": { "device_id": "dev_xxx", "label": "
|
|
291
|
+
"device": { "device_id": "dev_xxx", "label": "My Device", "platform": "ios" },
|
|
295
292
|
"access_token": { "token": "hlat_xxx", "expires_at": "2026-05-08T13:00:00Z" },
|
|
296
293
|
"refresh_token": { "token": "hlrt_xxx", "expires_at": "2026-08-06T12:00:00Z" }
|
|
297
294
|
}
|
|
298
295
|
```
|
|
299
296
|
|
|
300
|
-
**POST `/api/v1/auth/refresh`** Body
|
|
297
|
+
**POST `/api/v1/auth/refresh`** Body:
|
|
301
298
|
|
|
302
299
|
```json
|
|
303
300
|
{ "refresh_token": "hlrt_xxx" }
|
|
304
301
|
```
|
|
305
302
|
|
|
306
|
-
###
|
|
303
|
+
### Pairing
|
|
307
304
|
|
|
308
|
-
|
|
|
309
|
-
|
|
310
|
-
| GET | `/api/v1/pairing/session` |
|
|
311
|
-
| POST | `/api/v1/pairing/claim` |
|
|
305
|
+
| Method | Path | Description |
|
|
306
|
+
|--------|------|-------------|
|
|
307
|
+
| GET | `/api/v1/pairing/session` | Query pairing session status (includes `claimed` field) |
|
|
308
|
+
| POST | `/api/v1/pairing/claim` | Complete pairing from the app side |
|
|
312
309
|
|
|
313
|
-
**GET `/api/v1/pairing/session`**
|
|
310
|
+
**GET `/api/v1/pairing/session`** query: `?session_id=ps_xxx`
|
|
314
311
|
|
|
315
|
-
**POST `/api/v1/pairing/claim`** Body
|
|
312
|
+
**POST `/api/v1/pairing/claim`** Body:
|
|
316
313
|
|
|
317
314
|
```json
|
|
318
315
|
{
|
|
319
316
|
"session_id": "ps_xxx",
|
|
320
|
-
"claim_token": "connect_token
|
|
317
|
+
"claim_token": "<connect_token value>",
|
|
321
318
|
"device_label": "My App",
|
|
322
319
|
"device_platform": "ios"
|
|
323
320
|
}
|
|
324
321
|
```
|
|
325
322
|
|
|
326
|
-
###
|
|
327
|
-
|
|
328
|
-
|
|
|
329
|
-
|
|
330
|
-
| GET | `/api/v1/status` |
|
|
331
|
-
| GET | `/api/v1/logs` |
|
|
332
|
-
|
|
333
|
-
###
|
|
334
|
-
|
|
335
|
-
|
|
|
336
|
-
|
|
337
|
-
| GET | `/api/v1/devices` |
|
|
338
|
-
| PATCH | `/api/v1/devices/:deviceId` |
|
|
339
|
-
| DELETE | `/api/v1/devices/:deviceId` |
|
|
340
|
-
| DELETE | `/api/v1/devices/:deviceId/app-listing` |
|
|
341
|
-
|
|
342
|
-
###
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
|
347
|
-
|
|
348
|
-
|
|
|
349
|
-
|
|
|
350
|
-
|
|
|
351
|
-
|
|
|
352
|
-
|
|
|
353
|
-
| GET | `/api/v1/conversations/:id/
|
|
354
|
-
|
|
|
355
|
-
|
|
|
356
|
-
|
|
|
357
|
-
| PATCH | `/api/v1/conversations/:id/
|
|
358
|
-
|
|
|
359
|
-
|
|
|
360
|
-
|
|
|
361
|
-
| POST | `/api/v1/conversations
|
|
362
|
-
| POST | `/api/v1/conversations/:id/
|
|
363
|
-
| POST | `/api/v1/conversations/:id/approvals/:approvalId/
|
|
364
|
-
| POST | `/api/v1/conversations/:id/
|
|
365
|
-
|
|
|
366
|
-
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
| GET | `/api/v1/
|
|
374
|
-
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
|
382
|
-
|
|
|
383
|
-
|
|
|
384
|
-
|
|
385
|
-
#### 批量归档计划
|
|
386
|
-
|
|
387
|
-
| 方法 | 路径 | 说明 |
|
|
388
|
-
|------|------|------|
|
|
389
|
-
| POST | `/api/v1/conversations/archive-plans` | 创建批量归档计划(`{"exclude_conversation_ids":[]}`) |
|
|
390
|
-
| GET | `/api/v1/conversations/archive-plans/:planId` | 查询计划状态 |
|
|
391
|
-
| POST | `/api/v1/conversations/archive-plans/:planId/execute` | 执行计划(批量归档) |
|
|
392
|
-
|
|
393
|
-
#### 响应结构说明
|
|
394
|
-
|
|
395
|
-
**ConversationSummary**(对话列表每项):
|
|
396
|
-
|
|
397
|
-
```json
|
|
398
|
-
{
|
|
399
|
-
"id": "conv_xxx",
|
|
400
|
-
"title": "对话标题",
|
|
401
|
-
"created_at": "2026-05-09T00:00:00.000Z",
|
|
402
|
-
"updated_at": "2026-05-09T00:00:00.000Z",
|
|
403
|
-
"last_event_seq": 12,
|
|
404
|
-
"usage": { "input_tokens": 100, "output_tokens": 200, "total_tokens": 300, "updated_at": "..." },
|
|
405
|
-
"profile": { "uid": "prof_xxx", "name": "default", "display_name": "default", "avatar_url": null },
|
|
406
|
-
"last_message": { "id": "msg_xxx", "role": "assistant", "content_preview": "消息摘要..." }
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
**GET `/api/v1/conversations/:id/messages`** 响应新增 `runtime` 字段:
|
|
411
|
-
|
|
412
|
-
```json
|
|
413
|
-
{
|
|
414
|
-
"ok": true,
|
|
415
|
-
"messages": [...],
|
|
416
|
-
"last_event_seq": 12,
|
|
417
|
-
"runtime": {
|
|
418
|
-
"profile": { "name": "default", "display_name": "default", "avatar_url": null },
|
|
419
|
-
"model": { "id": "claude-3-5-sonnet", "provider": "anthropic", "context_window": 200000 },
|
|
420
|
-
"context": { "input_tokens": 100, "output_tokens": 200, "total_tokens": 300, "usage_percent": 0, "source": "estimated" }
|
|
421
|
-
},
|
|
422
|
-
"page": { "limit": 50, "has_more_before": false, "has_more_after": false, "oldest_message_id": "...", "newest_message_id": "..." }
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
**LinkMessage**(消息对象):
|
|
427
|
-
|
|
428
|
-
```json
|
|
429
|
-
{
|
|
430
|
-
"id": "msg_xxx",
|
|
431
|
-
"schema_version": 1,
|
|
432
|
-
"conversation_id": "conv_xxx",
|
|
433
|
-
"role": "user|assistant|tool|system",
|
|
434
|
-
"status": "queued|streaming|completed|failed|cancelled",
|
|
435
|
-
"created_at": "...",
|
|
436
|
-
"updated_at": "...",
|
|
437
|
-
"sender": { "id": "app_user", "type": "human|agent|system|tool", "display_name": "Me" },
|
|
438
|
-
"parts": [{ "type": "text", "text": "消息内容" }],
|
|
439
|
-
"attachments": [],
|
|
440
|
-
"blocks": [],
|
|
441
|
-
"agent_events": [],
|
|
442
|
-
"approvals": []
|
|
443
|
-
}
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
**DELETE `/api/v1/conversations/:id`** 响应新增字段:
|
|
447
|
-
|
|
448
|
-
```json
|
|
449
|
-
{
|
|
450
|
-
"ok": true,
|
|
451
|
-
"conversation_id": "conv_xxx",
|
|
452
|
-
"hermes_deleted": false,
|
|
453
|
-
"deleted_at": "2026-05-09T00:00:00.000Z"
|
|
454
|
-
}
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
### 统计
|
|
458
|
-
|
|
459
|
-
| 方法 | 路径 | 说明 |
|
|
460
|
-
|------|------|------|
|
|
461
|
-
| GET | `/api/v1/statistics` | 全局使用统计(`?profile=xxx&profile_uid=xxx`) |
|
|
462
|
-
| GET | `/api/v1/statistics/usage` | Token 用量统计(`?days=7&from=2026-05-01&to=2026-05-08&model=xxx&profile=xxx`) |
|
|
463
|
-
|
|
464
|
-
**GET `/api/v1/statistics`** 响应:
|
|
465
|
-
|
|
466
|
-
```json
|
|
467
|
-
{
|
|
468
|
-
"ok": true,
|
|
469
|
-
"statistics": {
|
|
470
|
-
"conversations": { "total": 10, "active": 8, "archived": 1, "deleted": 1 },
|
|
471
|
-
"tokens": { "input_tokens": 5000, "output_tokens": 8000, "total_tokens": 13000 },
|
|
472
|
-
"messages": { "total": 120 },
|
|
473
|
-
"runs": { "total": 50 },
|
|
474
|
-
"models": { "total": 0 },
|
|
475
|
-
"profiles": { "total": 0 },
|
|
476
|
-
"skills": { "total": 0 },
|
|
477
|
-
"tools": { "total": 0 }
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
### 模型(Models)
|
|
483
|
-
|
|
484
|
-
| 方法 | 路径 | 说明 |
|
|
485
|
-
|------|------|------|
|
|
486
|
-
| GET | `/api/v1/models` | 列出可用模型(来自 Hermes API Server,OpenAI 兼容格式) |
|
|
487
|
-
| GET | `/api/v1/model-configs` | 列出全局模型配置 |
|
|
488
|
-
| POST | `/api/v1/model-configs` | 新增全局模型配置 |
|
|
489
|
-
| PATCH | `/api/v1/model-configs/defaults` | 更新默认模型配置 |
|
|
490
|
-
| DELETE | `/api/v1/model-configs` | 删除全局模型配置 |
|
|
323
|
+
### System Status
|
|
324
|
+
|
|
325
|
+
| Method | Path | Description |
|
|
326
|
+
|--------|------|-------------|
|
|
327
|
+
| GET | `/api/v1/status` | Overall service status (version, device count, profile count, etc.) |
|
|
328
|
+
| GET | `/api/v1/logs` | Recent logs (`?source=link\|gateway&limit=50`) |
|
|
329
|
+
|
|
330
|
+
### Devices
|
|
331
|
+
|
|
332
|
+
| Method | Path | Description |
|
|
333
|
+
|--------|------|-------------|
|
|
334
|
+
| GET | `/api/v1/devices` | List all paired devices |
|
|
335
|
+
| PATCH | `/api/v1/devices/:deviceId` | Rename device (`{"label":"New Name"}`) |
|
|
336
|
+
| DELETE | `/api/v1/devices/:deviceId` | Revoke device (invalidates its tokens) |
|
|
337
|
+
| DELETE | `/api/v1/devices/:deviceId/app-listing` | Hide a revoked device from the list |
|
|
338
|
+
|
|
339
|
+
### Conversations
|
|
340
|
+
|
|
341
|
+
| Method | Path | Description |
|
|
342
|
+
|--------|------|-------------|
|
|
343
|
+
| GET | `/api/v1/conversations` | List conversations (`?limit=20&cursor=xxx`) |
|
|
344
|
+
| GET | `/api/v1/conversations/search` | Search conversations (`?q=keyword`) |
|
|
345
|
+
| POST | `/api/v1/conversations` | Create a new conversation |
|
|
346
|
+
| DELETE | `/api/v1/conversations` | Bulk delete conversations |
|
|
347
|
+
| DELETE | `/api/v1/conversations/:id` | Delete a single conversation |
|
|
348
|
+
| GET | `/api/v1/conversations/:id/messages` | Get messages in a conversation |
|
|
349
|
+
| POST | `/api/v1/conversations/:id/messages` | Send a message |
|
|
350
|
+
| GET | `/api/v1/conversations/:id/events` | SSE event stream for a conversation |
|
|
351
|
+
| GET | `/api/v1/conversations/events` | SSE stream for all conversations |
|
|
352
|
+
| PATCH | `/api/v1/conversations/:id/title` | Rename conversation (`{"title":"New Title"}`) |
|
|
353
|
+
| PATCH | `/api/v1/conversations/:id/model` | Switch model |
|
|
354
|
+
| PATCH | `/api/v1/conversations/:id/profile` | Switch profile |
|
|
355
|
+
| POST | `/api/v1/conversations/:id/ack` | Acknowledge events read |
|
|
356
|
+
| POST | `/api/v1/conversations/clear-plans` | Create a bulk-clear plan |
|
|
357
|
+
| GET | `/api/v1/conversations/clear-plans/:planId` | Query clear plan status |
|
|
358
|
+
| POST | `/api/v1/conversations/clear-plans/:planId/execute` | Execute clear plan |
|
|
359
|
+
| POST | `/api/v1/conversations/:id/runs/:runId/cancel` | Cancel an in-progress run |
|
|
360
|
+
| POST | `/api/v1/conversations/:id/approvals/:approvalId/approve` | Approve a tool call |
|
|
361
|
+
| POST | `/api/v1/conversations/:id/approvals/:approvalId/deny` | Deny a tool call |
|
|
362
|
+
| POST | `/api/v1/conversations/:id/blobs` | Upload attachment |
|
|
363
|
+
| GET | `/api/v1/conversations/:id/blobs/:blobId` | Download attachment |
|
|
364
|
+
| DELETE | `/api/v1/conversations/:id/blobs/:blobId` | Delete attachment |
|
|
365
|
+
|
|
366
|
+
### Statistics
|
|
367
|
+
|
|
368
|
+
| Method | Path | Description |
|
|
369
|
+
|--------|------|-------------|
|
|
370
|
+
| GET | `/api/v1/statistics` | Global usage stats (conversation count, message count, etc.) |
|
|
371
|
+
| GET | `/api/v1/statistics/usage` | Token usage (`?days=7&from=2026-05-01&to=2026-05-08&model=xxx&profile=xxx`) |
|
|
372
|
+
|
|
373
|
+
### Models
|
|
374
|
+
|
|
375
|
+
| Method | Path | Description |
|
|
376
|
+
|--------|------|-------------|
|
|
377
|
+
| GET | `/api/v1/models` | List available models (from Hermes API Server, OpenAI-compatible format) |
|
|
378
|
+
| GET | `/api/v1/model-configs` | List global model configs |
|
|
379
|
+
| POST | `/api/v1/model-configs` | Add global model config |
|
|
380
|
+
| PATCH | `/api/v1/model-configs/defaults` | Update default model config |
|
|
381
|
+
| DELETE | `/api/v1/model-configs` | Delete global model config |
|
|
491
382
|
|
|
492
383
|
### Profiles
|
|
493
384
|
|
|
494
|
-
|
|
|
495
|
-
|
|
496
|
-
| GET | `/api/v1/profiles` |
|
|
497
|
-
| POST | `/api/v1/profiles` |
|
|
498
|
-
| PATCH | `/api/v1/profiles/:name` |
|
|
499
|
-
| DELETE | `/api/v1/profiles/:name` |
|
|
500
|
-
| GET | `/api/v1/profiles/catalog` |
|
|
501
|
-
| GET | `/api/v1/profile-creation/status` |
|
|
502
|
-
| GET | `/api/v1/profile-creation/events` |
|
|
503
|
-
| GET | `/api/v1/profiles/:name/status` | Profile
|
|
504
|
-
| GET | `/api/v1/profiles/:name/statistics` | Profile
|
|
505
|
-
| GET | `/api/v1/profiles/:name/skills` |
|
|
506
|
-
| PATCH | `/api/v1/profiles/:name/skills/:skillName` |
|
|
507
|
-
| GET | `/api/v1/profiles/:name/memory` |
|
|
508
|
-
| POST | `/api/v1/profiles/:name/memory/entries` |
|
|
509
|
-
| PATCH | `/api/v1/profiles/:name/memory/entries` |
|
|
510
|
-
| DELETE | `/api/v1/profiles/:name/memory/entries` |
|
|
511
|
-
| DELETE | `/api/v1/profiles/:name/memory` |
|
|
512
|
-
| PATCH | `/api/v1/profiles/:name/memory/settings` |
|
|
513
|
-
| PATCH | `/api/v1/profiles/:name/memory/provider` |
|
|
514
|
-
| GET | `/api/v1/profiles/:name/permissions` |
|
|
515
|
-
| PATCH | `/api/v1/profiles/:name/permissions` |
|
|
516
|
-
| GET | `/api/v1/profiles/:name/tool-configs/:toolKey` |
|
|
517
|
-
| PATCH | `/api/v1/profiles/:name/tool-configs/:toolKey` |
|
|
518
|
-
| GET | `/api/v1/profiles/:name/model-configs` |
|
|
519
|
-
| POST | `/api/v1/profiles/:name/model-configs` |
|
|
520
|
-
| PATCH | `/api/v1/profiles/:name/model-configs/defaults` |
|
|
521
|
-
| DELETE | `/api/v1/profiles/:name/model-configs` |
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
### Cron Jobs
|
|
526
|
-
|
|
527
|
-
|
|
|
528
|
-
|
|
529
|
-
| GET | `/api/v1/cron-jobs` |
|
|
530
|
-
| GET | `/api/v1/profiles/:name/cron-jobs` |
|
|
531
|
-
| POST | `/api/v1/profiles/:name/cron-jobs` |
|
|
532
|
-
| GET | `/api/v1/profiles/:name/cron-jobs/:jobId` |
|
|
533
|
-
| PATCH | `/api/v1/profiles/:name/cron-jobs/:jobId` |
|
|
534
|
-
| DELETE | `/api/v1/profiles/:name/cron-jobs/:jobId` |
|
|
535
|
-
| POST | `/api/v1/profiles/:name/cron-jobs/:jobId/pause` |
|
|
536
|
-
| POST | `/api/v1/profiles/:name/cron-jobs/:jobId/resume` |
|
|
537
|
-
| POST | `/api/v1/profiles/:name/cron-jobs/:jobId/run` |
|
|
538
|
-
|
|
539
|
-
### Runs
|
|
540
|
-
|
|
541
|
-
|
|
|
542
|
-
|
|
543
|
-
| POST | `/api/v1/runs` |
|
|
544
|
-
| GET | `/api/v1/runs/:runId/events` |
|
|
545
|
-
| POST | `/api/v1/runs/:runId/cancel` |
|
|
546
|
-
|
|
547
|
-
**POST `/api/v1/runs`** Body
|
|
385
|
+
| Method | Path | Description |
|
|
386
|
+
|--------|------|-------------|
|
|
387
|
+
| GET | `/api/v1/profiles` | List all profile names |
|
|
388
|
+
| POST | `/api/v1/profiles` | Create new profile (async, returns 202) |
|
|
389
|
+
| PATCH | `/api/v1/profiles/:name` | Rename (`{"name":"new-name"}`) or update metadata |
|
|
390
|
+
| DELETE | `/api/v1/profiles/:name` | Delete profile |
|
|
391
|
+
| GET | `/api/v1/profiles/catalog` | Full catalog (capabilities, permissions, modelConfigs per profile) |
|
|
392
|
+
| GET | `/api/v1/profile-creation/status` | Query creation progress |
|
|
393
|
+
| GET | `/api/v1/profile-creation/events` | Creation progress SSE stream |
|
|
394
|
+
| GET | `/api/v1/profiles/:name/status` | Profile status (existence, API key configuration, etc.) |
|
|
395
|
+
| GET | `/api/v1/profiles/:name/statistics` | Profile conversation statistics |
|
|
396
|
+
| GET | `/api/v1/profiles/:name/skills` | List profile skills (`?include_disabled=true`) |
|
|
397
|
+
| PATCH | `/api/v1/profiles/:name/skills/:skillName` | Enable/disable skill (`{"enabled":true}`) |
|
|
398
|
+
| GET | `/api/v1/profiles/:name/memory` | View memory (USER.md + MEMORY.md) |
|
|
399
|
+
| POST | `/api/v1/profiles/:name/memory/entries` | Add memory entry (`{"target":"memory","content":"..."}`) |
|
|
400
|
+
| PATCH | `/api/v1/profiles/:name/memory/entries` | Replace memory entry (`{"target":"memory","match":"old","content":"new"}`) |
|
|
401
|
+
| DELETE | `/api/v1/profiles/:name/memory/entries` | Delete memory entry (`{"target":"memory","match":"text to match"}`) |
|
|
402
|
+
| DELETE | `/api/v1/profiles/:name/memory` | Reset memory (`{"target":"memory\|user\|all"}`) |
|
|
403
|
+
| PATCH | `/api/v1/profiles/:name/memory/settings` | Update memory provider settings |
|
|
404
|
+
| PATCH | `/api/v1/profiles/:name/memory/provider` | Switch memory provider (`{"provider":"built-in"}`) |
|
|
405
|
+
| GET | `/api/v1/profiles/:name/permissions` | View permissions config |
|
|
406
|
+
| PATCH | `/api/v1/profiles/:name/permissions` | Update permissions config |
|
|
407
|
+
| GET | `/api/v1/profiles/:name/tool-configs/:toolKey` | View tool config (toolKey: `web` / `image_gen` / `stt` / `tts` / `messaging` / `homeassistant` / `rl`) |
|
|
408
|
+
| PATCH | `/api/v1/profiles/:name/tool-configs/:toolKey` | Update tool config |
|
|
409
|
+
| GET | `/api/v1/profiles/:name/model-configs` | List profile model configs |
|
|
410
|
+
| POST | `/api/v1/profiles/:name/model-configs` | Add profile model config |
|
|
411
|
+
| PATCH | `/api/v1/profiles/:name/model-configs/defaults` | Update profile default model |
|
|
412
|
+
| DELETE | `/api/v1/profiles/:name/model-configs` | Delete profile model config |
|
|
413
|
+
|
|
414
|
+
Memory `target` values: `"memory"` (agent notes, MEMORY.md) or `"user"` (user info, USER.md).
|
|
415
|
+
|
|
416
|
+
### Cron Jobs
|
|
417
|
+
|
|
418
|
+
| Method | Path | Description |
|
|
419
|
+
|--------|------|-------------|
|
|
420
|
+
| GET | `/api/v1/cron-jobs` | List all cron jobs across all profiles |
|
|
421
|
+
| GET | `/api/v1/profiles/:name/cron-jobs` | List cron jobs for a specific profile |
|
|
422
|
+
| POST | `/api/v1/profiles/:name/cron-jobs` | Create cron job |
|
|
423
|
+
| GET | `/api/v1/profiles/:name/cron-jobs/:jobId` | Get cron job details |
|
|
424
|
+
| PATCH | `/api/v1/profiles/:name/cron-jobs/:jobId` | Update cron job |
|
|
425
|
+
| DELETE | `/api/v1/profiles/:name/cron-jobs/:jobId` | Delete cron job |
|
|
426
|
+
| POST | `/api/v1/profiles/:name/cron-jobs/:jobId/pause` | Pause cron job |
|
|
427
|
+
| POST | `/api/v1/profiles/:name/cron-jobs/:jobId/resume` | Resume cron job |
|
|
428
|
+
| POST | `/api/v1/profiles/:name/cron-jobs/:jobId/run` | Run cron job immediately |
|
|
429
|
+
|
|
430
|
+
### Runs
|
|
431
|
+
|
|
432
|
+
| Method | Path | Description |
|
|
433
|
+
|--------|------|-------------|
|
|
434
|
+
| POST | `/api/v1/runs` | Submit a run to Hermes Agent (returns 202) |
|
|
435
|
+
| GET | `/api/v1/runs/:runId/events` | Subscribe to run event stream (SSE proxy) |
|
|
436
|
+
| POST | `/api/v1/runs/:runId/cancel` | Cancel a run |
|
|
437
|
+
|
|
438
|
+
**POST `/api/v1/runs`** Body:
|
|
548
439
|
|
|
549
440
|
```json
|
|
550
441
|
{
|
|
551
|
-
"input": "
|
|
442
|
+
"input": "Please organise my ~/Downloads folder",
|
|
552
443
|
"profile": "default",
|
|
553
|
-
"instructions": "
|
|
554
|
-
"session_id": "
|
|
444
|
+
"instructions": "optional system instructions",
|
|
445
|
+
"session_id": "optional session ID",
|
|
555
446
|
"conversation_history": []
|
|
556
447
|
}
|
|
557
448
|
```
|
|
558
449
|
|
|
559
|
-
|
|
450
|
+
Response (202):
|
|
560
451
|
|
|
561
452
|
```json
|
|
562
453
|
{
|
|
@@ -565,42 +456,42 @@ hermeslink config set log-level debug # 日志级别:debug / info / wa
|
|
|
565
456
|
}
|
|
566
457
|
```
|
|
567
458
|
|
|
568
|
-
###
|
|
459
|
+
### Updates
|
|
569
460
|
|
|
570
|
-
#### Hermes Agent
|
|
461
|
+
#### Hermes Agent
|
|
571
462
|
|
|
572
|
-
|
|
|
573
|
-
|
|
574
|
-
| GET | `/api/v1/hermes/update-check` |
|
|
575
|
-
| GET | `/api/v1/hermes/update/status` |
|
|
576
|
-
| POST | `/api/v1/hermes/update` |
|
|
577
|
-
| GET | `/api/v1/hermes/update/events` |
|
|
463
|
+
| Method | Path | Description |
|
|
464
|
+
|--------|------|-------------|
|
|
465
|
+
| GET | `/api/v1/hermes/update-check` | Check for a new Hermes Agent version |
|
|
466
|
+
| GET | `/api/v1/hermes/update/status` | Query Hermes update progress |
|
|
467
|
+
| POST | `/api/v1/hermes/update` | Trigger Hermes Agent update |
|
|
468
|
+
| GET | `/api/v1/hermes/update/events` | Update progress SSE stream |
|
|
578
469
|
|
|
579
|
-
#### Link
|
|
470
|
+
#### Link itself
|
|
580
471
|
|
|
581
|
-
|
|
|
582
|
-
|
|
583
|
-
| GET | `/api/v1/link/update-check` |
|
|
584
|
-
| GET | `/api/v1/link/update/status` |
|
|
585
|
-
| POST | `/api/v1/link/update` |
|
|
586
|
-
| GET | `/api/v1/link/update/events` |
|
|
472
|
+
| Method | Path | Description |
|
|
473
|
+
|--------|------|-------------|
|
|
474
|
+
| GET | `/api/v1/link/update-check` | Check for a new Link version |
|
|
475
|
+
| GET | `/api/v1/link/update/status` | Query Link update progress |
|
|
476
|
+
| POST | `/api/v1/link/update` | Trigger Link self-update (`{"version":"0.3.0"}`) |
|
|
477
|
+
| GET | `/api/v1/link/update/events` | Update progress SSE stream |
|
|
587
478
|
|
|
588
|
-
###
|
|
479
|
+
### System
|
|
589
480
|
|
|
590
|
-
|
|
|
591
|
-
|
|
592
|
-
| GET | `/api/v1/system/status` |
|
|
593
|
-
| GET | `/api/v1/system/version` |
|
|
594
|
-
| POST | `/api/v1/system/autostart/enable` |
|
|
595
|
-
| POST | `/api/v1/system/autostart/disable` |
|
|
596
|
-
| GET | `/api/v1/system/logs` |
|
|
597
|
-
| GET | `/api/v1/system/logs/gateway` |
|
|
598
|
-
| GET | `/api/v1/system/updates` |
|
|
599
|
-
| POST | `/api/v1/system/updates/dismiss` |
|
|
481
|
+
| Method | Path | Description |
|
|
482
|
+
|--------|------|-------------|
|
|
483
|
+
| GET | `/api/v1/system/status` | System details (version, autostart state, network info) |
|
|
484
|
+
| GET | `/api/v1/system/version` | Link version only |
|
|
485
|
+
| POST | `/api/v1/system/autostart/enable` | Enable autostart on login |
|
|
486
|
+
| POST | `/api/v1/system/autostart/disable` | Disable autostart |
|
|
487
|
+
| GET | `/api/v1/system/logs` | Recent Link logs |
|
|
488
|
+
| GET | `/api/v1/system/logs/gateway` | Recent gateway logs |
|
|
489
|
+
| GET | `/api/v1/system/updates` | Available updates (Hermes + Link combined) |
|
|
490
|
+
| POST | `/api/v1/system/updates/dismiss` | Dismiss current update notification |
|
|
600
491
|
|
|
601
|
-
###
|
|
492
|
+
### Error Response Format
|
|
602
493
|
|
|
603
|
-
|
|
494
|
+
All errors return:
|
|
604
495
|
|
|
605
496
|
```json
|
|
606
497
|
{
|
|
@@ -612,31 +503,31 @@ hermeslink config set log-level debug # 日志级别:debug / info / wa
|
|
|
612
503
|
}
|
|
613
504
|
```
|
|
614
505
|
|
|
615
|
-
|
|
506
|
+
Common error codes:
|
|
616
507
|
|
|
617
|
-
| code | HTTP |
|
|
618
|
-
|
|
619
|
-
| `auth_required` | 401 |
|
|
620
|
-
| `device_access_token_invalid` | 401 | access_token
|
|
621
|
-
| `auth_invalid` | 401 | connect_token
|
|
622
|
-
| `pairing_session_not_found` | 404 |
|
|
623
|
-
| `pairing_session_expired` | 404 |
|
|
624
|
-
| `pairing_claim_mismatch` | 409 |
|
|
625
|
-
| `link_not_paired` | 409 |
|
|
508
|
+
| code | HTTP | Description |
|
|
509
|
+
|------|------|-------------|
|
|
510
|
+
| `auth_required` | 401 | No Authorization header |
|
|
511
|
+
| `device_access_token_invalid` | 401 | access_token expired or invalid |
|
|
512
|
+
| `auth_invalid` | 401 | connect_token invalid or already used |
|
|
513
|
+
| `pairing_session_not_found` | 404 | Pairing session not found |
|
|
514
|
+
| `pairing_session_expired` | 404 | Pairing session expired |
|
|
515
|
+
| `pairing_claim_mismatch` | 409 | Pairing token mismatch |
|
|
516
|
+
| `link_not_paired` | 409 | Service has not been assigned a link_id yet |
|
|
626
517
|
|
|
627
|
-
##
|
|
518
|
+
## Examples
|
|
628
519
|
|
|
629
|
-
###
|
|
520
|
+
### Full pairing and usage script
|
|
630
521
|
|
|
631
522
|
```bash
|
|
632
523
|
#!/bin/bash
|
|
633
524
|
BASE="http://localhost:18642"
|
|
634
525
|
|
|
635
|
-
# Step 1:
|
|
526
|
+
# Step 1: Generate a connect token
|
|
636
527
|
CONNECT=$(hermeslink pair 2>&1 | grep "Connect token:" | awk '{print $NF}')
|
|
637
528
|
echo "Connect token: $CONNECT"
|
|
638
529
|
|
|
639
|
-
# Step 2:
|
|
530
|
+
# Step 2: Exchange for access_token and refresh_token
|
|
640
531
|
RESP=$(curl -s -X POST "$BASE/api/v1/auth/device-session" \
|
|
641
532
|
-H "Authorization: Bearer $CONNECT" \
|
|
642
533
|
-H "Content-Type: application/json" \
|
|
@@ -647,11 +538,11 @@ REFRESH=$(echo $RESP | python3 -c "import json,sys; print(json.load(sys.stdin)['
|
|
|
647
538
|
echo "Access: $ACCESS"
|
|
648
539
|
echo "Refresh: $REFRESH"
|
|
649
540
|
|
|
650
|
-
# Step 3:
|
|
541
|
+
# Step 3: Check status
|
|
651
542
|
curl -s "$BASE/api/v1/status" -H "Authorization: Bearer $ACCESS" | python3 -m json.tool
|
|
652
543
|
```
|
|
653
544
|
|
|
654
|
-
###
|
|
545
|
+
### Refresh token
|
|
655
546
|
|
|
656
547
|
```bash
|
|
657
548
|
curl -s -X POST http://localhost:18642/api/v1/auth/refresh \
|
|
@@ -659,80 +550,80 @@ curl -s -X POST http://localhost:18642/api/v1/auth/refresh \
|
|
|
659
550
|
-d "{\"refresh_token\":\"$REFRESH\"}"
|
|
660
551
|
```
|
|
661
552
|
|
|
662
|
-
###
|
|
553
|
+
### List devices
|
|
663
554
|
|
|
664
555
|
```bash
|
|
665
556
|
curl -s http://localhost:18642/api/v1/devices \
|
|
666
557
|
-H "Authorization: Bearer $ACCESS"
|
|
667
558
|
```
|
|
668
559
|
|
|
669
|
-
###
|
|
560
|
+
### List conversations
|
|
670
561
|
|
|
671
562
|
```bash
|
|
672
563
|
curl -s "http://localhost:18642/api/v1/conversations?limit=10" \
|
|
673
564
|
-H "Authorization: Bearer $ACCESS"
|
|
674
565
|
```
|
|
675
566
|
|
|
676
|
-
##
|
|
567
|
+
## Autostart
|
|
677
568
|
|
|
678
|
-
- **macOS
|
|
679
|
-
- **Linux
|
|
680
|
-
- **Windows
|
|
569
|
+
- **macOS**: via launchd (`~/Library/LaunchAgents/com.hermes.link.plist`)
|
|
570
|
+
- **Linux**: via systemd user service or XDG autostart
|
|
571
|
+
- **Windows**: via the Startup folder
|
|
681
572
|
|
|
682
573
|
```bash
|
|
683
574
|
hermeslink autostart on
|
|
684
575
|
hermeslink autostart off
|
|
685
576
|
```
|
|
686
577
|
|
|
687
|
-
##
|
|
578
|
+
## Runtime Files
|
|
688
579
|
|
|
689
|
-
|
|
580
|
+
All files are stored under `~/.hermeslink/`:
|
|
690
581
|
|
|
691
|
-
|
|
|
692
|
-
|
|
693
|
-
| `config.json` |
|
|
694
|
-
| `identity.json` |
|
|
695
|
-
| `credentials.json` |
|
|
696
|
-
| `app-connect-tokens.json` |
|
|
697
|
-
| `conversations/` |
|
|
698
|
-
| `blobs/` |
|
|
699
|
-
| `pairing/` |
|
|
700
|
-
| `link.db` | SQLite
|
|
701
|
-
| `logs/` |
|
|
582
|
+
| Path | Description |
|
|
583
|
+
|------|-------------|
|
|
584
|
+
| `config.json` | User configuration |
|
|
585
|
+
| `identity.json` | Device identity (ed25519 key pair + link_id) |
|
|
586
|
+
| `credentials.json` | Access tokens for paired devices |
|
|
587
|
+
| `app-connect-tokens.json` | Pending pairing tokens (5-minute TTL) |
|
|
588
|
+
| `conversations/` | Conversation data |
|
|
589
|
+
| `blobs/` | File attachments |
|
|
590
|
+
| `pairing/` | Pairing sessions |
|
|
591
|
+
| `link.db` | SQLite database (usage statistics) |
|
|
592
|
+
| `logs/` | Log files |
|
|
702
593
|
|
|
703
|
-
|
|
594
|
+
Uninstalling the npm package does not delete this directory — reinstalling reuses the same link_id.
|
|
704
595
|
|
|
705
|
-
##
|
|
596
|
+
## Environment Variables
|
|
706
597
|
|
|
707
|
-
|
|
|
708
|
-
|
|
709
|
-
| `HERMESLINK_HOME` |
|
|
710
|
-
| `HERMESLINK_LOG_LEVEL` |
|
|
711
|
-
| `HERMESLINK_LANG` |
|
|
712
|
-
| `HERMES_BIN` | `hermes`
|
|
713
|
-
| `HERMESLINK_LISTEN_HOST` | HTTP
|
|
598
|
+
| Variable | Description |
|
|
599
|
+
|----------|-------------|
|
|
600
|
+
| `HERMESLINK_HOME` | Override the runtime directory (default: `~/.hermeslink`) |
|
|
601
|
+
| `HERMESLINK_LOG_LEVEL` | Override log level |
|
|
602
|
+
| `HERMESLINK_LANG` | Override language (`en` / `zh-CN`) |
|
|
603
|
+
| `HERMES_BIN` | Path to the `hermes` binary (default: `hermes`) |
|
|
604
|
+
| `HERMESLINK_LISTEN_HOST` | HTTP listen address (default: `0.0.0.0`) |
|
|
714
605
|
|
|
715
|
-
##
|
|
606
|
+
## Development
|
|
716
607
|
|
|
717
608
|
```bash
|
|
718
|
-
#
|
|
609
|
+
# Install dependencies and build
|
|
719
610
|
npm install
|
|
720
611
|
npm run build
|
|
721
612
|
|
|
722
|
-
#
|
|
613
|
+
# Run in foreground (for debugging)
|
|
723
614
|
npm run dev:run
|
|
724
|
-
#
|
|
615
|
+
# or
|
|
725
616
|
node dist/cli/index.js daemon --foreground
|
|
726
617
|
|
|
727
|
-
#
|
|
728
|
-
npm run dev:watch #
|
|
729
|
-
node dist/cli/index.js daemon --foreground #
|
|
618
|
+
# Watch mode (auto-rebuild on source changes, restart manually)
|
|
619
|
+
npm run dev:watch # terminal 1: watch and rebuild
|
|
620
|
+
node dist/cli/index.js daemon --foreground # terminal 2: run the service
|
|
730
621
|
|
|
731
|
-
# TypeScript
|
|
622
|
+
# TypeScript type check
|
|
732
623
|
npm run check
|
|
733
624
|
```
|
|
734
625
|
|
|
735
|
-
|
|
626
|
+
After starting, visit `http://localhost:18642/api/v1/bootstrap` to verify the service is running.
|
|
736
627
|
|
|
737
628
|
## License
|
|
738
629
|
|